diff --git a/.idea/libraries/Netty.xml b/.idea/libraries/Netty.xml
index 723ad4eef42d..1c2042bff2df 100644
--- a/.idea/libraries/Netty.xml
+++ b/.idea/libraries/Netty.xml
@@ -1,11 +1,11 @@
-
+
-
+
\ No newline at end of file
diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant
index 872cc5f6e9fe..5319444eaae6 100644
--- a/build/scripts/libLicenses.gant
+++ b/build/scripts/libLicenses.gant
@@ -252,7 +252,7 @@ libraryLicense(name: "XML-RPC", libraryName: "XmlRPC", version: "2.0", license:
libraryLicense(name: "XStream", version: "1.4.3", license: "BSD", url: "http://xstream.codehaus.org/", licenseUrl: "http://xstream.codehaus.org/license.html")
libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "8.0.x", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html")
libraryLicense(name: "protobuf", version: "2.5.0", license: "New BSD", url: "http://code.google.com/p/protobuf/", licenseUrl: "http://code.google.com/p/protobuf/source/browse/trunk/COPYING.txt?r=367")
-libraryLicense(name: "Netty", libraryName: "Netty", version: "4.1.0.Beta1", license: "Apache 2.0", url: "http://netty.io", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
+libraryLicense(name: "Netty", libraryName: "Netty", version: "4.1.0.Beta3", license: "Apache 2.0", url: "http://netty.io", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
libraryLicense(name: "Kryo", libraryName: "Kryo", version: "2.22", license: "New BSD License", url: "https://github.com/EsotericSoftware/kryo", licenseUrl: "https://github.com/EsotericSoftware/kryo/blob/master/license.txt")
libraryLicense(name: "Snappy-Java", libraryName: "Snappy-Java", version: "0.3", license: "Apache 2.0", url: "https://github.com/dain/snappy", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0")
libraryLicense(name: "Cucumber-Java", libraryName: "cucumber-java", version: "1.0.14", license: "MIT License", url: "https://github.com/cucumber/cucumber-jvm/", licenseUrl: "http://www.opensource.org/licenses/mit-license.html")
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java
index 097039b0f9f4..b239fee363fc 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java
@@ -38,6 +38,7 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
+import com.intellij.util.DocumentUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.Nullable;
@@ -66,7 +67,7 @@ public class ToggleMethodBreakpointAction extends AnAction {
}
final BreakpointManager manager = debugManager.getBreakpointManager();
final PlaceInDocument place = getPlace(e);
- if(place != null) {
+ if(place != null && DocumentUtil.isValidOffset(place.getOffset(), place.getDocument())) {
Breakpoint breakpoint = manager.findBreakpoint(place.getDocument(), place.getOffset(), MethodBreakpoint.CATEGORY);
if(breakpoint == null) {
final int methodLine = place.getDocument().getLineNumber(place.getOffset());
diff --git a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
index 9028b1489970..fcafd6440fbf 100644
--- a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
+++ b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * 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.
@@ -128,7 +128,12 @@ public abstract class SourcePosition implements Navigatable{
return true;
}
final PsiElement psiElement = myPsiElement;
- return psiElement != null && !psiElement.isValid();
+ return psiElement != null && !ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ return psiElement.isValid();
+ }
+ });
}
@Override
@@ -194,7 +199,7 @@ public abstract class SourcePosition implements Navigatable{
@Nullable
protected PsiElement calcPsiElement() {
- PsiFile psiFile = getFile();
+ final PsiFile psiFile = getFile();
int lineNumber = getLine();
if(lineNumber < 0) {
return psiFile;
@@ -207,47 +212,52 @@ public abstract class SourcePosition implements Navigatable{
if (lineNumber >= document.getLineCount()) {
return psiFile;
}
- int startOffset = document.getLineStartOffset(lineNumber);
+ final int startOffset = document.getLineStartOffset(lineNumber);
if(startOffset == -1) {
return null;
}
- PsiElement rootElement = psiFile;
+ return ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiElement compute() {
+ PsiElement rootElement = psiFile;
- List allFiles = psiFile.getViewProvider().getAllFiles();
- if (allFiles.size() > 1) { // jsp & gsp
- PsiClassOwner owner = ContainerUtil.findInstance(allFiles, PsiClassOwner.class);
- if (owner != null) {
- PsiClass[] classes = owner.getClasses();
- if (classes.length == 1 && classes[0] instanceof SyntheticElement) {
- rootElement = classes[0];
+ List allFiles = psiFile.getViewProvider().getAllFiles();
+ if (allFiles.size() > 1) { // jsp & gsp
+ PsiClassOwner owner = ContainerUtil.findInstance(allFiles, PsiClassOwner.class);
+ if (owner != null) {
+ PsiClass[] classes = owner.getClasses();
+ if (classes.length == 1 && classes[0] instanceof SyntheticElement) {
+ rootElement = classes[0];
+ }
+ }
}
- }
- }
- PsiElement element;
- while(true) {
- final CharSequence charsSequence = document.getCharsSequence();
- for (; startOffset < charsSequence.length(); startOffset++) {
- char c = charsSequence.charAt(startOffset);
- if (c != ' ' && c != '\t') {
- break;
+ PsiElement element;
+ int offset = startOffset;
+ while (true) {
+ final CharSequence charsSequence = document.getCharsSequence();
+ for (; offset < charsSequence.length(); offset++) {
+ char c = charsSequence.charAt(startOffset);
+ if (c != ' ' && c != '\t') {
+ break;
+ }
+ }
+ element = rootElement.findElementAt(startOffset);
+
+ if (element instanceof PsiComment) {
+ offset = element.getTextRange().getEndOffset() + 1;
+ }
+ else {
+ break;
+ }
}
+ if (element != null && element.getParent() instanceof PsiForStatement) {
+ return ((PsiForStatement)element.getParent()).getInitialization();
+ }
+ return element;
}
- element = rootElement.findElementAt(startOffset);
-
- if(element instanceof PsiComment) {
- startOffset = element.getTextRange().getEndOffset() + 1;
- }
- else{
- break;
- }
- }
-
- if (element != null && element.getParent() instanceof PsiForStatement) {
- return ((PsiForStatement)element.getParent()).getInitialization();
- }
- return element;
+ });
}
}
diff --git a/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java b/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java
index ded07d482ed3..eeb8d1b95a49 100644
--- a/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java
+++ b/java/idea-ui/src/com/intellij/ide/actions/ShowStructureSettingsAction.java
@@ -56,7 +56,7 @@ public class ShowStructureSettingsAction extends AnAction implements DumbAware {
protected JComponent createSouthPanel() {
JComponent panel = super.createSouthPanel();
assert panel != null;
- CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153, Gray._80), 1, 0, 0, 0);
+ CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128)), 1, 0, 0, 0);
panel.setBorder(new CompoundBorder(line, new EmptyBorder(10, 5, 5, 5)));
return panel;
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java
index 3dfc371daa64..01993d5e9dd0 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java
@@ -200,6 +200,14 @@ abstract class Analysis {
public static final int STEPS_LIMIT = 30000;
public static final int EQUATION_SIZE_LIMIT = 30;
+
+ protected static final ThreadLocal ourPendingStates = new ThreadLocal() {
+ @Override
+ protected State[] initialValue() {
+ return new State[STEPS_LIMIT];
+ }
+ };
+
final RichControlFlow richControlFlow;
final Direction direction;
final ControlFlowGraph controlFlow;
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java
index bc041fb0dc73..84a5851e847d 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java
@@ -277,10 +277,11 @@ public class BytecodeAnalysisConverter {
return 0;
} else if (dir instanceof In) {
In in = (In)dir;
- return 8 * in.paramId() + 1;
+ // nullity mask is 0/1
+ return 8 * in.paramId() + 1 + in.nullityMask;
} else {
InOut inOut = (InOut)dir;
- return 8 * inOut.paramId() + 2 + inOut.valueId();
+ return 8 * inOut.paramId() + 3 + inOut.valueId();
}
}
@@ -292,11 +293,11 @@ public class BytecodeAnalysisConverter {
else {
int paramId = directionKey / 8;
int subDirection = directionKey % 8;
- if (subDirection == 1) {
- return new In(paramId);
+ if (subDirection <= 2) {
+ return new In(paramId, subDirection - 1);
}
else {
- return new InOut(paramId, Value.values()[subDirection - 2]);
+ return new InOut(paramId, Value.values()[subDirection - 3]);
}
}
}
@@ -328,14 +329,14 @@ public class BytecodeAnalysisConverter {
* Given `solution` of all dependencies of a method with the `methodKey`, converts this solution into annotations.
*
* @param solution solution of equations
- * @param annotations annotations to which corresponding solutions should be added
+ * @param methodAnnotations annotations to which corresponding solutions should be added
* @param methodKey a primary key of a method being analyzed
* @param arity arity of this method (hint for constructing @Contract annotations)
*/
- public static void addMethodAnnotations(@NotNull HashMap solution, @NotNull Annotations annotations, @NotNull HKey methodKey, int arity) {
+ public static void addMethodAnnotations(@NotNull HashMap solution, @NotNull MethodAnnotations methodAnnotations, @NotNull HKey methodKey, int arity) {
List clauses = new ArrayList();
- HashSet notNulls = annotations.notNulls;
- HashMap contracts = annotations.contracts;
+ HashSet notNulls = methodAnnotations.notNulls;
+ HashMap contracts = methodAnnotations.contracts;
for (Map.Entry entry : solution.entrySet()) {
HKey key = entry.getKey().mkStable();
Value value = entry.getValue();
@@ -363,27 +364,6 @@ public class BytecodeAnalysisConverter {
}
}
- /**
- * Converts solutions for equations over parameters into annotations.
- *
- * @param solution
- * @param annotations
- */
- public static void addParameterAnnotations(@NotNull HashMap solution, @NotNull Annotations annotations) {
- HashSet notNulls = annotations.notNulls;
- for (Map.Entry entry : solution.entrySet()) {
- HKey key = entry.getKey().mkStable();
- Value value = entry.getValue();
- if (value == Value.Top || value == Value.Bot) {
- continue;
- }
- Direction direction = extractDirection(key.dirKey);
- if (value == Value.NotNull && (direction instanceof In || direction instanceof Out)) {
- notNulls.add(key);
- }
- }
- }
-
private static String contractValueString(@NotNull Value v) {
switch (v) {
case False: return "false";
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java
index a477c7d59101..a7070b882431 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java
@@ -40,7 +40,7 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension FINAL_TOP = new Final(Value.Top);
public static final Final FINAL_BOT = new Final(Value.Bot);
public static final Final FINAL_NOT_NULL = new Final(Value.NotNull);
+ public static final Final FINAL_NULL = new Final(Value.Null);
private static final List> EMPTY_EQUATIONS = Collections.EMPTY_LIST;
@NotNull
@@ -129,22 +130,21 @@ public class ClassDataIndexer implements DataIndexer 0) {
final DFSTree dfs = DFSTree.build(graph.transitions, graph.edgeCount);
- boolean complex = !dfs.back.isEmpty();
- if (!complex) {
+ boolean branching = !dfs.back.isEmpty();
+ if (!branching) {
for (int[] transition : graph.transitions) {
if (transition != null && transition.length > 1) {
- complex = true;
+ branching = true;
break;
}
}
}
- if (complex) {
+ if (branching) {
RichControlFlow richControlFlow = new RichControlFlow(graph, dfs);
if (richControlFlow.reducible()) {
return Pair.create(primaryKey,
@@ -180,7 +180,7 @@ public class ClassDataIndexer implements DataIndexer> result = new ArrayList>(argumentTypes.length * 3 + 1);
+ List> result = new ArrayList>(argumentTypes.length * 4 + 1);
boolean maybeLeakingParameter = isInterestingResult;
for (Type argType : argumentTypes) {
if (ASMUtils.isReferenceType(argType) || (isReferenceResult && ASMUtils.isBooleanType(argType))) {
@@ -193,6 +193,8 @@ public class ClassDataIndexer implements DataIndexer origins = new NullableLazyValue() {
@Override
@@ -231,14 +233,28 @@ public class ClassDataIndexer implements DataIndexer notNullParamEquation = new NonNullInAnalysis(richControlFlow, new In(i), stable).analyze();
+ NonNullInAnalysis notNullInAnalysis = new NonNullInAnalysis(richControlFlow, new In(i, In.NOT_NULL), stable);
+ Equation notNullParamEquation = notNullInAnalysis.analyze();
+ possibleNPE = notNullInAnalysis.possibleNPE;
notNullParam = notNullParamEquation.rhs.equals(FINAL_NOT_NULL);
result.add(notNullParamEquation);
}
else {
// parameter is not leaking, so it is definitely NOT @NotNull
- result.add(new Equation(new Key(method, new In(i), stable), FINAL_TOP));
+ result.add(new Equation(new Key(method, new In(i, In.NOT_NULL), stable), FINAL_TOP));
+ }
+ if (leakingNullableParameters[i]) {
+ if (notNullParam || possibleNPE) {
+ result.add(new Equation(new Key(method, new In(i, In.NULLABLE), stable), FINAL_TOP));
+ }
+ else {
+ result.add(new NullableInAnalysis(richControlFlow, new In(i, In.NULLABLE), stable).analyze());
+ }
+ }
+ else {
+ result.add(new Equation(new Key(method, new In(i, In.NULLABLE), stable), FINAL_NULL));
}
}
if (isReferenceArg && isInterestingResult) {
@@ -296,7 +312,7 @@ public class ClassDataIndexer implements DataIndexer> result = new ArrayList>(argumentTypes.length * 3 + 1);
+ List> result = new ArrayList>(argumentTypes.length * 4 + 1);
CombinedSingleAnalysis analyzer = new CombinedSingleAnalysis(method, graph);
analyzer.analyze();
if (isReferenceResult) {
@@ -307,6 +323,7 @@ public class ClassDataIndexer implements DataIndexer(new Key(method, new In(i), stable), FINAL_TOP));
+ result.add(new Equation(new Key(method, new In(i, In.NOT_NULL), stable), FINAL_TOP));
+ result.add(new Equation(new Key(method, new In(i, In.NULLABLE), stable), FINAL_TOP));
}
if (isReferenceArg && isInterestingResult) {
result.add(new Equation(new Key(method, new InOut(i, Value.Null), stable), FINAL_TOP));
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java
index f747c76bdb4d..645c00260af1 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java
@@ -28,12 +28,48 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter;
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.intellij.codeInspection.bytecodeAnalysis.AbstractValues.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
+final class ParamKey {
+ final Method method;
+ final int i;
+ final boolean stable;
+
+
+ ParamKey(Method method, int i, boolean stable) {
+ this.method = method;
+ this.i = i;
+ this.stable = stable;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ParamKey paramKey = (ParamKey)o;
+
+ if (i != paramKey.i) return false;
+ if (stable != paramKey.stable) return false;
+ if (!method.equals(paramKey.method)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = method.hashCode();
+ result = 31 * result + i;
+ result = 31 * result + (stable ? 1 : 0);
+ return result;
+ }
+}
+
final class CombinedCall extends BasicValue {
final Method method;
final boolean stableCall;
@@ -106,18 +142,44 @@ final class CombinedSingleAnalysis {
}
final Equation notNullParamEquation(int i, boolean stable) {
- final Key key = new Key(method, new In(i), stable);
+ final Key key = new Key(method, new In(i, In.NOT_NULL), stable);
final Result result;
if (interpreter.dereferenced[i]) {
result = new Final(Value.NotNull);
}
else {
- Set calls = interpreter.callDerefs[i];
+ Set calls = interpreter.callDerefs[i];
if (calls == null || calls.isEmpty()) {
result = new Final(Value.Top);
}
else {
- result = new Pending(new SingletonSet>(new Product(Value.Top, calls)));
+ Set keys = new HashSet();
+ for (ParamKey pk: calls) {
+ keys.add(new Key(pk.method, new In(pk.i, In.NOT_NULL), pk.stable));
+ }
+ result = new Pending(new SingletonSet>(new Product(Value.Top, keys)));
+ }
+ }
+ return new Equation(key, result);
+ }
+
+ final Equation nullableParamEquation(int i, boolean stable) {
+ final Key key = new Key(method, new In(i, In.NULLABLE), stable);
+ final Result result;
+ if (interpreter.dereferenced[i] || interpreter.notNullable[i] || returnValue instanceof NParamValue && ((NParamValue)returnValue).n == i) {
+ result = new Final(Value.Top);
+ }
+ else {
+ Set calls = interpreter.callDerefs[i];
+ if (calls == null || calls.isEmpty()) {
+ result = new Final(Value.Null);
+ }
+ else {
+ Set> sum = new HashSet>();
+ for (ParamKey pk: calls) {
+ sum.add(new Product(Value.Top, Collections.singleton(new Key(pk.method, new In(pk.i, In.NULLABLE), pk.stable))));
+ }
+ result = new Pending(sum);
}
}
return new Equation(key, result);
@@ -228,10 +290,12 @@ final class CombinedSingleAnalysis {
final class CombinedInterpreter extends BasicInterpreter {
final boolean[] dereferenced;
- final Set[] callDerefs;
+ final boolean[] notNullable;
+ final Set[] callDerefs;
CombinedInterpreter(int arity) {
dereferenced = new boolean[arity];
+ notNullable = new boolean[arity];
callDerefs = new Set[arity];
}
@@ -303,10 +367,17 @@ final class CombinedInterpreter extends BasicInterpreter {
case BALOAD:
case CALOAD:
case SALOAD:
+ if (value1 instanceof NParamValue) {
+ dereferenced[((NParamValue)value1).n] = true;
+ }
+ break;
case PUTFIELD:
if (value1 instanceof NParamValue) {
dereferenced[((NParamValue)value1).n] = true;
}
+ if (value2 instanceof NParamValue) {
+ notNullable[((NParamValue)value2).n] = true;
+ }
break;
default:
}
@@ -321,13 +392,21 @@ final class CombinedInterpreter extends BasicInterpreter {
case LASTORE:
case FASTORE:
case DASTORE:
- case AASTORE:
case BASTORE:
case CASTORE:
case SASTORE:
if (value1 instanceof NParamValue) {
dereferenced[((NParamValue)value1).n] = true;
}
+ break;
+ case AASTORE:
+ if (value1 instanceof NParamValue) {
+ dereferenced[((NParamValue)value1).n] = true;
+ }
+ if (value3 instanceof NParamValue) {
+ notNullable[((NParamValue)value3).n] = true;
+ }
+ break;
default:
}
return super.ternaryOperation(insn, value1, value2, value3);
@@ -347,7 +426,6 @@ final class CombinedInterpreter extends BasicInterpreter {
}
}
-
switch (opCode) {
case INVOKESTATIC:
case INVOKESPECIAL:
@@ -360,14 +438,17 @@ final class CombinedInterpreter extends BasicInterpreter {
for (int i = shift; i < values.size(); i++) {
if (values.get(i) instanceof NParamValue) {
- if (opCode != INVOKEINTERFACE) {
- int n = ((NParamValue)values.get(i)).n;
- Set npKeys = callDerefs[n];
+ int n = ((NParamValue)values.get(i)).n;
+ if (opCode == INVOKEINTERFACE) {
+ notNullable[n] = true;
+ }
+ else {
+ Set npKeys = callDerefs[n];
if (npKeys == null) {
- npKeys = new HashSet();
+ npKeys = new HashSet();
callDerefs[n] = npKeys;
}
- npKeys.add(new Key(method, new In(i - shift), stable));
+ npKeys.add(new ParamKey(method, i - shift, stable));
}
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java
index 1226993383a4..c382148abb05 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java
@@ -37,17 +37,10 @@ import static org.jetbrains.org.objectweb.asm.Opcodes.*;
class InOutAnalysis extends Analysis> {
- private static final ThreadLocal ourPending = new ThreadLocal() {
- @Override
- protected State[] initialValue() {
- return new State[Analysis.STEPS_LIMIT];
- }
- };
-
static final ResultUtil resultUtil =
new ResultUtil(new ELattice(Value.Bot, Value.Top));
- final private State[] pending = ourPending.get();
+ final private State[] pending = ourPendingStates.get();
private final InOutInterpreter interpreter;
private final Value inValue;
private final int generalizeShift;
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java
index 29050f480fbe..55a842af684c 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java
@@ -52,20 +52,17 @@ enum Value {
Bot, NotNull, Null, True, False, Top
}
-interface Direction {
- static final int OUT_DIRECTION = 0;
- static final int IN_DIRECTION = 1;
- static final int INOUT_DIRECTION = 2;
- int directionId();
- int paramId();
- int valueId();
-}
+interface Direction {}
final class In implements Direction {
+ static final int NOT_NULL = 0;
+ static final int NULLABLE = 1;
final int paramIndex;
+ final int nullityMask;
- In(int paramIndex) {
+ In(int paramIndex, int nullityMask) {
this.paramIndex = paramIndex;
+ this.nullityMask = nullityMask;
}
@Override
@@ -79,28 +76,19 @@ final class In implements Direction {
if (o == null || getClass() != o.getClass()) return false;
In in = (In) o;
if (paramIndex != in.paramIndex) return false;
+ if (nullityMask != in.nullityMask) return false;
return true;
}
@Override
public int hashCode() {
- return paramIndex;
+ return 31*paramIndex + nullityMask;
}
- @Override
- public int directionId() {
- return IN_DIRECTION;
- }
-
- @Override
public int paramId() {
return paramIndex;
}
- @Override
- public int valueId() {
- return 0;
- }
}
final class InOut implements Direction {
@@ -137,17 +125,10 @@ final class InOut implements Direction {
return "InOut " + paramIndex + " " + inValue.toString();
}
- @Override
- public int directionId() {
- return INOUT_DIRECTION;
- }
-
- @Override
public int paramId() {
return paramIndex;
}
- @Override
public int valueId() {
return inValue.ordinal();
}
@@ -168,21 +149,6 @@ final class Out implements Direction {
public boolean equals(Object obj) {
return obj instanceof Out;
}
-
- @Override
- public int directionId() {
- return OUT_DIRECTION;
- }
-
- @Override
- public int paramId() {
- return 0;
- }
-
- @Override
- public int valueId() {
- return 0;
- }
}
final class Key {
@@ -219,10 +185,6 @@ final class Key {
@Override
public String toString() {
- return "" + method + ' ' + direction + ' ' + stable;
+ return method + " " + direction + " " + stable;
}
}
-
-class LimitReachedException extends RuntimeException {
-
-}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java
index 047613847186..7c938347ccb9 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/HData.java
@@ -63,6 +63,10 @@ final class HKey {
return stable ? this : new HKey(key, dirKey, true);
}
+ HKey mkUnstable() {
+ return stable ? new HKey(key, dirKey, false) : this;
+ }
+
public HKey mkBase() {
return dirKey == 0 ? this : new HKey(key, 0, stable);
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java
index b68b5164ba2d..a7c25782d48b 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java
@@ -107,6 +107,18 @@ abstract class PResults {
}
}
+ static PResult combineNullable(PResult r1, PResult r2) throws AnalyzerException {
+ if (Identity == r1) return r2;
+ if (Identity == r2) return r1;
+ if (Return == r1) return r2;
+ if (Return == r2) return r1;
+ if (NPE == r1) return NPE;
+ if (NPE == r2) return NPE;
+ ConditionalNPE cnpe1 = (ConditionalNPE) r1;
+ ConditionalNPE cnpe2 = (ConditionalNPE) r2;
+ return new ConditionalNPE(join(cnpe1.sop, cnpe2.sop));
+ }
+
static PResult join(PResult r1, PResult r2) throws AnalyzerException {
if (Identity == r1) return r2;
if (Identity == r2) return r1;
@@ -169,9 +181,12 @@ class NonNullInAnalysis extends Analysis {
final private PendingAction[] pending = ourPending.get();
- private final NonNullInInterpreter interpreter = new NonNullInInterpreter();
+ private final NotNullInterpreter interpreter = new NotNullInterpreter();
private PResult[] results;
+ // Flag saying that at some branch NPE was found. Used later as an evidence that this param is *NOT* @Nullable (optimization).
+ boolean possibleNPE;
+
protected NonNullInAnalysis(RichControlFlow richControlFlow, Direction direction, boolean stable) {
super(richControlFlow, direction, stable);
results = ourResults.get();
@@ -289,6 +304,7 @@ class NonNullInAnalysis extends Analysis {
if (subResult == NPE) {
results[stateIndex] = NPE;
+ possibleNPE = true;
addComputed(insnIndex, state);
return;
}
@@ -314,6 +330,7 @@ class NonNullInAnalysis extends Analysis {
if (opcode == ATHROW) {
if (taken) {
results[stateIndex] = NPE;
+ possibleNPE = true;
} else {
results[stateIndex] = Identity;
}
@@ -399,13 +416,216 @@ class NonNullInAnalysis extends Analysis {
}
}
-class NonNullInInterpreter extends BasicInterpreter {
+class NullableInAnalysis extends Analysis {
+ final private State[] pending = ourPendingStates.get();
+
+ private final NullableInterpreter interpreter = new NullableInterpreter();
+
+ protected NullableInAnalysis(RichControlFlow richControlFlow, Direction direction, boolean stable) {
+ super(richControlFlow, direction, stable);
+ }
+
+ @NotNull
+ Equation mkEquation(PResult result) {
+ if (NPE == result) {
+ return new Equation(aKey, new Final(Value.Top));
+ }
+ if (Identity == result || Return == result) {
+ return new Equation(aKey, new Final(Value.Null));
+ }
+ else {
+ ConditionalNPE condNpe = (ConditionalNPE) result;
+ Set> components = new HashSet>();
+ for (Set prod : condNpe.sop) {
+ components.add(new Product(Value.Top, prod));
+ }
+ return new Equation(aKey, new Pending(components));
+ }
+ }
+
+ private int id = 0;
+ private Frame nextFrame = null;
+ private PResult myResult = Identity;
private PResult subResult = Identity;
+ private boolean top = false;
+
+ @NotNull
+ protected Equation analyze() throws AnalyzerException {
+ pendingPush(createStartState());
+ int steps = 0;
+ while (pendingTop > 0 && earlyResult == null) {
+ steps ++;
+ if (steps >= STEPS_LIMIT) {
+ throw new AnalyzerException(null, "limit is reached, steps: " + steps + " in method " + method);
+ }
+ State state = pending[--pendingTop];
+ int insnIndex = state.conf.insnIndex;
+ Conf conf = state.conf;
+ List history = state.history;
+
+ boolean fold = false;
+ if (dfsTree.loopEnters[insnIndex]) {
+ for (Conf prev : history) {
+ if (AbstractValues.isInstance(conf, prev)) {
+ fold = true;
+ break;
+ }
+ }
+ }
+ if (fold) {
+ addComputed(insnIndex, state);
+ }
+ else {
+ State baseState = null;
+ List thisComputed = computed[insnIndex];
+ if (thisComputed != null) {
+ for (State prevState : thisComputed) {
+ if (stateEquiv(state, prevState)) {
+ baseState = prevState;
+ break;
+ }
+ }
+ }
+ if (baseState == null) {
+ processState(state);
+ }
+ }
+ }
+ if (earlyResult != null) {
+ return mkEquation(earlyResult);
+ } else {
+ return mkEquation(myResult);
+ }
+ }
+
+ private void processState(State state) throws AnalyzerException {
+ Conf conf = state.conf;
+ int insnIndex = conf.insnIndex;
+ List history = state.history;
+ boolean taken = state.taken;
+ Frame frame = conf.frame;
+ AbstractInsnNode insnNode = methodNode.instructions.get(insnIndex);
+ List nextHistory = dfsTree.loopEnters[insnIndex] ? append(history, conf) : history;
+
+ addComputed(insnIndex, state);
+ execute(frame, insnNode);
+
+ if (subResult == NPE || top) {
+ earlyResult = NPE;
+ return;
+ }
+
+ if (subResult instanceof ConditionalNPE) {
+ myResult = combineNullable(myResult, subResult);
+ }
+
+ int opcode = insnNode.getOpcode();
+ switch (opcode) {
+ case ARETURN:
+ if (popValue(frame) instanceof ParamValue) {
+ earlyResult = NPE;
+ }
+ return;
+ case IRETURN:
+ case LRETURN:
+ case FRETURN:
+ case DRETURN:
+ case RETURN:
+ return;
+ default:
+ }
+
+ if (opcode == ATHROW) {
+ if (taken) {
+ earlyResult = NPE;
+ }
+ return;
+ }
+
+ if (opcode == IFNONNULL && popValue(frame) instanceof ParamValue) {
+ int nextInsnIndex = insnIndex + 1;
+ pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
+ return;
+ }
+
+ if (opcode == IFNULL && popValue(frame) instanceof ParamValue) {
+ int nextInsnIndex = methodNode.instructions.indexOf(((JumpInsnNode)insnNode).label);
+ pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
+ return;
+ }
+
+ if (opcode == IFEQ && popValue(frame) == InstanceOfCheckValue) {
+ int nextInsnIndex = methodNode.instructions.indexOf(((JumpInsnNode)insnNode).label);
+ pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
+ return;
+ }
+
+ if (opcode == IFNE && popValue(frame) == InstanceOfCheckValue) {
+ int nextInsnIndex = insnIndex + 1;
+ pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame), nextHistory, true, false));
+ return;
+ }
+
+ // general case
+ for (int nextInsnIndex : controlFlow.transitions[insnIndex]) {
+ Frame nextFrame1 = nextFrame;
+ if (controlFlow.errors[nextInsnIndex] && controlFlow.errorTransitions.contains(new Edge(insnIndex, nextInsnIndex))) {
+ nextFrame1 = new Frame(frame);
+ nextFrame1.clearStack();
+ nextFrame1.push(ASMUtils.THROWABLE_VALUE);
+ }
+ pendingPush(new State(++id, new Conf(nextInsnIndex, nextFrame1), nextHistory, taken, false));
+ }
+
+ }
+
+ private int pendingTop = 0;
+
+ private void pendingPush(State state) throws AnalyzerException {
+ if (pendingTop >= STEPS_LIMIT) {
+ throw new AnalyzerException(null, "limit is reached in method " + method);
+ }
+ pending[pendingTop++] = state;
+ }
+
+ private void execute(Frame frame, AbstractInsnNode insnNode) throws AnalyzerException {
+ switch (insnNode.getType()) {
+ case AbstractInsnNode.LABEL:
+ case AbstractInsnNode.LINE:
+ case AbstractInsnNode.FRAME:
+ nextFrame = frame;
+ subResult = Identity;
+ top = false;
+ break;
+ default:
+ nextFrame = new Frame(frame);
+ interpreter.reset();
+ nextFrame.execute(insnNode, interpreter);
+ subResult = interpreter.getSubResult();
+ top = interpreter.top;
+ }
+ }
+}
+
+abstract class NullityInterpreter extends BasicInterpreter {
+ boolean top = false;
+ final boolean nullableAnalysis;
+ final int nullityMask;
+ private PResult subResult = Identity;
+
+ NullityInterpreter(boolean nullableAnalysis, int nullityMask) {
+ this.nullableAnalysis = nullableAnalysis;
+ this.nullityMask = nullityMask;
+ }
+
+ abstract PResult combine(PResult res1, PResult res2) throws AnalyzerException;
+
public PResult getSubResult() {
return subResult;
}
void reset() {
subResult = Identity;
+ top = false;
}
@Override
@@ -445,10 +665,17 @@ class NonNullInInterpreter extends BasicInterpreter {
case BALOAD:
case CALOAD:
case SALOAD:
+ if (value1 instanceof ParamValue) {
+ subResult = NPE;
+ }
+ break;
case PUTFIELD:
if (value1 instanceof ParamValue) {
subResult = NPE;
}
+ if (nullableAnalysis && value2 instanceof ParamValue) {
+ subResult = NPE;
+ }
break;
default:
}
@@ -462,13 +689,21 @@ class NonNullInInterpreter extends BasicInterpreter {
case LASTORE:
case FASTORE:
case DASTORE:
- case AASTORE:
case BASTORE:
case CASTORE:
case SASTORE:
if (value1 instanceof ParamValue) {
subResult = NPE;
}
+ break;
+ case AASTORE:
+ if (value1 instanceof ParamValue) {
+ subResult = NPE;
+ }
+ if (nullableAnalysis && value3 instanceof ParamValue) {
+ subResult = NPE;
+ }
+ break;
default:
}
return super.ternaryOperation(insn, value1, value2, value3);
@@ -483,19 +718,54 @@ class NonNullInInterpreter extends BasicInterpreter {
subResult = NPE;
}
switch (opcode) {
+ case INVOKEINTERFACE:
+ if (nullableAnalysis) {
+ for (int i = shift; i < values.size(); i++) {
+ if (values.get(i) instanceof ParamValue) {
+ top = true;
+ return super.naryOperation(insn, values);
+ }
+ }
+ }
+ break;
case INVOKESTATIC:
case INVOKESPECIAL:
case INVOKEVIRTUAL:
boolean stable = opcode == INVOKESTATIC || opcode == INVOKESPECIAL;
MethodInsnNode methodNode = (MethodInsnNode) insn;
+ Method method = new Method(methodNode.owner, methodNode.name, methodNode.desc);
for (int i = shift; i < values.size(); i++) {
if (values.get(i) instanceof ParamValue) {
- Method method = new Method(methodNode.owner, methodNode.name, methodNode.desc);
- subResult = meet(subResult, new ConditionalNPE(new Key(method, new In(i - shift), stable)));
+ subResult = combine(subResult, new ConditionalNPE(new Key(method, new In(i - shift, nullityMask), stable)));
}
}
+ break;
default:
}
return super.naryOperation(insn, values);
}
}
+
+class NotNullInterpreter extends NullityInterpreter {
+
+ NotNullInterpreter() {
+ super(false, In.NOT_NULL);
+ }
+
+ @Override
+ PResult combine(PResult res1, PResult res2) throws AnalyzerException {
+ return meet(res1, res2);
+ }
+}
+
+class NullableInterpreter extends NullityInterpreter {
+
+ NullableInterpreter() {
+ super(true, In.NULLABLE);
+ }
+
+ @Override
+ PResult combine(PResult res1, PResult res2) throws AnalyzerException {
+ return join(res1, res2);
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java
index ec58fb83431a..aa44951961ad 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java
@@ -37,10 +37,7 @@ import org.jetbrains.annotations.Nullable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
+import java.util.*;
/**
* @author lambdamix
@@ -64,7 +61,7 @@ public class ProjectBytecodeAnalysis {
if (!(listOwner instanceof PsiCompiledElement)) {
return null;
}
- if (annotationFQN.equals(AnnotationUtil.NOT_NULL) || annotationFQN.equals(ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) {
+ if (annotationFQN.equals(AnnotationUtil.NOT_NULL) || annotationFQN.equals(AnnotationUtil.NULLABLE) || annotationFQN.equals(ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) {
PsiAnnotation[] annotations = findInferredAnnotations(listOwner);
for (PsiAnnotation annotation : annotations) {
if (annotationFQN.equals(annotation.getQualifiedName())) {
@@ -96,34 +93,45 @@ public class ProjectBytecodeAnalysis {
private PsiAnnotation[] collectInferredAnnotations(PsiModifierListOwner listOwner) {
try {
MessageDigest md = BytecodeAnalysisConverter.getMessageDigest();
- HKey ownerKey = getKey(listOwner, md);
- if (ownerKey == null) {
+ HKey primaryKey = getKey(listOwner, md);
+ if (primaryKey == null) {
return PsiAnnotation.EMPTY_ARRAY;
}
- ArrayList allKeys = contractKeys(listOwner, ownerKey);
- Annotations annotations = loadAnnotations(listOwner, ownerKey, allKeys);
- boolean notNull = annotations.notNulls.contains(ownerKey);
- String contractValue = annotations.contracts.get(ownerKey);
-
- if (notNull && contractValue != null) {
- return new PsiAnnotation[]{
- getNotNullAnnotation(),
- createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
- };
- }
- else if (notNull) {
- return new PsiAnnotation[]{
- getNotNullAnnotation()
- };
- }
- else if (contractValue != null) {
- return new PsiAnnotation[]{
- createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
- };
- }
- else {
- return PsiAnnotation.EMPTY_ARRAY;
+ if (listOwner instanceof PsiMethod) {
+ ArrayList allKeys = contractKeys((PsiMethod)listOwner, primaryKey);
+ MethodAnnotations methodAnnotations = loadMethodAnnotations((PsiMethod)listOwner, primaryKey, allKeys);
+ boolean notNull = methodAnnotations.notNulls.contains(primaryKey);
+ String contractValue = methodAnnotations.contracts.get(primaryKey);
+ if (notNull && contractValue != null) {
+ return new PsiAnnotation[]{
+ getNotNullAnnotation(),
+ createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
+ };
+ }
+ else if (notNull) {
+ return new PsiAnnotation[]{
+ getNotNullAnnotation()
+ };
+ }
+ else if (contractValue != null) {
+ return new PsiAnnotation[]{
+ createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
+ };
+ }
+ } else if (listOwner instanceof PsiParameter) {
+ ParameterAnnotations parameterAnnotations = loadParameterAnnotations(primaryKey);
+ if (parameterAnnotations.notNull) {
+ return new PsiAnnotation[]{
+ getNotNullAnnotation()
+ };
+ }
+ else if (parameterAnnotations.nullable) {
+ return new PsiAnnotation[]{
+ getNullableAnnotation()
+ };
+ }
}
+ return PsiAnnotation.EMPTY_ARRAY;
}
catch (EquationsLimitException e) {
String externalName = PsiFormatUtil.getExternalName(listOwner, false, Integer.MAX_VALUE);
@@ -146,6 +154,16 @@ public class ProjectBytecodeAnalysis {
});
}
+ private PsiAnnotation getNullableAnnotation() {
+ return CachedValuesManager.getManager(myProject).getCachedValue(myProject, new CachedValueProvider() {
+ @Nullable
+ @Override
+ public Result compute() {
+ return Result.create(createAnnotationFromText("@" + AnnotationUtil.NULLABLE), ModificationTracker.NEVER_CHANGED);
+ }
+ });
+ }
+
public PsiAnnotation createContractAnnotation(String contractValue) {
return createAnnotationFromText("@org.jetbrains.annotations.Contract(" + contractValue + ")");
}
@@ -162,43 +180,50 @@ public class ProjectBytecodeAnalysis {
PsiElement gParent = parent.getParent();
if (gParent instanceof PsiMethod) {
final int index = ((PsiParameterList)parent).getParameterIndex((PsiParameter)owner);
- return BytecodeAnalysisConverter.psiKey((PsiMethod)gParent, new In(index), md);
+ return BytecodeAnalysisConverter.psiKey((PsiMethod)gParent, new In(index, In.NOT_NULL), md);
}
}
}
return null;
}
- public static ArrayList contractKeys(@NotNull PsiModifierListOwner owner, HKey primaryKey) {
- if (owner instanceof PsiMethod) {
- ArrayList result = BytecodeAnalysisConverter.mkInOutKeys((PsiMethod)owner, primaryKey);
- result.add(primaryKey);
- return result;
- }
- ArrayList result = new ArrayList(1);
+ public static ArrayList contractKeys(@NotNull PsiMethod owner, HKey primaryKey) {
+ ArrayList result = BytecodeAnalysisConverter.mkInOutKeys(owner, primaryKey);
result.add(primaryKey);
return result;
}
- private Annotations loadAnnotations(@NotNull PsiModifierListOwner owner, @NotNull HKey key, ArrayList allKeys)
+ private ParameterAnnotations loadParameterAnnotations(@NotNull HKey notNullKey)
throws EquationsLimitException {
- Annotations result = new Annotations();
- if (owner instanceof PsiParameter) {
- final Solver solver = new Solver(new ELattice(Value.NotNull, Value.Top));
- collectEquations(allKeys, solver);
- HashMap solutions = solver.solve();
- BytecodeAnalysisConverter.addParameterAnnotations(solutions, result);
- } else if (owner instanceof PsiMethod) {
- final Solver solver = new Solver(new ELattice(Value.Bot, Value.Top));
- collectEquations(allKeys, solver);
- HashMap solutions = solver.solve();
- int arity = ((PsiMethod)owner).getParameterList().getParameters().length;
- BytecodeAnalysisConverter.addMethodAnnotations(solutions, result, key, arity);
- }
+
+ final Solver notNullSolver = new Solver(new ELattice(Value.NotNull, Value.Top));
+ collectEquations(Collections.singletonList(notNullKey), notNullSolver);
+
+ HashMap notNullSolutions = notNullSolver.solve();
+ boolean notNull =
+ (Value.NotNull == notNullSolutions.get(notNullKey)) || (Value.NotNull == notNullSolutions.get(notNullKey.mkUnstable()));
+
+ final Solver nullableSolver = new Solver(new ELattice(Value.Null, Value.Top));
+ final HKey nullableKey = new HKey(notNullKey.key, notNullKey.dirKey + 1, true);
+ collectEquations(Collections.singletonList(nullableKey), nullableSolver);
+ HashMap nullableSolutions = nullableSolver.solve();
+ boolean nullable =
+ (Value.Null == nullableSolutions.get(nullableKey)) || (Value.Null == nullableSolutions.get(nullableKey.mkUnstable()));
+ return new ParameterAnnotations(notNull, nullable);
+ }
+
+ private MethodAnnotations loadMethodAnnotations(@NotNull PsiMethod owner, @NotNull HKey key, ArrayList allKeys)
+ throws EquationsLimitException {
+ MethodAnnotations result = new MethodAnnotations();
+ final Solver solver = new Solver(new ELattice(Value.Bot, Value.Top));
+ collectEquations(allKeys, solver);
+ HashMap solutions = solver.solve();
+ int arity = owner.getParameterList().getParameters().length;
+ BytecodeAnalysisConverter.addMethodAnnotations(solutions, result, key, arity);
return result;
}
- private void collectEquations(ArrayList keys, Solver solver) throws EquationsLimitException {
+ private void collectEquations(List keys, Solver solver) throws EquationsLimitException {
GlobalSearchScope librariesScope = ProjectScope.getLibrariesScope(myProject);
HashSet queued = new HashSet();
Stack queue = new Stack();
@@ -258,11 +283,21 @@ public class ProjectBytecodeAnalysis {
}
}
-class Annotations {
+class MethodAnnotations {
// @NotNull keys
final HashSet notNulls = new HashSet();
// @Contracts
final HashMap contracts = new HashMap();
}
+class ParameterAnnotations {
+ final boolean notNull;
+ final boolean nullable;
+
+ ParameterAnnotations(boolean notNull, boolean nullable) {
+ this.notNull = notNull;
+ this.nullable = nullable;
+ }
+}
+
class EquationsLimitException extends Exception {}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java
index 9fa5425e6999..1a7ab15722f9 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java
@@ -31,10 +31,12 @@ import static org.jetbrains.org.objectweb.asm.Opcodes.*;
public class LeakingParameters {
public final Frame[] frames;
public final boolean[] parameters;
+ public final boolean[] nullableParameters;
- public LeakingParameters(Frame[] frames, boolean[] parameters) {
+ public LeakingParameters(Frame[] frames, boolean[] parameters, boolean[] nullableParameters) {
this.frames = frames;
this.parameters = parameters;
+ this.nullableParameters = nullableParameters;
}
public static LeakingParameters build(String className, MethodNode methodNode, boolean jsr) throws AnalyzerException {
@@ -57,7 +59,12 @@ public class LeakingParameters {
}
}
}
- return new LeakingParameters((Frame[])(Frame>[])frames, collector.leaking);
+ boolean[] notNullParameters = collector.leaking;
+ boolean[] nullableParameters = collector.nullableLeaking;
+ for (int i = 0; i < nullableParameters.length; i++) {
+ nullableParameters[i] |= notNullParameters[i];
+ }
+ return new LeakingParameters((Frame[])(Frame>[])frames, notNullParameters, nullableParameters);
}
public static LeakingParameters buildFast(String className, MethodNode methodNode, boolean jsr) throws AnalyzerException {
@@ -66,11 +73,14 @@ public class LeakingParameters {
new Analyzer(parametersUsage).analyze(className, methodNode) :
new LiteAnalyzer(parametersUsage).analyze(className, methodNode);
int leakingMask = parametersUsage.leaking;
- boolean[] result = new boolean[parametersUsage.arity];
- for (int i = 0; i < result.length; i++) {
- result[i] = (leakingMask & (1 << i)) != 0;
+ int nullableLeakingMask = parametersUsage.nullableLeaking;
+ boolean[] notNullParameters = new boolean[parametersUsage.arity];
+ boolean[] nullableParameters = new boolean[parametersUsage.arity];
+ for (int i = 0; i < notNullParameters.length; i++) {
+ notNullParameters[i] = (leakingMask & (1 << i)) != 0;
+ nullableParameters[i] = ((leakingMask | nullableLeakingMask) & (1 << i)) != 0;
}
- return new LeakingParameters((Frame[])frames, result);
+ return new LeakingParameters((Frame[])frames, notNullParameters, nullableParameters);
}
}
@@ -288,6 +298,7 @@ class IParametersUsage extends Interpreter {
static final IParamsValue val1 = new IParamsValue(0, 1);
static final IParamsValue val2 = new IParamsValue(0, 2);
int leaking = 0;
+ int nullableLeaking = 0;
int called = -1;
final int rangeStart;
final int rangeEnd;
@@ -415,8 +426,12 @@ class IParametersUsage extends Interpreter {
case BALOAD:
case CALOAD:
case SALOAD:
+ leaking |= value1.params;
+ size = 1;
+ break;
case PUTFIELD:
leaking |= value1.params;
+ nullableLeaking |= value2.params;
size = 1;
break;
default:
@@ -432,12 +447,15 @@ class IParametersUsage extends Interpreter {
case LASTORE:
case FASTORE:
case DASTORE:
- case AASTORE:
case BASTORE:
case CASTORE:
case SASTORE:
leaking |= value1.params;
break;
+ case AASTORE:
+ leaking |= value1.params;
+ nullableLeaking |= value3.params;
+ break;
default:
}
return val1;
@@ -479,9 +497,11 @@ class IParametersUsage extends Interpreter {
class LeakingParametersCollector extends ParametersUsage {
final boolean[] leaking;
+ final boolean[] nullableLeaking;
LeakingParametersCollector(MethodNode methodNode) {
super(methodNode);
leaking = new boolean[arity];
+ nullableLeaking = new boolean[arity];
}
@Override
@@ -518,12 +538,21 @@ class LeakingParametersCollector extends ParametersUsage {
case BALOAD:
case CALOAD:
case SALOAD:
- case PUTFIELD:
boolean[] params = value1.params;
for (int i = 0; i < arity; i++) {
leaking[i] |= params[i];
}
break;
+ case PUTFIELD:
+ params = value1.params;
+ for (int i = 0; i < arity; i++) {
+ leaking[i] |= params[i];
+ }
+ params = value2.params;
+ for (int i = 0; i < arity; i++) {
+ nullableLeaking[i] |= params[i];
+ }
+ break;
default:
}
return super.binaryOperation(insn, value1, value2);
@@ -536,7 +565,6 @@ class LeakingParametersCollector extends ParametersUsage {
case LASTORE:
case FASTORE:
case DASTORE:
- case AASTORE:
case BASTORE:
case CASTORE:
case SASTORE:
@@ -545,6 +573,16 @@ class LeakingParametersCollector extends ParametersUsage {
leaking[i] |= params[i];
}
break;
+ case AASTORE:
+ params = value1.params;
+ for (int i = 0; i < arity; i++) {
+ leaking[i] |= params[i];
+ }
+ params = value3.params;
+ for (int i = 0; i < arity; i++) {
+ nullableLeaking[i] |= params[i];
+ }
+ break;
default:
}
return super.ternaryOperation(insn, value1, value2, value3);
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java
new file mode 100644
index 000000000000..55918450f481
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeCondition.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.intellij.codeInspection.inheritance;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiClass;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public abstract class ImplementedAtRuntimeCondition {
+ public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.codeInsight.implementedAtRuntime");
+
+ public abstract boolean isImplementedAtRuntime(@NotNull PsiClass psiClass);
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java
index 5d6c4bcb59a1..36d7bc2f17ef 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * 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.
@@ -540,7 +540,7 @@ public class JavaDocLocalInspectionBase extends BaseJavaBatchLocalInspectionTool
}
if (required && superMethods.length == 0 && isTagRequired(psiMethod, "@throws") && psiMethod.getThrowsList().getReferencedTypes().length > 0) {
- final Map declaredExceptions = new HashMap();
+ final Map declaredExceptions = new LinkedHashMap();
final PsiClassType[] classTypes = psiMethod.getThrowsList().getReferencedTypes();
for (PsiClassType classType : classTypes) {
final PsiClass psiClass = classType.resolve();
diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java
index 182f79c94bce..e373207222ea 100644
--- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java
+++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java
@@ -91,10 +91,27 @@ public class ExternalAnnotationsLineMarkerProvider implements LineMarkerProvider
private static boolean hasNonCodeAnnotations(@NotNull PsiModifierListOwner element) {
Project project = element.getProject();
PsiAnnotation[] externalAnnotations = ExternalAnnotationsManager.getInstance(project).findExternalAnnotations(element);
- if (externalAnnotations != null && externalAnnotations.length > 0) {
- return true;
+ if (externalAnnotations != null) {
+ for (PsiAnnotation annotation : externalAnnotations) {
+ if (isVisibleAnnotation(annotation)) {
+ return true;
+ }
+ }
}
- return InferredAnnotationsManager.getInstance(project).findInferredAnnotations(element).length > 0;
+ for (PsiAnnotation annotation : InferredAnnotationsManager.getInstance(project).findInferredAnnotations(element)) {
+ if (isVisibleAnnotation(annotation)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isVisibleAnnotation(@NotNull PsiAnnotation annotation) {
+ PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
+ if (ref == null) return true;
+
+ PsiElement target = ref.resolve();
+ return !(target instanceof PsiClass) || JavaDocInfoGenerator.isDocumentedAnnotationType((PsiClass)target);
}
@Override
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaColorProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaColorProvider.java
index dfc7169a2777..f74e4431d451 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaColorProvider.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaColorProvider.java
@@ -15,7 +15,6 @@
*/
package com.intellij.codeInsight.daemon.impl;
-import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.editor.ElementColorProvider;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
@@ -32,7 +31,12 @@ import java.awt.*;
public class JavaColorProvider implements ElementColorProvider {
@Override
public Color getColorFrom(@NotNull PsiElement element) {
- if (element instanceof PsiNewExpression && element.getLanguage() == JavaLanguage.INSTANCE) {
+ return getJavaColorFromExpression(element);
+ }
+
+ @Nullable
+ public static Color getJavaColorFromExpression(@Nullable PsiElement element) {
+ if (element instanceof PsiNewExpression) {
final PsiNewExpression expr = (PsiNewExpression)element;
final PsiType type = expr.getType();
if (type != null) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java
index 21e32a3e3aeb..d1d6691fca51 100644
--- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java
+++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java
@@ -3,10 +3,13 @@ package com.intellij.codeInsight.lookup;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.*;
+import com.intellij.codeInsight.daemon.impl.JavaColorProvider;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.RecursionManager;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
@@ -15,9 +18,11 @@ import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.HashMap;
+import com.intellij.util.ui.ColorIcon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.awt.*;
import java.util.Collection;
/**
@@ -25,10 +30,12 @@ import java.util.Collection;
*/
public class VariableLookupItem extends LookupItem implements TypedLookupItem, StaticallyImportable {
@Nullable private final MemberLookupHelper myHelper;
+ private Color myColor;
- public VariableLookupItem(PsiVariable object) {
- super(object, object.getName());
+ public VariableLookupItem(PsiVariable var) {
+ super(var, var.getName());
myHelper = null;
+ myColor = getInitializerColor(var);
}
public VariableLookupItem(PsiField field, boolean shouldImport) {
@@ -37,6 +44,30 @@ public class VariableLookupItem extends LookupItem implements Typed
if (!shouldImport) {
forceQualify();
}
+ myColor = getInitializerColor(field);
+ }
+
+ private static Color getInitializerColor(@NotNull PsiVariable var) {
+ PsiElement navigationElement = var.getNavigationElement();
+ if (navigationElement instanceof PsiVariable) {
+ var = (PsiVariable)navigationElement;
+ }
+ return getExpressionColor(var.getInitializer());
+ }
+
+ private static Color getExpressionColor(@Nullable PsiExpression expression) {
+ if (expression instanceof PsiReferenceExpression) {
+ final PsiElement target = ((PsiReferenceExpression)expression).resolve();
+ if (target instanceof PsiVariable) {
+ return RecursionManager.doPreventingRecursion(expression, true, new Computable() {
+ @Override
+ public Color compute() {
+ return getExpressionColor(((PsiVariable)target).getInitializer());
+ }
+ });
+ }
+ }
+ return JavaColorProvider.getJavaColorFromExpression(expression);
}
@Override
@@ -76,6 +107,9 @@ public class VariableLookupItem extends LookupItem implements Typed
if (myHelper != null) {
myHelper.renderElement(presentation, getAttribute(FORCE_QUALIFY) != null ? Boolean.TRUE : null, getSubstitutor());
}
+ if (myColor != null) {
+ presentation.setTypeText("", new ColorIcon(12, myColor));
+ }
}
@Override
diff --git a/java/java-impl/src/com/intellij/ide/util/scopeChooser/HierarchyScopeDescriptorProvider.java b/java/java-impl/src/com/intellij/ide/util/scopeChooser/HierarchyScopeDescriptorProvider.java
index 36ee6dfcdb36..1eda5c607525 100644
--- a/java/java-impl/src/com/intellij/ide/util/scopeChooser/HierarchyScopeDescriptorProvider.java
+++ b/java/java-impl/src/com/intellij/ide/util/scopeChooser/HierarchyScopeDescriptorProvider.java
@@ -21,11 +21,17 @@
package com.intellij.ide.util.scopeChooser;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.wm.ToolWindowId;
+import com.intellij.openapi.wm.ToolWindowManager;
import org.jetbrains.annotations.NotNull;
public class HierarchyScopeDescriptorProvider implements ScopeDescriptorProvider {
@NotNull
public ScopeDescriptor[] getScopeDescriptors(final Project project) {
+ if (Comparing.strEqual(ToolWindowManager.getInstance(project).getActiveToolWindowId(), ToolWindowId.TODO_VIEW)) {
+ return EMPTY;
+ }
return new ScopeDescriptor[]{new ClassHierarchyScopeDescriptor(project)};
}
}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/internal/StaticIconFieldsAction.java b/java/java-impl/src/com/intellij/internal/StaticIconFieldsAction.java
index 2864db6608e6..7fae15f159b7 100644
--- a/java/java-impl/src/com/intellij/internal/StaticIconFieldsAction.java
+++ b/java/java-impl/src/com/intellij/internal/StaticIconFieldsAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * 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.
@@ -22,10 +22,12 @@ package com.intellij.internal;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
@@ -49,19 +51,36 @@ public class StaticIconFieldsAction extends AnAction {
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Searching icons usages") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
- JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
- GlobalSearchScope all = GlobalSearchScope.allScope(project);
- PsiClass allIcons = facade.findClass("com.intellij.icons.AllIcons", all);
+ final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
+ final GlobalSearchScope all = GlobalSearchScope.allScope(project);
+ PsiClass allIcons = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiClass compute() {
+ return facade.findClass("com.intellij.icons.AllIcons", all);
+ }
+ });
searchFields(allIcons, view, indicator);
- for (PsiClass iconsClass : facade.findPackage("icons").getClasses(all)) {
+ PsiClass[] classes = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiClass[] compute() {
+ return facade.findPackage("icons").getClasses(all);
+ }
+ });
+ for (PsiClass iconsClass : classes) {
searchFields(iconsClass, view, indicator);
}
}
});
}
- private static void searchFields(PsiClass allIcons, final UsageView view, ProgressIndicator indicator) {
- indicator.setText("Searching for: " + allIcons.getQualifiedName());
+ private static void searchFields(final PsiClass allIcons, final UsageView view, final ProgressIndicator indicator) {
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ indicator.setText("Searching for: " + allIcons.getQualifiedName());
+ }
+ });
+
ReferencesSearch.search(allIcons).forEach(new Processor() {
@Override
public boolean process(PsiReference reference) {
diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java
index 345b3129defb..67bb13ce81e4 100644
--- a/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java
+++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java
@@ -36,7 +36,9 @@ public class ConstructorParameterOnFieldRenameRenamer extends AutomaticRenamer {
}
protected String nameToCanonicalName(@NonNls final String name, final PsiNamedElement element) {
- return JavaCodeStyleManager.getInstance(element.getProject()).variableNameToPropertyName(name, VariableKind.FIELD);
+ final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(element.getProject());
+ final VariableKind variableKind = element instanceof PsiVariable ? javaCodeStyleManager.getVariableKind((PsiVariable)element) : VariableKind.FIELD;
+ return javaCodeStyleManager.variableNameToPropertyName(name, variableKind);
}
public ConstructorParameterOnFieldRenameRenamer(PsiField aField, String newFieldName) {
diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java
index 876617b516e4..4bd3d6db70a5 100644
--- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java
+++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * 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.
@@ -28,13 +28,14 @@ import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
@@ -71,7 +72,7 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler {
}
final AnalysisScope scope = new AnalysisScope(file);
- final Module module = ModuleUtil.findModuleForPsiElement(file);
+ final Module module = ModuleUtilCore.findModuleForPsiElement(file);
final BaseAnalysisActionDialog dlg = new BaseAnalysisActionDialog(RefactoringBundle.message("replace.method.duplicates.scope.chooser.title", REFACTORING_NAME),
RefactoringBundle.message("replace.method.duplicates.scope.chooser.message"),
project, scope, module != null ? module.getName() : null, false,
@@ -134,13 +135,18 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler {
}
final Map> memberWithModulesMap = new HashMap>();
- for (PsiMember member : members) {
- final Module module = ModuleUtil.findModuleForPsiElement(member);
+ for (final PsiMember member : members) {
+ final Module module = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public Module compute() {
+ return ModuleUtilCore.findModuleForPsiElement(member);
+ }
+ });
if (module != null) {
final HashSet dependencies = new HashSet();
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
- ModuleUtil.collectModulesDependsOn(module, dependencies);
+ ModuleUtilCore.collectModulesDependsOn(module, dependencies);
}
});
memberWithModulesMap.put(member, dependencies);
@@ -158,7 +164,7 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler {
progressIndicator.setText2(ProjectUtil.calcRelativeToProjectPath(virtualFile, project));
}
}
- final Module targetModule = ModuleUtil.findModuleForPsiElement(file);
+ final Module targetModule = ModuleUtilCore.findModuleForPsiElement(file);
if (targetModule == null) return;
for (Map.Entry> entry : memberWithModulesMap.entrySet()) {
final Set dependencies = entry.getValue();
diff --git a/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java b/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java
index d59129174520..a08464fbd7ce 100644
--- a/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java
+++ b/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * 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.
@@ -244,7 +244,7 @@ public class SliceLeafAnalyzer {
final SliceNodeGuide guide = new SliceNodeGuide(treeStructure);
WalkingState walkingState = new WalkingState(guide) {
@Override
- public void visit(@NotNull SliceNode element) {
+ public void visit(@NotNull final SliceNode element) {
element.calculateDupNode();
node(element, map).clear();
SliceNode duplicate = element.getDuplicate();
@@ -252,20 +252,21 @@ public class SliceLeafAnalyzer {
node(element, map).addAll(node(duplicate, map));
}
else {
- final SliceUsage sliceUsage = element.getValue();
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ final SliceUsage sliceUsage = element.getValue();
- Collection extends AbstractTreeNode> children = element.getChildren();
- if (children.isEmpty()) {
- PsiElement value = ApplicationManager.getApplication().runReadAction(new Computable() {
- @Override
- public PsiElement compute() {
- return sliceUsage.indexNesting == 0 ? sliceUsage.getElement() : null;
+ Collection extends AbstractTreeNode> children = element.getChildren();
+ if (children.isEmpty()) {
+ PsiElement value = sliceUsage.indexNesting == 0 ? sliceUsage.getElement() : null;
+ if (value != null) {
+ node(element, map).addAll(ContainerUtil.singleton(value, LEAF_ELEMENT_EQUALITY));
+ }
}
- });
- if (value != null) {
- node(element, map).addAll(ContainerUtil.singleton(value, LEAF_ELEMENT_EQUALITY));
}
- }
+ });
+
super.visit(element);
}
}
diff --git a/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java b/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java
index b65932aeaa81..ba6f8602ba46 100644
--- a/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java
+++ b/java/java-impl/src/com/intellij/slicer/SliceNullnessAnalyzer.java
@@ -170,7 +170,7 @@ public class SliceNullnessAnalyzer {
final SliceLeafAnalyzer.SliceNodeGuide guide = new SliceLeafAnalyzer.SliceNodeGuide(treeStructure);
WalkingState walkingState = new WalkingState(guide) {
@Override
- public void visit(@NotNull SliceNode element) {
+ public void visit(@NotNull final SliceNode element) {
element.calculateDupNode();
node(element, map).clear();
SliceNode duplicate = element.getDuplicate();
@@ -178,11 +178,10 @@ public class SliceNullnessAnalyzer {
node(element, map).add(node(duplicate, map));
}
else {
- final SliceUsage sliceUsage = element.getValue();
final PsiElement value = ApplicationManager.getApplication().runReadAction(new Computable() {
@Override
public PsiElement compute() {
- return sliceUsage.getElement();
+ return element.getValue().getElement();
}
});
Nullness nullness = ApplicationManager.getApplication().runReadAction(new Computable() {
@@ -198,7 +197,13 @@ public class SliceNullnessAnalyzer {
group(element, map, NullAnalysisResult.NOT_NULLS).add(value);
}
else {
- Collection extends AbstractTreeNode> children = element.getChildren();
+ Collection extends AbstractTreeNode> children = ApplicationManager.getApplication().runReadAction(
+ new Computable>() {
+ @Override
+ public Collection extends AbstractTreeNode> compute() {
+ return element.getChildren();
+ }
+ });
if (children.isEmpty()) {
group(element, map, NullAnalysisResult.UNKNOWNS).add(value);
}
diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java b/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java
index abde9233f535..fd96a06d6cd4 100644
--- a/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java
+++ b/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java
@@ -28,6 +28,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -63,12 +64,17 @@ public class JavaTestGenerator implements TestGenerator {
if (targetClass == null) {
return null;
}
- addSuperClass(targetClass, project, d.getSuperClassName());
+ final TestFramework frameworkDescriptor = d.getSelectedTestFrameworkDescriptor();
+ final String defaultSuperClass = frameworkDescriptor.getDefaultSuperClass();
+ final String superClassName = d.getSuperClassName();
+ if (!Comparing.strEqual(superClassName, defaultSuperClass)) {
+ addSuperClass(targetClass, project, superClassName);
+ }
Editor editor = CodeInsightUtil.positionCursor(project, targetClass.getContainingFile(), targetClass.getLBrace());
addTestMethods(editor,
targetClass,
- d.getSelectedTestFrameworkDescriptor(),
+ frameworkDescriptor,
d.getSelectedMethods(),
d.shouldGeneratedBefore(),
d.shouldGeneratedAfter());
@@ -135,7 +141,7 @@ public class JavaTestGenerator implements TestGenerator {
private static void addSuperClass(PsiClass targetClass, Project project, String superClassName) throws IncorrectOperationException {
if (superClassName == null) return;
final PsiReferenceList extendsList = targetClass.getExtendsList();
- if (extendsList == null || extendsList.getReferencedTypes().length > 0) return;
+ if (extendsList == null) return;
PsiElementFactory ef = JavaPsiFacade.getInstance(project).getElementFactory();
PsiJavaCodeReferenceElement superClassRef;
@@ -147,7 +153,12 @@ public class JavaTestGenerator implements TestGenerator {
else {
superClassRef = ef.createFQClassNameReferenceElement(superClassName, GlobalSearchScope.allScope(project));
}
- extendsList.add(superClassRef);
+ final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
+ if (referenceElements.length == 0) {
+ extendsList.add(superClassRef);
+ } else {
+ referenceElements[0].replace(superClassRef);
+ }
}
@Nullable
diff --git a/java/java-indexing-impl/src/com/intellij/codeInsight/navigation/MethodImplementationsSearch.java b/java/java-indexing-impl/src/com/intellij/codeInsight/navigation/MethodImplementationsSearch.java
index 2e05e4cbc8aa..9a5f5ac4ddc1 100644
--- a/java/java-indexing-impl/src/com/intellij/codeInsight/navigation/MethodImplementationsSearch.java
+++ b/java/java-indexing-impl/src/com/intellij/codeInsight/navigation/MethodImplementationsSearch.java
@@ -50,7 +50,7 @@ public class MethodImplementationsSearch implements QueryExecutor methods = new ArrayList();
+ List methods = new ArrayList();
getOverridingMethods(psiMethod, methods, searchScope);
return ContainerUtil.process(methods, consumer);
}
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedElementsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedElementsSearcher.java
index dec2dccb341e..53fa2eb48604 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedElementsSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedElementsSearcher.java
@@ -18,7 +18,6 @@ package com.intellij.psi.impl.search;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
-import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
@@ -50,7 +49,12 @@ public class AnnotatedElementsSearcher implements QueryExecutor() {
+ @Override
+ public PsiManager compute() {
+ return annClass.getManager();
+ }
+ });
final SearchScope useScope = p.getScope();
final Class extends PsiModifierListOwner>[] types = p.getTypes();
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedPackagesSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedPackagesSearcher.java
index 4437b3f49e51..51565a81e5f4 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedPackagesSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/AnnotatedPackagesSearcher.java
@@ -19,15 +19,15 @@
*/
package com.intellij.psi.impl.search;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
-import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchHelper;
-import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.AnnotatedPackagesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Processor;
@@ -44,49 +44,67 @@ public class AnnotatedPackagesSearcher implements QueryExecutor() {
+ @Override
+ public String compute() {
+ return annClass.getQualifiedName();
+ }
+ });
assert annotationFQN != null;
- final PsiManagerImpl psiManager = (PsiManagerImpl)annClass.getManager();
- final SearchScope useScope = p.getScope();
+ final PsiManager psiManager = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiManager compute() {
+ return annClass.getManager();
+ }
+ });
+ final GlobalSearchScope useScope = (GlobalSearchScope)p.getScope();
- final String annotationShortName = annClass.getName();
+ final String annotationShortName = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public String compute() {
+ return annClass.getName();
+ }
+ });
assert annotationShortName != null;
- final GlobalSearchScope scope = useScope instanceof GlobalSearchScope ? (GlobalSearchScope)useScope : null;
+ final Collection annotations = JavaAnnotationIndex.getInstance().get(annotationShortName, psiManager.getProject(),
+ useScope);
- final Collection annotations = JavaAnnotationIndex.getInstance().get(annotationShortName, psiManager.getProject(), scope);
- for (PsiAnnotation annotation : annotations) {
- PsiModifierList modlist = (PsiModifierList)annotation.getParent();
- final PsiElement owner = modlist.getParent();
- if (!(owner instanceof PsiClass)) continue;
- PsiClass candidate = (PsiClass)owner;
- if (!"package-info".equals(candidate.getName())) continue;
-
- LOG.assertTrue(candidate.isValid());
-
- final PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
- if (ref == null) continue;
-
- if (!psiManager.areElementsEquivalent(ref.resolve(), annClass)) continue;
- if (useScope instanceof GlobalSearchScope &&
- !((GlobalSearchScope)useScope).contains(candidate.getContainingFile().getVirtualFile())) {
- continue;
- }
- final String qname = candidate.getQualifiedName();
- if (qname != null && !consumer.process(JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(
- qname.substring(0, qname.lastIndexOf('.'))))) {
- return false;
- }
+ for (final PsiAnnotation annotation : annotations) {
+ boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable(){
+ @Override
+ public Boolean compute() {
+ PsiModifierList modlist = (PsiModifierList)annotation.getParent();
+ final PsiElement owner = modlist.getParent();
+ if ((owner instanceof PsiClass)) {
+ PsiClass candidate = (PsiClass)owner;
+ if ("package-info".equals(candidate.getName())) {
+ LOG.assertTrue(candidate.isValid());
+ final PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
+ if (ref != null && psiManager.areElementsEquivalent(ref.resolve(), annClass) &&
+ useScope.contains(candidate.getContainingFile().getVirtualFile())) {
+ final String qname = candidate.getQualifiedName();
+ if (qname != null && !consumer.process(JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(
+ qname.substring(0, qname.lastIndexOf('.'))))) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+ });
+ if (!accepted) return false;
}
PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(psiManager.getProject());
final GlobalSearchScope infoFilesFilter = new PackageInfoFilesOnly();
GlobalSearchScope infoFiles =
- useScope instanceof GlobalSearchScope ? ((GlobalSearchScope)useScope).intersectWith(infoFilesFilter) : infoFilesFilter;
+ useScope.intersectWith(infoFilesFilter);
- final boolean[] wantmore = {true};
+ final boolean[] wantMore = {true};
helper.processAllFilesWithWord(annotationShortName, infoFiles, new Processor() {
@Override
public boolean process(final PsiFile psiFile) {
@@ -103,12 +121,12 @@ public class AnnotatedPackagesSearcher implements QueryExecutor> consumer) {
final PsiClass psiClass = p.getPsiClass();
- PsiMethod[] methodsArray = psiClass.getMethods();
- final List methods = new ArrayList(methodsArray.length);
- for (PsiMethod method : methodsArray) {
- if (PsiUtil.canBeOverriden(method)) methods.add(method);
- }
+ final List methods = ApplicationManager.getApplication().runReadAction(new Computable>() {
+ @Override
+ public List compute() {
+ PsiMethod[] methodsArray = psiClass.getMethods();
+ final List methods = new ArrayList(methodsArray.length);
+ for (PsiMethod method : methodsArray) {
+ if (PsiUtil.canBeOverriden(method)) methods.add(method);
+ }
+ return methods;
+ }
+ });
+
final SearchScope scope = p.getScope();
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java
index d7d5cb8fce21..287d43f4cf2d 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java
@@ -110,9 +110,14 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor> classes = new HashMap>();
- for (PsiReferenceList referenceList : candidates) {
+ for (final PsiReferenceList referenceList : candidates) {
ProgressIndicatorProvider.checkCanceled();
- final PsiClass candidate = (PsiClass)referenceList.getParent();
+ final PsiClass candidate = (PsiClass)ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiElement compute() {
+ return referenceList.getParent();
+ }
+ });
if (!checkInheritance(p, aClass, candidate)) continue;
String fqn = ApplicationManager.getApplication().runReadAction(new Computable() {
@@ -148,7 +153,13 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor() {
+ @Override
+ public Boolean compute() {
+ return aClass.isEnum();
+ }
+ });
+ if (isEnum) {
// abstract enum can be subclassed in the body
PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable() {
@Override
@@ -189,10 +200,10 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor() {
+ @Override
+ public VirtualFile compute() {
+ return PsiUtil.getJarFile(aClass);
+ }
+ });
+ }
}
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java
index 2ee2cc2d8123..f73af1d24902 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java
@@ -27,6 +27,7 @@ import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import org.jetbrains.annotations.NotNull;
@@ -36,15 +37,15 @@ import java.util.Collection;
public class JavaFunctionalExpressionSearcher implements QueryExecutor {
@Override
- public boolean execute(final @NotNull FunctionalExpressionSearch.SearchParameters queryParameters,
- final @NotNull Processor consumer) {
+ public boolean execute(@NotNull final FunctionalExpressionSearch.SearchParameters queryParameters,
+ @NotNull final Processor consumer) {
final PsiClass aClass = queryParameters.getElementToSearch();
- if (!ApplicationManager.getApplication().runReadAction(new Computable() {
+ if (ApplicationManager.getApplication().runReadAction(new Computable() {
@Override
public Boolean compute() {
- return LambdaUtil.isFunctionalClass(aClass);
+ return !LambdaUtil.isFunctionalClass(aClass) || !PsiUtil.isLanguageLevel8OrHigher(aClass);
}
- }) || !PsiUtil.isLanguageLevel8OrHigher(aClass)) {
+ })) {
return true;
}
return collectFunctionalExpressions(aClass, ApplicationManager.getApplication().runReadAction(new Computable() {
@@ -65,7 +66,7 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor lambdaCandidates = ApplicationManager.getApplication().runReadAction(new Computable>() {
@Override
@@ -76,16 +77,16 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor() {
- @Override
- public Boolean compute() {
+ for (final PsiReference ref : MethodReferencesSearch.search(psiMethod, scope, false)) {
+ boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ final PsiElement refElement = ref.getElement();
+ if (refElement != null) {
+ final PsiElement candidateElement = refElement.getParent();
+ if (candidateElement instanceof PsiCallExpression) {
+ final PsiExpressionList argumentList = ((PsiCallExpression)candidateElement).getArgumentList();
+ if (argumentList != null) {
final PsiExpression[] args = argumentList.getExpressions();
for (PsiExpression arg : args) {
if (arg instanceof PsiFunctionalExpression) {
@@ -96,57 +97,66 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor() {
+ @Override
+ public Boolean compute() {
+ final PsiElement element = reference.getElement();
+ if (element != null) {
+ final PsiElement parent = element.getParent();
+ if (parent instanceof PsiTypeElement) {
+ final PsiElement gParent = parent.getParent();
+ if (gParent instanceof PsiVariable) {
+ final PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(((PsiVariable)gParent).getInitializer());
+ if (initializer instanceof PsiFunctionalExpression) {
+ if (!consumer.process((PsiFunctionalExpression)initializer)) return false;
+ }
+ for (PsiReference varRef : ReferencesSearch.search(parent, scope)) {
+ final PsiElement varElement = varRef.getElement();
+ if (varElement != null) {
+ final PsiElement varElementParent = varElement.getParent();
+ if (varElementParent instanceof PsiAssignmentExpression &&
+ ((PsiAssignmentExpression)varElementParent).getLExpression() == varElement) {
+ final PsiExpression rExpression = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)varElementParent).getRExpression());
+ if (rExpression instanceof PsiFunctionalExpression) {
+ if (!consumer.process((PsiFunctionalExpression)rExpression)) return false;
+ }
+ }
+ }
+ }
+ } else if (gParent instanceof PsiMethod) {
+ final PsiReturnStatement[] returnStatements = ApplicationManager.getApplication().runReadAction(
+ new Computable() {
+ @Override
+ public PsiReturnStatement[] compute() {
+ return PsiUtil.findReturnStatements((PsiMethod)gParent);
+ }
+ });
+ for (PsiReturnStatement returnStatement : returnStatements) {
+ final PsiExpression returnValue = returnStatement.getReturnValue();
+ if (returnValue instanceof PsiFunctionalExpression) {
+ if (!consumer.process((PsiFunctionalExpression)returnValue)) return false;
}
}
}
}
- } else if (gParent instanceof PsiMethod) {
- final PsiReturnStatement[] returnStatements = ApplicationManager.getApplication().runReadAction(
- new Computable() {
- @Override
- public PsiReturnStatement[] compute() {
- return PsiUtil.findReturnStatements((PsiMethod)gParent);
- }
- });
- for (PsiReturnStatement returnStatement : returnStatements) {
- final PsiExpression returnValue = returnStatement.getReturnValue();
- if (returnValue instanceof PsiFunctionalExpression) {
- if (!consumer.process((PsiFunctionalExpression)returnValue)) return false;
- }
- }
}
+
+ return true;
}
- }
+ });
+ if (!accepted) return false;
+
}
return true;
}
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodDeepestSuperSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodDeepestSuperSearcher.java
index ece2108b072c..933998344add 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodDeepestSuperSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodDeepestSuperSearcher.java
@@ -1,5 +1,22 @@
+/*
+ * 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 com.intellij.psi.impl.search;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiMethod;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
@@ -23,12 +40,17 @@ public class MethodDeepestSuperSearcher implements QueryExecutor set,
Set guard,
Processor processor) {
if (guard != null && !guard.add(method)) return true;
- PsiMethod[] supers = method.findSuperMethods();
+ PsiMethod[] supers = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiMethod[] compute() {
+ return method.findSuperMethods();
+ }
+ });
if (supers.length == 0 && set.add(method) && !processor.process(method)) {
return false;
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java
index d65e80e7f997..acb5faae4947 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/MethodSuperSearcher.java
@@ -1,6 +1,23 @@
+/*
+ * 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 com.intellij.psi.impl.search;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.SuperMethodsSearch;
import com.intellij.psi.util.InheritanceUtil;
@@ -22,18 +39,23 @@ public class MethodSuperSearcher implements QueryExecutor consumer) {
final PsiClass parentClass = queryParameters.getPsiClass();
final PsiMethod method = queryParameters.getMethod();
- HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature();
+ return ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature();
- final boolean checkBases = queryParameters.isCheckBases();
- final boolean allowStaticMethod = queryParameters.isAllowStaticMethod();
- final List supers = signature.getSuperSignatures();
- for (HierarchicalMethodSignature superSignature : supers) {
- if (MethodSignatureUtil.isSubsignature(superSignature, signature)) {
- if (!addSuperMethods(superSignature, method, parentClass, allowStaticMethod, checkBases, consumer)) return false;
+ final boolean checkBases = queryParameters.isCheckBases();
+ final boolean allowStaticMethod = queryParameters.isAllowStaticMethod();
+ final List supers = signature.getSuperSignatures();
+ for (HierarchicalMethodSignature superSignature : supers) {
+ if (MethodSignatureUtil.isSubsignature(superSignature, signature)) {
+ if (!addSuperMethods(superSignature, method, parentClass, allowStaticMethod, checkBases, consumer)) return false;
+ }
+ }
+
+ return true;
}
- }
-
- return true;
+ });
}
private static boolean addSuperMethods(final HierarchicalMethodSignature signature,
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/PsiAnnotationMethodReferencesSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/PsiAnnotationMethodReferencesSearcher.java
index 50f10caef9cb..b5a6fc58d425 100644
--- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/PsiAnnotationMethodReferencesSearcher.java
+++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/PsiAnnotationMethodReferencesSearcher.java
@@ -1,5 +1,22 @@
+/*
+ * 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 com.intellij.psi.impl.search;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiUtil;
@@ -16,10 +33,24 @@ public class PsiAnnotationMethodReferencesSearcher implements QueryExecutor consumer) {
final PsiElement refElement = p.getElementToSearch();
- if (PsiUtil.isAnnotationMethod(refElement)) {
- PsiMethod method = (PsiMethod)refElement;
- if (PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(method.getName()) && method.getParameterList().getParametersCount() == 0) {
- final Query query = ReferencesSearch.search(method.getContainingClass(), p.getScope(), p.isIgnoreAccessScope());
+ boolean isAnnotation = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public Boolean compute() {
+ return PsiUtil.isAnnotationMethod(refElement);
+ }
+ });
+ if (isAnnotation) {
+ final PsiMethod method = (PsiMethod)refElement;
+ PsiClass containingClass = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiClass compute() {
+ boolean isValueMethod =
+ PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(method.getName()) && method.getParameterList().getParametersCount() == 0;
+ return isValueMethod ? method.getContainingClass() : null;
+ }
+ });
+ if (containingClass != null) {
+ final Query query = ReferencesSearch.search(containingClass, p.getScope(), p.isIgnoreAccessScope());
return query.forEach(createImplicitDefaultAnnotationMethodConsumer(consumer));
}
}
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
index f2b9583c49b0..23ab044569f2 100644
--- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
+++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
@@ -727,7 +727,7 @@ public class JavaDocInfoGenerator {
boolean inferred = AnnotationUtil.isInferredAnnotation(annotation);
if (resolved instanceof PsiClass) {
final PsiClass annotationType = (PsiClass)resolved;
- if (AnnotationUtil.isAnnotated(annotationType, "java.lang.annotation.Documented", false)) {
+ if (isDocumentedAnnotationType(annotationType)) {
if (inferred) buffer.append("");
final PsiClassType type = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(annotationType, PsiSubstitutor.EMPTY);
buffer.append("@");
@@ -770,6 +770,10 @@ public class JavaDocInfoGenerator {
}
}
+ public static boolean isDocumentedAnnotationType(PsiClass annotationType) {
+ return AnnotationUtil.isAnnotated(annotationType, "java.lang.annotation.Documented", false);
+ }
+
private void generateMethodParameterJavaDoc(@NonNls StringBuilder buffer, PsiParameter parameter, boolean generatePrologueAndEpilogue) {
if (generatePrologueAndEpilogue)
generatePrologue(buffer);
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml
index 0314b02a4d7b..2e75eb0e3c6c 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml
@@ -1,4 +1,10 @@
+ -
+
+
+ -
+
+
-
@@ -18,6 +24,12 @@
-
+ -
+
+
+ -
+
+
-
@@ -26,46 +38,85 @@
-
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
-
+ -
+
+
-
+ -
+
+
+ -
+
+
-
+ -
+
+
-
+ -
+
+
-
+ -
+
+
-
+ -
+
+
-
+ -
+
+
-
+ -
+
+
-
@@ -93,6 +144,9 @@
-
+ -
+
+
-
@@ -107,6 +161,9 @@
-
+ -
+
+
-
@@ -124,6 +181,9 @@
-
+ -
+
+
-
@@ -134,6 +194,9 @@
+ -
+
+
-
@@ -146,9 +209,48 @@
-
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
-
+ -
+
+
+ -
+
+
-
@@ -161,9 +263,54 @@
-
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
-
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
-
@@ -185,16 +332,28 @@
-
+ -
+
+
-
+ -
+
+
+ -
+
+
-
+ -
+
+
-
@@ -225,12 +384,21 @@
-
+ -
+
+
-
-
+ -
+
+
+ -
+
+
-
@@ -252,15 +420,24 @@
-
+ -
+
+
-
-
+ -
+
+
-
+ -
+
+
-
@@ -273,6 +450,9 @@
-
+ -
+
+
-