Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2017-06-08 18:14:46 +03:00
226 changed files with 2355 additions and 1538 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<log_file path="$PROJECT_DIR$/system/log/build-log/build.log" checked="true" skipped="true" show_all="false" alias="build.log" />
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
<option name="VM_PARAMETERS" value="-Xmx512m -XX:ReservedCodeCacheSize=150m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Xbootclasspath/p:../out/classes/production/boot -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Dapple.laf.useScreenMenuBar=true -Dsun.awt.disablegrab=true -Didea.jre.check=true -Didea.is.internal=true -Didea.debug.mode=true -Didea.config.path=../config -Didea.system.path=../system" />
<option name="VM_PARAMETERS" value="-Xmx512m -XX:ReservedCodeCacheSize=150m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:MaxJavaStackTraceDepth=10000 -ea -Xbootclasspath/a:../out/classes/production/boot -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Dapple.laf.useScreenMenuBar=true -Dsun.awt.disablegrab=true -Didea.jre.check=true -Didea.is.internal=true -Didea.debug.mode=true -Didea.config.path=../config -Didea.system.path=../system" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bin" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
-11
View File
@@ -147,17 +147,6 @@ BITS=$?
"$RM" -f "$VERSION_LOG"
test ${BITS} -eq 0 && BITS="64" || BITS=""
#----------------------------------------------------------------------
# Set platform enviroment variables for IDE
#----------------------------------------------------------------------
if [ "$OS_TYPE" = "Linux" ] ; then
case "$XDG_CURRENT_DESKTOP" in
*Unity*)
export JAYATANA_FORCE=true
;;
esac
fi
# ---------------------------------------------------------------------
# Collect JVM options and IDE properties.
# ---------------------------------------------------------------------
+1 -1
View File
@@ -1,4 +1,4 @@
# The file might be automatically updated. Comments and empty lines will be removed.
kotlinPluginBuild=1.1.2-release-IJ2017.2-1
jetSignBuild=42.30
jdkBuild=u152b915.1
jdkBuild=u152b927.1
@@ -48,7 +48,7 @@ public class ChainSearcher {
if (methods == null) {
methods = currentMethods;
} else {
methods.addAll(currentMethods);
methods = unionSortedSet(currentMethods, methods);
}
}
return new SearchInitializer(methods, context);
@@ -169,4 +169,13 @@ public class ChainSearcher {
result.add(newChain);
}
}
private static <T> SortedSet<T> unionSortedSet(SortedSet<T> s1, SortedSet<T> s2) {
if (s1.isEmpty()) return s2;
if (s2.isEmpty()) return s1;
TreeSet<T> result = new TreeSet<>();
result.addAll(s1);
result.addAll(s2);
return result;
}
}
@@ -57,7 +57,6 @@ public class ChainCompletionNewVariableLookupElement extends LookupElement {
@Override
public void handleInsert(final InsertionContext context) {
final PsiFile file = context.getFile();
((PsiJavaFile)file).importClass(myQualifierClass);
final PsiElement caretElement = ObjectUtils.notNull(file.findElementAt(context.getEditor().getCaretModel().getOffset()));
final PsiStatement statement = PsiTreeUtil.getParentOfType(caretElement.getPrevSibling(), PsiStatement.class, false);
@@ -67,8 +66,8 @@ public class ChainCompletionNewVariableLookupElement extends LookupElement {
final PsiStatement newVarDeclarationTemplate = elementFactory.createVariableDeclarationStatement(myNewVarName,
elementFactory.createType(myQualifierClass),
elementFactory.createExpressionFromText(PsiKeyword.NULL, null));
statement.getParent().addBefore(newVarDeclarationTemplate, statement);
PsiElement varDeclaration = statement.getParent().addBefore(newVarDeclarationTemplate, statement);
JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(varDeclaration);
}
@NotNull
@@ -246,7 +246,7 @@ public class ChainCompletionContext {
if (element instanceof PsiMethod) {
return ((PsiMethod)element).getReturnType();
}
throw new AssertionError(element);
return null;
}
public static boolean isWidelyUsed(@NotNull PsiType type) {
@@ -86,8 +86,8 @@ public class AppletConfigurationProducer extends JavaRuntimeConfigurationProduce
private static boolean isAppletClass(final PsiClass aClass, final PsiManager manager) {
if (DumbService.isDumb(manager.getProject())) return false;
if (!PsiClassUtil.isRunnableClass(aClass, true)) return false;
if (DumbService.isDumb(manager.getProject())) return true;
final Module module = JavaExecutionUtil.findModule(aClass);
final GlobalSearchScope scope = module != null
@@ -47,14 +47,24 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.text.JTextComponent;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -118,6 +128,12 @@ public class RepositoryAttachDialog extends DialogWrapper {
protected void textChanged(DocumentEvent e) {
ApplicationManager.getApplication().invokeLater(() -> {
if (myProgressIcon.isDisposed()) return;
ApplicationManager.getApplication().invokeLater(() -> {
if (myProgressIcon.isDisposed()) return;
handleMavenDependencyInsertion(e, textField);
updateComboboxSelection(false);
});
updateComboboxSelection(false);
});
}
@@ -163,6 +179,30 @@ public class RepositoryAttachDialog extends DialogWrapper {
init();
}
private static void handleMavenDependencyInsertion(DocumentEvent e, JTextField textField) {
if (e.getType() == DocumentEvent.EventType.INSERT) {
String text = textField.getText();
if (isMvnDependency(text)) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
try {
Document document = builder.parse(new InputSource(new StringReader(text)));
String mavenCoordinates = extractMavenCoordinates(document);
if (mavenCoordinates != null) {
textField.setText(mavenCoordinates);
}
}
catch (SAXException | IOException ignored) {
}
}
catch (ParserConfigurationException ignored) {
}
}
}
}
public boolean getAttachJavaDoc() {
return myJavaDocCheckBox.isSelected();
}
@@ -348,4 +388,46 @@ public class RepositoryAttachDialog extends DialogWrapper {
private void createUIComponents() {
myProgressIcon = new AsyncProcessIcon("Progress");
}
private static boolean isMvnDependency(String text) {
String trimmed = text.trim();
if (trimmed.startsWith("<dependency>") && trimmed.endsWith("</dependency>")) {
return true;
}
return false;
}
@Nullable
private static String extractMavenCoordinates(Document document) {
String groupId = getGroupId(document);
String artifactId = getArtifactId(document);
if (groupId.isEmpty() && artifactId.isEmpty()) {
return null;
}
String version = getVersion(document);
String classifier = getClassifier(document);
String gradleClassifier = classifier.isEmpty() ? "" : ":" + classifier;
return groupId + ":" + artifactId + ":" + version + gradleClassifier;
}
private static String getVersion(@NotNull Document document) {
return firstOrEmpty(document.getElementsByTagName("version"));
}
private static String getArtifactId(@NotNull Document document) {
return firstOrEmpty(document.getElementsByTagName("artifactId"));
}
private static String getGroupId(@NotNull Document document) {
return firstOrEmpty(document.getElementsByTagName("groupId"));
}
private static String getClassifier(@NotNull Document document) {
return firstOrEmpty(document.getElementsByTagName("classifier"));
}
private static String firstOrEmpty(@NotNull NodeList list) {
Node first = list.item(0);
return first != null ? first.getTextContent() : "";
}
}
@@ -71,6 +71,7 @@ public class ClassDataIndexer implements VirtualFileGist.GistCalculator<Map<HMet
try {
MessageDigest md = BytecodeAnalysisConverter.getMessageDigest();
Map<EKey, Equations> allEquations = processClass(new ClassReader(file.contentsToByteArray(false)), file.getPresentableUrl());
allEquations = solvePartially(allEquations);
allEquations.forEach((methodKey, equations) -> map.put(methodKey.method.hashed(md), hash(equations, md)));
}
catch (ProcessCanceledException e) {
@@ -85,6 +86,20 @@ public class ClassDataIndexer implements VirtualFileGist.GistCalculator<Map<HMet
return map;
}
private static Map<EKey, Equations> solvePartially(Map<EKey, Equations> map) {
PuritySolver solver = new PuritySolver();
EntryStream.of(map).mapToKey((key, eqs) -> new EKey(key.method, Pure, eqs.stable, false))
.flatMapValues(eqs -> eqs.results.stream().map(drp -> drp.result))
.selectValues(Effects.class)
.forKeyValue(solver::addEquation);
Map<EKey, Effects> solved = solver.solve();
Map<EKey, Effects> partiallySolvedPurity =
StreamEx.of(solved, solver.pending).flatMapToEntry(Function.identity()).removeValues(Effects::isTop).toMap();
return EntryStream.of(map)
.mapToValue((key, eqs) -> eqs.update(Pure, partiallySolvedPurity.get(new EKey(key.method, Pure, eqs.stable, false))))
.toMap();
}
private static Equations hash(Equations equations, MessageDigest md) {
return new Equations(ContainerUtil.map(equations.results, drp -> hash(drp, md)), equations.stable);
}
@@ -15,12 +15,11 @@
*/
package com.intellij.codeInspection.bytecodeAnalysis;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Stream;
/**
@@ -129,6 +128,15 @@ class Equations {
public int hashCode() {
return 31 * results.hashCode() + (stable ? 1 : 0);
}
@NotNull
Equations update(Direction direction, Effects newResult) {
List<DirectionResultPair> newPairs = StreamEx.of(this.results)
.map(drp -> drp.updateForDirection(direction, newResult))
.nonNull()
.toList();
return new Equations(newPairs, this.stable);
}
}
class DirectionResultPair {
@@ -159,6 +167,16 @@ class DirectionResultPair {
public String toString() {
return Direction.fromInt(directionKey) + "->" + result;
}
@Nullable
DirectionResultPair updateForDirection(Direction direction, Result newResult) {
if (this.directionKey == direction.asInt()) {
return newResult == null ? null : new DirectionResultPair(direction.asInt(), newResult);
}
else {
return this;
}
}
}
interface Result {}
@@ -227,6 +245,8 @@ final class Pending implements Result {
}
final class Effects implements Result {
static final Set<EffectQuantum> TOP_EFFECTS = Collections.singleton(EffectQuantum.TopEffectQuantum);
@NotNull final DataValue returnValue;
@NotNull final Set<EffectQuantum> effects;
@@ -239,6 +259,10 @@ final class Effects implements Result {
return Stream.concat(returnValue.dependencies(), effects.stream().flatMap(EffectQuantum::dependencies));
}
public boolean isTop() {
return returnValue == DataValue.UnknownDataValue1 && effects.equals(TOP_EFFECTS);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -254,6 +278,7 @@ final class Effects implements Result {
@Override
public String toString() {
return "Effects[" + effects.size() + "|" + returnValue + "]";
Object effectsPresentation = effects.isEmpty() ? "Pure" : effects.size() == 1 ? effects.iterator().next() : effects.size();
return "Effects[" + effectsPresentation + "|" + returnValue + "]";
}
}
@@ -66,7 +66,7 @@ public class PurityAnalysis {
for (EffectQuantum effectQuantum : quanta) {
if (effectQuantum != null) {
if (effectQuantum == EffectQuantum.TopEffectQuantum) {
return returnValue == DataValue.UnknownDataValue1 ? null : new Equation(key, new Effects(returnValue, PuritySolver.TOP_EFFECTS));
return returnValue == DataValue.UnknownDataValue1 ? null : new Equation(key, new Effects(returnValue, Effects.TOP_EFFECTS));
}
effects.add(effectQuantum);
}
@@ -559,11 +559,10 @@ class DataInterpreter extends Interpreter<DataValue> {
}
final class PuritySolver {
static final Set<EffectQuantum> TOP_EFFECTS = Collections.singleton(EffectQuantum.TopEffectQuantum);
private HashMap<EKey, Effects> solved = new HashMap<>();
private HashMap<EKey, Set<EKey>> dependencies = new HashMap<>();
private final Stack<EKey> moving = new Stack<>();
private HashMap<EKey, Effects> pending = new HashMap<>();
HashMap<EKey, Effects> pending = new HashMap<>();
void addEquation(EKey key, Effects effects) {
Set<EKey> depKeys = effects.dependencies().collect(Collectors.toSet());
@@ -593,7 +592,7 @@ final class PuritySolver {
}
else {
propagateKeys = new EKey[]{key.mkStable(), key};
propagateEffects = new Effects[]{effects, new Effects(DataValue.UnknownDataValue1, TOP_EFFECTS)};
propagateEffects = new Effects[]{effects, new Effects(DataValue.UnknownDataValue1, Effects.TOP_EFFECTS)};
}
for (int i = 0; i < propagateKeys.length; i++) {
EKey pKey = propagateKeys[i];
@@ -615,7 +614,7 @@ final class PuritySolver {
EffectQuantum.CallQuantum call = substitute((EffectQuantum.CallQuantum)dEffect, pKey, pEffects);
if (call.key.equals(pKey)) {
delta = substitute(pEffects, call.data, call.isStatic);
if(delta.equals(TOP_EFFECTS)) {
if(delta.equals(Effects.TOP_EFFECTS)) {
newEffects = delta;
break;
}
@@ -630,7 +629,7 @@ final class PuritySolver {
EffectQuantum.ReturnChangeQuantum retChange = (EffectQuantum.ReturnChangeQuantum)dEffect;
if (retChange.key.equals(pKey)) {
if(pEffects.returnValue != DataValue.LocalDataValue) {
newEffects = delta = TOP_EFFECTS;
newEffects = delta = Effects.TOP_EFFECTS;
break;
}
continue;
@@ -639,8 +638,8 @@ final class PuritySolver {
newEffects.add(dEffect);
}
if (TOP_EFFECTS.equals(delta) && returnValue.equals(DataValue.UnknownDataValue1)) {
solved.put(dKey, new Effects(returnValue, TOP_EFFECTS));
if (Effects.TOP_EFFECTS.equals(delta) && returnValue.equals(DataValue.UnknownDataValue1)) {
solved.put(dKey, new Effects(returnValue, Effects.TOP_EFFECTS));
moving.push(dKey);
}
else {
@@ -682,7 +681,7 @@ final class PuritySolver {
}
private static Set<EffectQuantum> substitute(Effects effects, DataValue[] data, boolean isStatic) {
if (effects.effects.isEmpty() || TOP_EFFECTS.equals(effects.effects)) {
if (effects.effects.isEmpty() || Effects.TOP_EFFECTS.equals(effects.effects)) {
return effects.effects;
}
Set<EffectQuantum> newEffects = new HashSet<>(effects.effects.size());
@@ -710,7 +709,7 @@ final class PuritySolver {
newEffects.add(new EffectQuantum.ReturnChangeQuantum(((DataValue.ReturnDataValue)arg).key));
continue;
}
return TOP_EFFECTS;
return Effects.TOP_EFFECTS;
}
return newEffects;
}
@@ -199,6 +199,10 @@ public class HardcodedContracts {
return className.startsWith("junit.framework.") || className.startsWith("org.junit.");
}
private static boolean isJunit5(String className) {
return className.startsWith("org.junit.jupiter.");
}
private static boolean isTestng(String className) {
return className.startsWith("org.testng.");
}
@@ -245,7 +249,7 @@ public class HardcodedContracts {
if (paramCount == 0) return Collections.emptyList();
int checkedParam = testng ? 0 : paramCount - 1;
int checkedParam = testng || isJunit5(className) ? 0 : paramCount - 1;
MethodContract.ValueConstraint[] constraints = createConstraintArray(paramCount);
if ("assertTrue".equals(methodName) || "assumeTrue".equals(methodName)) {
constraints[checkedParam] = FALSE_VALUE;
@@ -106,7 +106,10 @@ public class FunctionalInterfaceSuggester {
}
for (int i = 0; i < interfaceMethodParameters.length; i++) {
if (!TypeConversionUtil.isAssignable(parameters[i].getType(), substitutor.substitute(interfaceMethodParameters[i].getType()))) {
PsiType paramType = parameters[i].getType();
PsiType interfaceParamType = substitutor.substitute(interfaceMethodParameters[i].getType());
if (!(interfaceParamType instanceof PsiPrimitiveType
? paramType.equals(interfaceParamType) : TypeConversionUtil.isAssignable(paramType, interfaceParamType))) {
return null;
}
}
@@ -117,7 +120,7 @@ public class FunctionalInterfaceSuggester {
return null;
}
if (returnType instanceof PsiPrimitiveType && !returnType.equals(interfaceMethodReturnType)) {
if (interfaceMethodReturnType instanceof PsiPrimitiveType && !interfaceMethodReturnType.equals(returnType)) {
return null;
}
@@ -2,19 +2,75 @@ public int hashCode() {
#if (!$superHasHashCode && $fields.size()==1 && $fields[0].array)
return java.util.Arrays.hashCode($fields[0].accessor);
#else
return java.util.Objects.hash(##
#set($i = 0)
#if($superHasHashCode)
super.hashCode() ##
#set($i = 1)
#set($hasArrays = false)
#set($hasNoArrays = false)
#foreach($field in $fields)
#if ($field.array)
#set($hasArrays = true)
#else
#set($hasNoArrays = true)
#end
#end
#if (!$hasArrays)
return java.util.Objects.hash(##
#set($i = 0)
#if($superHasHashCode)
super.hashCode() ##
#set($i = 1)
#end
#foreach($field in $fields)
#if ($i > 0)
, ##
#end
$field.accessor ##
#set($i = $i + 1)
#end
);
#else
#set($resultName = $helper.getUniqueLocalVarName("result", $fields, $settings))
#set($resultAssigned = false)
#set($resultDeclarationCompleted = false)
int $resultName ##
#if($hasNoArrays)
= java.util.Objects.hash(##
#set($i = 0)
#if($superHasHashCode)
super.hashCode() ##
#set($i = 1)
#end
#foreach($field in $fields)
#if(!$field.array)
#if ($i > 0)
, ##
#end
$field.accessor ##
#set($i = $i + 1)
#end
#end
);
#set($resultAssigned = true)
#set($resultDeclarationCompleted = true)
#elseif($superHasHashCode)
= super.hashCode(); ##
#set($resultAssigned = true)
#set($resultDeclarationCompleted = true)
#end
#foreach($field in $fields)
#if ($i > 0)
, ##
#if($field.array)
#if ($resultDeclarationCompleted)
$resultName ##
#end
= ##
#if ($resultAssigned)
31 * $resultName + ##
#end
java.util.Arrays.hashCode($field.accessor);
#set($resultAssigned = true)
#set($resultDeclarationCompleted = true)
#end
$field.accessor ##
#set($i = $i + 1)
#end
);
#end
return $resultName;
#end
#end
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -98,7 +98,7 @@ public class SurroundAutoCloseableAction extends PsiElementBaseIntentionAction {
PsiElement sibling = element.getPrevSibling();
if (sibling instanceof PsiDeclarationStatement) {
PsiElement lastVar = ArrayUtil.getLastElement(((PsiDeclarationStatement)sibling).getDeclaredElements());
if (lastVar instanceof PsiLocalVariable) {
if (lastVar instanceof PsiLocalVariable && ((PsiLocalVariable)lastVar).getInitializer() != null) {
return (PsiLocalVariable)lastVar;
}
}
@@ -193,7 +193,7 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo
if(!hasNoBadRefs) return ProblemType.NONE;
if (!hasOptionalReference.get() || !(lambdaCandidate instanceof PsiExpression)) return ProblemType.INFO;
PsiExpression expression = (PsiExpression)lambdaCandidate;
if (!PsiType.VOID.equals(expression.getType()) && NullnessUtil.getExpressionNullness(expression) != Nullness.NOT_NULL) {
if (falseExpression != null && NullnessUtil.getExpressionNullness(expression) != Nullness.NOT_NULL) {
return ProblemType.INFO;
}
return ProblemType.WARNING;
@@ -52,6 +52,7 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
public boolean mySuggestMapPutIfAbsent = true;
public boolean mySuggestMapMerge = true;
public boolean myTreatGetNullAsContainsKey = false;
public boolean mySideEffects = false;
@Nullable
@Override
@@ -62,6 +63,7 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
panel.addCheckbox("Suggest conversion to Map.putIfAbsent", "mySuggestMapPutIfAbsent");
panel.addCheckbox("Suggest conversion to Map.merge", "mySuggestMapMerge");
panel.addCheckbox("Treat 'get(k) != null' the same as 'containsKey(k)' (may change semantics)", "myTreatGetNullAsContainsKey");
panel.addCheckbox("Suggest replacement even if lambda may have side effects", "mySideEffects");
return panel;
}
@@ -121,7 +123,9 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
if (PsiTreeUtil.collectElements(presentValue, e -> PsiEquivalenceUtil.areElementsEquivalent(e, absentValue)).length == 0) {
return;
}
condition.register(holder, new ReplaceWithSingleMapOperation("merge", PsiTreeUtil
boolean informationLevel =
!mySideEffects && SideEffectChecker.mayHaveSideEffects(presentValue, ex -> condition.extractGetCall(ex) != null);
condition.register(holder, informationLevel, new ReplaceWithSingleMapOperation("merge", PsiTreeUtil
.getParentOfType(absentValue, PsiMethodCallExpression.class), presentValue, noneBranch));
}
}
@@ -139,11 +143,11 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
condition.isMap(putCall.getMethodExpression().getQualifierExpression())) {
PsiExpression[] putArgs = putCall.getArgumentList().getExpressions();
if (putArgs.length != 2 || !condition.isKey(putArgs[0]) || !ExpressionUtils.isSimpleExpression(putArgs[1])) return;
condition.register(holder, new ReplaceWithSingleMapOperation("putIfAbsent", getCall, putArgs[1], result));
condition.register(holder, false, new ReplaceWithSingleMapOperation("putIfAbsent", getCall, putArgs[1], result));
}
if (mySuggestMapGetOrDefault && condition.isContainsKey() && ExpressionUtils.isSimpleExpression(noneExpression) &&
condition.isMapValueType(noneExpression.getType())) {
condition.register(holder, new ReplaceWithSingleMapOperation("getOrDefault", getCall, noneExpression, result));
condition.register(holder, false, new ReplaceWithSingleMapOperation("getOrDefault", getCall, noneExpression, result));
}
}
@@ -159,7 +163,7 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
PsiExpression rValue = assignment.getRExpression();
if (ExpressionUtils.isSimpleExpression(rValue) && condition.isValueReference(assignment.getLExpression()) &&
!condition.isValueReference(rValue) && condition.isMapValueType(rValue.getType())) {
condition.register(holder, ReplaceWithSingleMapOperation.fromIf("getOrDefault", condition, rValue));
condition.register(holder, false, ReplaceWithSingleMapOperation.fromIf("getOrDefault", condition, rValue));
}
} else if (condition.isGetNull()) {
/*
@@ -171,25 +175,30 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
*/
PsiExpression lambdaCandidate = extractLambdaCandidate(condition, noneBranch);
if (lambdaCandidate != null && mySuggestMapComputeIfAbsent) {
condition.register(holder, ReplaceWithSingleMapOperation.fromIf("computeIfAbsent", condition, lambdaCandidate));
boolean informationLevel = !mySideEffects && SideEffectChecker.mayHaveSideEffects(lambdaCandidate);
condition
.register(holder, informationLevel, ReplaceWithSingleMapOperation.fromIf("computeIfAbsent", condition, lambdaCandidate));
}
if (lambdaCandidate == null) {
PsiExpression expression = extractPutValue(condition, noneBranch);
if(expression != null) {
String replacement = null;
boolean informationLevel = false;
if (mySuggestMapPutIfAbsent && ExpressionUtils.isSimpleExpression(expression) && !condition.isValueReference(expression)) {
replacement = "putIfAbsent";
}
else if (mySuggestMapComputeIfAbsent && !condition.hasVariable()) {
informationLevel = !mySideEffects && SideEffectChecker.mayHaveSideEffects(expression);
replacement = "computeIfAbsent";
}
if(replacement != null) {
if(condition.hasVariable()) {
condition.register(holder, ReplaceWithSingleMapOperation.fromIf(replacement, condition, expression));
condition.register(holder, informationLevel, ReplaceWithSingleMapOperation.fromIf(replacement, condition, expression));
} else {
PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class);
LOG.assertTrue(call != null);
condition.register(holder, new ReplaceWithSingleMapOperation(replacement, call, expression, noneBranch));
condition
.register(holder, informationLevel, new ReplaceWithSingleMapOperation(replacement, call, expression, noneBranch));
}
}
}
@@ -554,9 +563,10 @@ public class Java8MapApiInspection extends BaseJavaBatchLocalInspectionTool {
return myFullCondition;
}
public void register(ProblemsHolder holder, ReplaceWithSingleMapOperation fix) {
public void register(ProblemsHolder holder, boolean informationLevel, ReplaceWithSingleMapOperation fix) {
//noinspection DialogTitleCapitalization
holder.registerProblem(getFullCondition(), QuickFixBundle.message("java.8.map.api.inspection.description", fix.myMethodName), fix);
holder.registerProblem(getFullCondition(), QuickFixBundle.message("java.8.map.api.inspection.description", fix.myMethodName),
informationLevel ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix);
}
public boolean isMapValueType(@Nullable PsiType type) {
@@ -120,7 +120,7 @@ public class RawTypeCanBeGenericInspection extends BaseJavaBatchLocalInspectionT
if (type != null) {
final TypeMigrationRules rules = new TypeMigrationRules();
rules.setBoundScope(PsiSearchHelper.SERVICE.getInstance(project).getUseScope(variable));
TypeMigrationProcessor.runHighlightingTypeMigration(project, null, rules, variable, type, false);
TypeMigrationProcessor.runHighlightingTypeMigration(project, null, rules, variable, type, false, true);
}
}
}
@@ -219,7 +219,6 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor {
}
protected void performRefactoring(@NotNull UsageInfo[] usages) {
if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myTargetClass)) return;
LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName());
try {
doRefactoring(usages);
@@ -147,7 +147,8 @@ public class ExtractEnumProcessor {
myTypeMigrationProcessor = new TypeMigrationProcessor(myProject,
PsiUtilCore.toPsiElementArray(myEnumConstants),
Functions.constant(JavaPsiFacade.getElementFactory(myProject).createType(myClass)),
rules);
rules,
true);
for (UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) {
final PsiElement migrateElement = usageInfo.getElement();
if (migrateElement instanceof PsiField) {
@@ -639,6 +639,9 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase {
final PsiType selectedType,
final ExtractMethodProcessor processor,
final PsiElement[] elements) {
if (!elements[0].isValid()) {
return;
}
final PsiElement commonParent = findCommonParent(elements);
if (commonParent == null) {
LOG.error("Should have common parent:" + Arrays.toString(elements));
@@ -42,11 +42,11 @@ import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.VariableData;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
public class IntroduceFunctionalVariableHandler extends IntroduceVariableHandler {
@@ -68,8 +68,12 @@ public class IntroduceFunctionalVariableHandler extends IntroduceVariableHandler
MyExtractMethodProcessor processor =
new MyExtractMethodProcessor(project, editor, elementsInCopy, null, IntroduceFunctionalVariableAction.REFACTORING_NAME, null,
HelpID.INTRODUCE_VARIABLE);
processor.setShowErrorDialogs(false);
try {
processor.prepare();
if (!processor.prepare()) {
showErrorMessage(project, editor);
return;
}
}
catch (PrepareFailedException e) {
showErrorMessage(project, editor);
@@ -116,6 +120,7 @@ public class IntroduceFunctionalVariableHandler extends IntroduceVariableHandler
Editor editor,
MyExtractMethodProcessor processor,
PsiElement[] elements) {
if (!elements[0].isValid()) return;
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, elements[0])) return;
MyExtractMethodProcessor physicalProcessor =
new MyExtractMethodProcessor(project, editor, elements,
@@ -259,6 +264,17 @@ public class IntroduceFunctionalVariableHandler extends IntroduceVariableHandler
};
}
@Override
public boolean prepare(@Nullable Pass<ExtractMethodProcessor> pass) throws PrepareFailedException {
final boolean prepare = super.prepare(pass);
if (prepare) {
if (myNotNullConditionalCheck || myNullConditionalCheck) {
return false;
}
}
return prepare;
}
@Override
public boolean showDialog() {
if (!myInputVariables.hasInstanceFields() && myInputVariables.getInputVariables().isEmpty() ||
@@ -275,12 +291,11 @@ public class IntroduceFunctionalVariableHandler extends IntroduceVariableHandler
}
public void copyParameters(MyExtractMethodProcessor processor) {
InputVariables inputVariables = processor.myInputVariables;
myInputVariables.setPassFields(inputVariables.isPassFields());
List<VariableData> variables = inputVariables.getInputVariables();
myVariableDatum = new VariableData[variables.size()];
for (int i = 0; i < variables.size(); i++) {
VariableData data = variables.get(i);
myInputVariables.setPassFields(processor.myInputVariables.isPassFields());
VariableData[] variables = processor.myVariableDatum;
myVariableDatum = new VariableData[variables.length];
for (int i = 0; i < variables.length; i++) {
VariableData data = variables[i];
String variableName = data.variable.getName();
assert variableName != null;
VariableData dataByVName =
@@ -147,7 +147,7 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
try {
ConflictsUtil.checkMethodConflicts(myTargetClass, myMethod, getPatternMethod(), conflicts);
}
catch (IncorrectOperationException e) {}
catch (IncorrectOperationException ignored) {}
return showConflicts(conflicts, usages);
}
@@ -247,8 +247,6 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
}
protected void performRefactoring(@NotNull UsageInfo[] usages) {
if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, myTargetClass)) return;
PsiMethod patternMethod = createMethodToAdd();
final List<PsiReference> docRefs = new ArrayList<>();
for (UsageInfo usage : usages) {
@@ -455,16 +453,16 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
}
return null;
}
private PsiMethod createMethodToAdd () {
ChangeContextUtil.encodeContextInfo(myMethod, true);
try {
final PsiManager manager = myMethod.getManager();
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
final PsiElementFactory factory = facade.getElementFactory();
//correct internal references
final PsiCodeBlock body = myMethod.getBody();
@@ -492,8 +490,11 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
final PsiElement resolved = expression.resolve();
if (ExpressionUtils.isReferenceTo(qualifier, myTargetVariable)) {
if (resolved instanceof PsiField) {
String fieldName = ((PsiField)resolved).getName();
LOG.assertTrue(fieldName != null);
for (PsiParameter parameter : myMethod.getParameterList().getParameters()) {
if (Comparing.strEqual(parameter.getName(), ((PsiField)resolved).getName())) {
if (Comparing.strEqual(parameter.getName(), fieldName) ||
facade.getResolveHelper().resolveReferencedVariable(fieldName, expression) != null) {
qualifier.replace(factory.createExpressionFromText("this", null));
return;
}
@@ -16,9 +16,13 @@
package com.intellij.refactoring.typeMigration;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.tree.IElementType;
@@ -27,7 +31,6 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
import com.intellij.util.Function;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,8 +49,11 @@ public class TypeEvaluator {
private final HashMap<TypeMigrationUsageInfo, LinkedList<PsiType>> myTypeMap;
private final TypeMigrationRules myRules;
private final TypeMigrationLabeler myLabeler;
private final ProjectFileIndex myProjectFileIndex;
public TypeEvaluator(final LinkedList<Pair<TypeMigrationUsageInfo, PsiType>> types, final TypeMigrationLabeler labeler) {
public TypeEvaluator(LinkedList<Pair<TypeMigrationUsageInfo, PsiType>> types,
TypeMigrationLabeler labeler,
Project project) {
myLabeler = labeler;
myRules = labeler == null ? new TypeMigrationRules() : labeler.getRules();
myTypeMap = new HashMap<>();
@@ -62,6 +68,7 @@ public class TypeEvaluator {
}
}
myProjectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
}
public boolean setType(final TypeMigrationUsageInfo usageInfo, @NotNull PsiType type) {
@@ -99,6 +106,11 @@ public class TypeEvaluator {
@Nullable
public PsiType getType(PsiElement element) {
VirtualFile file = element.getContainingFile().getVirtualFile();
if (file == null || !myProjectFileIndex.isInContent(file)) {
return TypeMigrationLabeler.getElementType(element);
}
for (Map.Entry<TypeMigrationUsageInfo, LinkedList<PsiType>> entry : myTypeMap.entrySet()) {
if (Comparing.equal(element, entry.getKey().getElement())) {
return entry.getValue().getFirst();
@@ -67,6 +67,7 @@ public class TypeMigrationLabeler {
private boolean myShowWarning = true;
private volatile MigrateException myException;
private final Semaphore myDialogSemaphore = new Semaphore();
private final Project myProject;
public TypeMigrationRules getRules() {
return myRules;
@@ -74,6 +75,7 @@ public class TypeMigrationLabeler {
private final TypeMigrationRules myRules;
private final Function<PsiElement, PsiType> myMigrationRootTypeFunction;
@Nullable private final Set<PsiElement> myAllowedRoots;
private TypeEvaluator myTypeEvaluator;
private final LinkedHashMap<PsiElement, Object> myConversions;
private final Map<Pair<SmartPsiElementPointer<PsiExpression>, PsiType>, TypeMigrationUsageInfo> myFailedConversions;
@@ -89,18 +91,23 @@ public class TypeMigrationLabeler {
private final Map<Pair<TypeMigrationUsageInfo, TypeMigrationUsageInfo>, Set<PsiElement>> myRootUsagesTree = new HashMap<>();
private final Set<TypeMigrationUsageInfo> myProcessedRoots = new HashSet<>();
public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) {
this(rules, Functions.constant(rootType));
public TypeMigrationLabeler(TypeMigrationRules rules, PsiType rootType, Project project) {
this(rules, Functions.constant(rootType), null, project);
}
public TypeMigrationLabeler(final TypeMigrationRules rules, Function<PsiElement, PsiType> migrationRootTypeFunction) {
public TypeMigrationLabeler(TypeMigrationRules rules,
Function<PsiElement, PsiType> migrationRootTypeFunction,
@Nullable("any root accepted if null") PsiElement[] allowedRoots,
Project project) {
myRules = rules;
myMigrationRootTypeFunction = migrationRootTypeFunction;
myAllowedRoots = allowedRoots == null ? null : ContainerUtil.set(allowedRoots);
myConversions = new LinkedHashMap<>();
myFailedConversions = new LinkedHashMap<>();
myNewExpressionTypeChange = new LinkedHashMap<>();
myClassTypeArgumentsChange = new LinkedHashMap<>();
myProject = project;
}
public boolean hasFailedConversions() {
@@ -574,6 +581,9 @@ public class TypeMigrationLabeler {
boolean alreadyProcessed,
final boolean isContraVariantPosition,
final boolean userDefinedType) {
if (myAllowedRoots != null && !myAllowedRoots.contains(element)) {
return false;
}
if (type.equals(PsiType.NULL)) {
return false;
}
@@ -1061,7 +1071,7 @@ public class TypeMigrationLabeler {
private void migrate(boolean autoMigrate, final PsiElement... victims) {
myMigrationRoots = new LinkedList<>();
myTypeEvaluator = new TypeEvaluator(myMigrationRoots, this);
myTypeEvaluator = new TypeEvaluator(myMigrationRoots, this, myProject);
for (PsiElement victim : victims) {
@@ -50,18 +50,25 @@ import java.util.Set;
import static com.intellij.util.ObjectUtils.assertNotNull;
public class TypeMigrationProcessor extends BaseRefactoringProcessor {
public volatile static boolean ourSkipFailedConversionInTestMode;
private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3;
private PsiElement[] myRoot;
private PsiElement[] myRoots;
private final Function<PsiElement, PsiType> myRootTypes;
private final boolean myAllowDependentRoots;
private final TypeMigrationRules myRules;
private TypeMigrationLabeler myLabeler;
public TypeMigrationProcessor(final Project project, final PsiElement[] roots, final Function<PsiElement, PsiType> rootTypes, final TypeMigrationRules rules) {
public TypeMigrationProcessor(final Project project,
final PsiElement[] roots,
final Function<PsiElement, PsiType> rootTypes,
final TypeMigrationRules rules,
final boolean allowDependentRoots) {
super(project);
myRoot = roots;
myRoots = roots;
myRules = rules;
myRootTypes = rootTypes;
myAllowDependentRoots = allowDependentRoots;
}
public static void runHighlightingTypeMigration(final Project project,
@@ -69,7 +76,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
final TypeMigrationRules rules,
final PsiElement root,
final PsiType migrationType) {
runHighlightingTypeMigration(project, editor, rules, root, migrationType, false);
runHighlightingTypeMigration(project, editor, rules, root, migrationType, false, true);
}
public static void runHighlightingTypeMigration(final Project project,
@@ -77,8 +84,9 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
final TypeMigrationRules rules,
final PsiElement root,
final PsiType migrationType,
final boolean optimizeImports) {
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports);
final boolean optimizeImports,
boolean allowDependentRoots) {
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports, allowDependentRoots);
}
@@ -87,9 +95,10 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
final TypeMigrationRules rules,
final PsiElement[] roots,
final Function<PsiElement, PsiType> migrationTypeFunction,
final boolean optimizeImports) {
final Set<PsiFile> containingFiles = ContainerUtil.map2Set(roots, element -> element.getContainingFile());
final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules) {
final boolean optimizeImports,
boolean allowDependentRoots) {
final Set<PsiFile> containingFiles = ContainerUtil.map2Set(roots, PsiElement::getContainingFile);
final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules, allowDependentRoots) {
@Override
public void performRefactoring(@NotNull final UsageInfo[] usages) {
super.performRefactoring(usages);
@@ -135,13 +144,17 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
@NotNull
@Override
protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
return new TypeMigrationViewDescriptor(myRoot[0]);
return new TypeMigrationViewDescriptor(myRoots[0]);
}
@Override
protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) {
if (hasFailedConversions()) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
if (ourSkipFailedConversionInTestMode) {
prepareSuccessful();
return true;
}
throw new BaseRefactoringProcessor.ConflictsInTestsException(Arrays.asList(myLabeler.getFailedConversionsReport()));
}
FailedConversionsDialog dialog = new FailedConversionsDialog(myLabeler.getFailedConversionsReport(), myProject);
@@ -164,24 +177,24 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
@Override
protected void previewRefactoring(@NotNull final UsageInfo[] usages) {
MigrationPanel panel = new MigrationPanel(myRoot, myLabeler, myProject, isPreviewUsages());
MigrationPanel panel = new MigrationPanel(myRoots, myLabeler, myProject, isPreviewUsages());
String name;
if (myRoot.length == 1) {
String fromType = assertNotNull(TypeMigrationLabeler.getElementType(myRoot[0])).getPresentableText();
String toType = myRootTypes.fun(myRoot[0]).getPresentableText();
if (myRoots.length == 1) {
String fromType = assertNotNull(TypeMigrationLabeler.getElementType(myRoots[0])).getPresentableText();
String toType = myRootTypes.fun(myRoots[0]).getPresentableText();
String text;
text = getPresentation(myRoot[0]);
text = getPresentation(myRoots[0]);
name = "Migrate Type of " + text + " from \'" + fromType + "\' to \'" + toType + "\'";
} else {
final int rootsInPresentationCount = myRoot.length > MAX_ROOT_IN_PREVIEW_PRESENTATION ? MAX_ROOT_IN_PREVIEW_PRESENTATION : myRoot.length;
final int rootsInPresentationCount = myRoots.length > MAX_ROOT_IN_PREVIEW_PRESENTATION ? MAX_ROOT_IN_PREVIEW_PRESENTATION : myRoots.length;
String[] rootsPresentation = new String[rootsInPresentationCount];
for (int i = 0; i < rootsInPresentationCount; i++) {
final PsiElement root = myRoot[i];
final PsiElement root = myRoots[i];
rootsPresentation[i] = root instanceof PsiNamedElement ? ((PsiNamedElement)root).getName() : root.getText();
}
rootsPresentation = StringUtil.surround(rootsPresentation, "\'", "\'");
name = "Migrate Type of " + StringUtil.join(rootsPresentation, ", ");
if (myRoot.length > MAX_ROOT_IN_PREVIEW_PRESENTATION) {
if (myRoots.length > MAX_ROOT_IN_PREVIEW_PRESENTATION) {
name += "...";
}
}
@@ -213,21 +226,21 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
@NotNull
@Override
public UsageInfo[] findUsages() {
myLabeler = new TypeMigrationLabeler(myRules, myRootTypes);
myLabeler = new TypeMigrationLabeler(myRules, myRootTypes, myAllowDependentRoots ? null : myRoots, myProject);
try {
return myLabeler.getMigratedUsages(!isPreviewUsages(), myRoot);
return myLabeler.getMigratedUsages(!isPreviewUsages(), myRoots);
}
catch (TypeMigrationLabeler.MigrateException e) {
setPreviewUsages(true);
myLabeler.clearStopException();
return myLabeler.getMigratedUsages(false, myRoot);
return myLabeler.getMigratedUsages(false, myRoots);
}
}
@Override
protected void refreshElements(@NotNull PsiElement[] elements) {
myRoot = elements;
myRoots = elements;
}
@Override
@@ -287,6 +300,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
return myLabeler;
}
@NotNull
@Override
protected String getCommandName() {
return "TypeMigration";
@@ -386,6 +386,8 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
final PsiExpression rOperand = operands[i];
if (rOperand == null) return;
final TypeView right = new TypeView(rOperand);
if (tryFindConversionIfOperandIsNull(left, right, rOperand)) continue;
if (tryFindConversionIfOperandIsNull(right, left, lOperand)) continue;
if (!TypeConversionUtil.isBinaryOperatorApplicable(operationTokenType, left.getType(), right.getType(), false)) {
if (left.isChanged()) {
findConversionOrFail(lOperand, lOperand, left.getTypePair());
@@ -399,6 +401,19 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
}
}
protected boolean tryFindConversionIfOperandIsNull(TypeView nullCandidate, TypeView comparingType, PsiExpression comparingExpr) {
if (nullCandidate.getType() == PsiType.NULL && comparingType.isChanged()) {
Pair<PsiType, PsiType> typePair = comparingType.getTypePair();
final TypeConversionDescriptorBase
conversion = myLabeler.getRules().findConversion(typePair.getFirst(), typePair.getSecond(), null, comparingExpr, false, myLabeler);
if (conversion != null) {
myLabeler.setConversionMapping(comparingExpr, conversion);
}
return true;
}
return false;
}
private void processArrayInitializer(final PsiArrayInitializerExpression expression, final PsiExpression parentExpression) {
final PsiExpression[] initializers = expression.getInitializers();
PsiType migrationType = null;
@@ -593,6 +608,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
}
}
private static boolean canBeVariableType(@NotNull PsiType type) {
return !type.getDeepComponentType().equals(PsiType.VOID);
}
@@ -98,7 +98,7 @@ public abstract class TypeMigrationDialog extends RefactoringDialog {
myRules = new TypeMigrationRules();
myRules.setBoundScope(myScopeChooserCombo.getSelectedScope());
}
invokeRefactoring(new TypeMigrationProcessor(myProject, myRoots, getMigrationTypeFunction(), myRules));
invokeRefactoring(new TypeMigrationProcessor(myProject, myRoots, getMigrationTypeFunction(), myRules, true));
}
@NotNull
@@ -31,6 +31,7 @@ import java.util.regex.Pattern;
public class ThreadDumpParser {
private static final Pattern ourThreadStartPattern = Pattern.compile("^\\s*\"(.+)\".+(prio=\\d+ (?:os_prio=[^\\s]+ )?tid=[^\\s]+ nid=[^\\s]+|[Ii][Dd]=\\d+) ([^\\[]+)");
private static final Pattern ourYourkitThreadStartPattern = Pattern.compile("(.+) \\[([^\\[]*)]");
private static final Pattern ourYourkitThreadStartPattern2 = Pattern.compile("(.+) State: (.+) CPU usage on sample: .+");
private static final Pattern ourThreadStatePattern = Pattern.compile("java\\.lang\\.Thread\\.State: (.+) \\((.+)\\)");
private static final Pattern ourThreadStatePattern2 = Pattern.compile("java\\.lang\\.Thread\\.State: (.+)");
private static final Pattern ourWaitingForLockPattern = Pattern.compile("- waiting (on|to lock) <(.+)>");
@@ -188,7 +189,7 @@ public class ThreadDumpParser {
}
@Nullable
private static ThreadState tryParseThreadStart(final String line) {
private static ThreadState tryParseThreadStart(String line) {
Matcher m = ourThreadStartPattern.matcher(line);
if (m.find()) {
final ThreadState state = new ThreadState(m.group(1), m.group(3));
@@ -197,14 +198,17 @@ public class ThreadDumpParser {
}
return state;
}
boolean daemon = line.contains(" [DAEMON]");
if (daemon) {
line = StringUtil.replace(line, " [DAEMON]", "");
}
String noDaemon = StringUtil.trimEnd(line, " [DAEMON]");
m = ourYourkitThreadStartPattern.matcher(noDaemon);
m = ourYourkitThreadStartPattern.matcher(line);
if (!m.matches()) m = ourYourkitThreadStartPattern2.matcher(line);
if (m.matches()) {
ThreadState state = new ThreadState(m.group(1), m.group(2));
if (noDaemon.length() < line.length()) {
state.setDaemon(true);
}
state.setDaemon(daemon);
return state;
}
return null;
@@ -0,0 +1,29 @@
import java.util.Arrays;
import java.util.Objects;
class A {
int i;
String s;
int[] a1;
int[] a2;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final A a = (A) o;
return i == a.i &&
Objects.equals(s, a.s) &&
Arrays.equals(a1, a.a1) &&
Arrays.equals(a2, a.a2);
}
@Override
public int hashCode() {
int result = Objects.hash(i, s);
result = 31 * result + Arrays.hashCode(a1);
result = 31 * result + Arrays.hashCode(a2);
return result;
}
}
@@ -0,0 +1,31 @@
import java.util.Arrays;
class I {
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
return o == this;
}
}
class A extends I {
int[] a1;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
final A a = (A) o;
return Arrays.equals(a1, a.a1);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + Arrays.hashCode(a1);
return result;
}
}
@@ -0,0 +1,7 @@
class A {
int i;
String s;
int[] a1;
int[] a2;
<caret>
}
@@ -0,0 +1,13 @@
class I {
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
return o == this;
}
}
class A extends I {
int[] a1;
<caret>
}
@@ -8,4 +8,20 @@ class Contracts {
String s = o.toString();
}
void foo2(@Nullable Object o) {
Assertions.assertNotNull(o, "message");
String s = o.toString();
}
void foo3(java.util.function.BooleanSupplier o) {
Assertions.assertTrue(o, "message");
}
void foo3(boolean b) {
Assertions.assertTrue(b, "message");
if (<warning descr="Condition '!b' is always 'false'">!<warning descr="Value 'b' is always 'true'">b</warning></warning>) {
System.out.println("how?");
}
}
}
@@ -1,4 +1,4 @@
// "Replace with 'computeIfAbsent' method call" "true"
// "Replace with 'computeIfAbsent' method call" "GENERIC_ERROR_OR_WARNING"
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -1,4 +1,4 @@
// "Replace with 'computeIfAbsent' method call" "true"
// "Replace with 'computeIfAbsent' method call" "INFORMATION"
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -1,4 +1,4 @@
// "Replace with 'merge' method call" "true"
// "Replace with 'merge' method call" "GENERIC_ERROR_OR_WARNING"
import java.util.Map;
public class Main {
@@ -1,4 +1,4 @@
// "Replace with 'computeIfAbsent' method call" "true"
// "Replace with 'computeIfAbsent' method call" "GENERIC_ERROR_OR_WARNING"
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -1,4 +1,4 @@
// "Replace with 'computeIfAbsent' method call" "true"
// "Replace with 'computeIfAbsent' method call" "INFORMATION"
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -1,4 +1,4 @@
// "Replace with 'merge' method call" "true"
// "Replace with 'merge' method call" "GENERIC_ERROR_OR_WARNING"
import java.util.Map;
public class Main {
@@ -0,0 +1,8 @@
class Test {
{
int x = 0, y;
<selection>y = ++x;</selection>
System.out.println("x = " + x);
System.out.println("y = " + y);
}
}
@@ -0,0 +1,23 @@
import java.util.ArrayList;
import java.util.List;
class Data {
final List<Datum> datums;
Data(List<Datum> datums) {
this.datums = datums;
}
static class Datum { }
}
class DataUser {
public List<Data.Datum> fi<caret>lter(Data data) {
List<Data.Datum> datums = new ArrayList<>();
for (Data.Datum datum : data.datums) {
if (datum != null) datums.add(datum);
}
return datums;
}
}
@@ -0,0 +1,24 @@
import java.util.ArrayList;
import java.util.List;
class Data {
final List<Datum> datums;
Data(List<Datum> datums) {
this.datums = datums;
}
public List<Datum> filter() {
List<Datum> datums = new ArrayList<>();
for (Datum datum : this.datums) {
if (datum != null) datums.add(datum);
}
return datums;
}
static class Datum { }
}
class DataUser {
}
@@ -68,6 +68,14 @@ public class GenerateEquals15Test extends GenerateEqualsTestCase {
doTestWithTemplate(EqualsHashCodeTemplatesManager.JAVA_UTIL_OBJECTS_EQUALS_AND_HASH_CODE);
}
public void testArrayAndNotOnlyArrayWithObjectsTemplate() throws Exception {
doTestWithTemplate(EqualsHashCodeTemplatesManager.JAVA_UTIL_OBJECTS_EQUALS_AND_HASH_CODE);
}
public void testArrayAndSuperWithObjectsTemplate() throws Exception {
doTestWithTemplate(EqualsHashCodeTemplatesManager.JAVA_UTIL_OBJECTS_EQUALS_AND_HASH_CODE);
}
private void doTestWithTemplate(String templateName) throws Exception {
try {
EqualsHashCodeTemplatesManager.getInstance().setDefaultTemplate(templateName);
@@ -107,7 +107,7 @@ public class HighlightStressTest extends LightDaemonAnalyzerTestCase {
UIUtil.dispatchAllInvocationEvents();
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
}
System.out.println(System.currentTimeMillis() - time+"ms");
LOG.debug(System.currentTimeMillis() - time+"ms");
}
public void _testHugeFile() throws Exception {
@@ -124,11 +124,11 @@ public class HighlightStressTest extends LightDaemonAnalyzerTestCase {
doHighlighting();
long end = System.currentTimeMillis();
time[i] = end - start;
System.out.println("i = " + i + "; time= "+(end-start));
LOG.debug("i = " + i + "; time= "+(end-start));
UIUtil.dispatchAllInvocationEvents();
}
System.out.println("Average among the N/3 median times: " + ArrayUtil.averageAmongMedians(time, 3) + "ms");
LOG.debug("Average among the N/3 median times: " + ArrayUtil.averageAmongMedians(time, 3) + "ms");
//System.out.println("JobLauncher.COUNT = " + JobLauncher.COUNT);
//System.out.println("JobLauncher.TINY = " + JobLauncher.TINY_COUNT);
@@ -166,7 +166,7 @@ public class HighlightStressTest extends LightDaemonAnalyzerTestCase {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
long start = System.currentTimeMillis();
System.out.println("i = " + i);
LOG.debug("i = " + i);
String s = myFile.getText();
int offset;
while (true) {
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
import com.intellij.codeInsight.hint.EditorHintListener;
import com.intellij.codeInsight.intention.AbstractIntentionAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.IntentionActionDelegate;
import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
import com.intellij.codeInspection.*;
@@ -36,6 +37,7 @@ import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase;
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.codeInspection.htmlInspections.RequiredAttributesInspectionBase;
import com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection;
import com.intellij.configurationStore.StorageUtilKt;
@@ -1576,7 +1578,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase {
final DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject());
int N = Math.max(5, Timings.adjustAccordingToMySpeed(80, false));
System.out.println("N = " + N);
LOG.debug("N = " + N);
final long[] interruptTimes = new long[N];
for (int i = 0; i < N; i++) {
codeAnalyzer.restart();
@@ -1688,7 +1690,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase {
final DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject());
int N = Math.max(5, Timings.adjustAccordingToMySpeed(80, false));
System.out.println("N = " + N);
LOG.debug("N = " + N);
final long[] interruptTimes = new long[N];
for (int i = 0; i < N; i++) {
codeAnalyzer.restart();
@@ -2651,7 +2653,32 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase {
assertEmpty(fixes);
}
public void testStupidQuickFixIsStillVisibleAfterAppliedButDidNothing() {
MyInspection tool = new MyInspection();
enableInspectionTool(tool);
disposeOnTearDown(() -> disableInspectionTool(tool.getShortName()));
@Language("JAVA")
String text = "class X { void f() { if (this == null) {} else return; } }";
configureByText(JavaFileType.INSTANCE, text);
WriteCommandAction.runWriteCommandAction(getProject(), () -> myEditor.getDocument().setText(text));
getEditor().getCaretModel().moveToOffset(getFile().getText().indexOf("if (") + 1);
assertEmpty(doHighlighting(HighlightSeverity.ERROR));
List<IntentionAction> fixes = findStupidFixes();
IntentionAction fix = assertOneElement(fixes);
((MyInspection.StupidQuickFixWhichDoesntCheckItsOwnApplicability)((QuickFixWrapper)((IntentionActionDelegate)fix).getDelegate()).getFix()).doFix = false;
fix.invoke(getProject(), getEditor(), getFile()); // did nothing
fixes = findStupidFixes();
assertOneElement(fixes);
assertEmpty(doHighlighting(HighlightSeverity.ERROR));
fixes = findStupidFixes();
assertOneElement(fixes);
}
private List<IntentionAction> findStupidFixes() {
UIUtil.dispatchAllInvocationEvents();
return CodeInsightTestFixtureImpl.getAvailableIntentions(getEditor(), getFile())
.stream().filter(f->f.getFamilyName().equals(new MyInspection.StupidQuickFixWhichDoesntCheckItsOwnApplicability().getFamilyName()))
.collect(Collectors.toList());
@@ -2692,6 +2719,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase {
};
}
private static class StupidQuickFixWhichDoesntCheckItsOwnApplicability implements LocalQuickFix {
private boolean doFix = true;
@Nls
@NotNull
@Override
@@ -2708,7 +2736,9 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase {
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
WriteCommandAction.runWriteCommandAction(project, () -> ((PsiIfStatement)descriptor.getPsiElement().getParent()).getElseBranch().delete());
if (doFix) {
WriteCommandAction.runWriteCommandAction(project, () -> ((PsiIfStatement)descriptor.getPsiElement().getParent()).getElseBranch().delete());
}
}
}
}
@@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull;
public class ComparatorResultComparisonInspectionTest extends LightInspectionTestCase {
public static final String TEST_DATA_DIR = "/codeInsight/daemonCodeAnalyzer/quickFix/comparatorResultComparison/";
static final String TEST_DATA_DIR = "/codeInsight/daemonCodeAnalyzer/quickFix/comparatorResultComparison/";
public void testComparatorResultComparison() {
doTest();
@@ -17,11 +17,18 @@ package com.intellij.java.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInspection.dataFlow.DataFlowInspection;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class HardcodedContractsTest extends DataFlowInspectionTestCase {
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_8;
}
@Override
protected String getTestDataPath() {
@@ -110,8 +117,13 @@ public class HardcodedContractsTest extends DataFlowInspectionTestCase {
}
public void testJunit5Assert() {
myFixture.addClass("package org.junit.jupiter.api; public class Assertions {\n" +
myFixture.addClass("package org.junit.jupiter.api;" +
"import java.util.function.BooleanSupplier;" +
"public class Assertions {\n" +
" public static void assertNotNull(Object actual){}" +
" public static void assertNotNull(Object actual, String message){}" +
" public static void assertTrue(boolean b, String message){}" +
" public static void assertTrue(BooleanSupplier b, String message){}" +
"}");
checkHighlighting();
}
@@ -32,7 +32,7 @@ import org.jetbrains.annotations.NotNull;
* @author Tagir Valeev
*/
public class ObviousNullCheckInspectionTest extends LightInspectionTestCase {
public static final String TEST_DATA_DIR = "/inspection/obviousNotNull/";
static final String TEST_DATA_DIR = "/inspection/obviousNotNull/";
private static final LightProjectDescriptor JAVA_8_WITH_ANNOTATIONS = new DefaultLightProjectDescriptor() {
@Override
@@ -39,8 +39,8 @@ public class FunctionalInterfaceSuggesterTest extends LightCodeInsightFixtureTes
.stream()
.map(type -> type.getCanonicalText())
.collect(Collectors.toList());
Assert.assertTrue(suggestedTypes.containsAll(Arrays.asList("java.util.function.IntToDoubleFunction",
Assert.assertEquals(4, suggestedTypes.size());
Assert.assertTrue(suggestedTypes.containsAll(Arrays.asList("java.util.function.ToDoubleFunction<java.lang.Double>",
"java.util.function.DoubleUnaryOperator")));
Assert.assertFalse(suggestedTypes.contains("java.util.function.LongToIntFunction"));
}
}
@@ -63,6 +63,17 @@ public class IntroduceFunctionalVariableTest extends LightRefactoringTestCase {
doTest(0);
}
public void testIgnoreMethodObjectSuggestion() throws Exception {
try {
doTest();
fail("Unable to perform is expected");
}
catch (CommonRefactoringUtil.RefactoringErrorHintException e) {
assertEquals("Cannot perform refactoring.\n" +
"Extract Functional Variable is not supported in current context", e.getMessage());
}
}
public void testNoSuggestionForInaccessibleInterface() throws Exception {
try {
doTest();
@@ -502,10 +502,7 @@ public class InlineToAnonymousClassTest extends LightRefactoringTestCase {
}
@Override
protected LanguageLevel getLanguageLevel() {
if (getTestName(false).endsWith("Java8")) {
return LanguageLevel.JDK_1_8;
}
protected LanguageLevel getDefaultLanguageLevel() {
return LanguageLevel.JDK_1_7;
}
}
@@ -104,6 +104,10 @@ public class MoveInstanceMethodTest extends LightRefactoringTestCase {
doTest(true, 0);
}
public void testConflictingLocalVariableAndTargetClassField() throws Exception {
doTest(true, 0);
}
public void testMethodReference() throws Exception {
BaseRefactoringProcessor.ConflictsInTestsException.withIgnoredConflicts(() -> doTest(true, 0));
}
@@ -118,6 +118,56 @@ java.lang.Thread.run() Thread.java:745
assert threads.collect { it.daemon } == [false, true, false]
assert threads.collect { it.stackTrace.readLines().size() } == [2, 2, 5] // thread name is included into stack trace
}
void "test YourKit 2017 format"() {
def text = '''
Stacks at 2017-06-08 12:56:31 PM. Uptime is 23m 47s 200ms.
thread 23 State: RUNNABLE CPU usage on sample: 968ms
com.intellij.openapi.util.io.win32.IdeaWin32.listChildren0(String) IdeaWin32.java (native)
com.intellij.openapi.util.io.win32.IdeaWin32.listChildren(String) IdeaWin32.java:136
com.intellij.openapi.vfs.impl.win32.Win32FsCache.list(VirtualFile) Win32FsCache.java:58
com.intellij.openapi.vfs.impl.win32.Win32LocalFileSystem.list(VirtualFile) Win32LocalFileSystem.java:57
com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker.partialDirRefresh(NewVirtualFileSystem, TObjectHashingStrategy, VirtualDirectoryImpl) RefreshWorker.java:272
com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker.processQueue(NewVirtualFileSystem, PersistentFS) RefreshWorker.java:124
com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker.scan() RefreshWorker.java:85
com.intellij.openapi.vfs.newvfs.RefreshSessionImpl.scan() RefreshSessionImpl.java:147
com.intellij.openapi.vfs.newvfs.RefreshQueueImpl.doScan(RefreshSessionImpl) RefreshQueueImpl.java:91
com.intellij.openapi.vfs.newvfs.RefreshQueueImpl.lambda$queueSession$1(RefreshSessionImpl, TransactionId, ModalityState) RefreshQueueImpl.java:74
com.intellij.openapi.vfs.newvfs.RefreshQueueImpl$$Lambda$242.run()
java.util.concurrent.Executors$RunnableAdapter.call() Executors.java:511
java.util.concurrent.FutureTask.run() FutureTask.java:266
com.intellij.util.concurrency.BoundedTaskExecutor$2.run() BoundedTaskExecutor.java:212
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) ThreadPoolExecutor.java:1142
java.util.concurrent.ThreadPoolExecutor$Worker.run() ThreadPoolExecutor.java:617
java.lang.Thread.run() Thread.java:745
thread 24 State: WAITING CPU usage on sample: 0ms
sun.misc.Unsafe.park(boolean, long) Unsafe.java (native)
java.util.concurrent.locks.LockSupport.parkNanos(Object, long) LockSupport.java:215
java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue$TransferStack$SNode, boolean, long) SynchronousQueue.java:460
java.util.concurrent.SynchronousQueue$TransferStack.transfer(Object, boolean, long) SynchronousQueue.java:362
java.util.concurrent.SynchronousQueue.poll(long, TimeUnit) SynchronousQueue.java:941
java.util.concurrent.ThreadPoolExecutor.getTask() ThreadPoolExecutor.java:1066
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) ThreadPoolExecutor.java:1127
java.util.concurrent.ThreadPoolExecutor$Worker.run() ThreadPoolExecutor.java:617
java.lang.Thread.run() Thread.java:745
thread 25 State: WAITING CPU usage on sample: 0ms
sun.misc.Unsafe.park(boolean, long) Unsafe.java (native)
java.util.concurrent.locks.LockSupport.parkNanos(Object, long) LockSupport.java:215
java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue$TransferStack$SNode, boolean, long) SynchronousQueue.java:460
java.util.concurrent.SynchronousQueue$TransferStack.transfer(Object, boolean, long) SynchronousQueue.java:362
java.util.concurrent.SynchronousQueue.poll(long, TimeUnit) SynchronousQueue.java:941
Swing-Shell [DAEMON] State: WAITING CPU usage on sample: 0ms
sun.misc.Unsafe.park(boolean, long) Unsafe.java (native)
java.util.concurrent.locks.LockSupport.park(Object) LockSupport.java:175
'''
def threads = ThreadDumpParser.parse(text)
assert threads.collect { it.name } == ['thread 23', 'thread 24', 'thread 25', 'Swing-Shell']
assert threads.collect { it.daemon } == [false, false, false, true]
}
void "test log is not a thread dump"() {
def threads = ThreadDumpParser.parse("""\
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
* A TestCase for single PsiFile being opened in Editor conversion. See configureXXX and checkResultXXX method docs.
*/
public abstract class LightCodeInsightTestCase extends LightPlatformCodeInsightTestCase {
private static final Pattern JDK_SELECT_PATTERN = Pattern.compile("Java([\\d.]+).java$");
private static final Pattern JDK_SELECT_PATTERN = Pattern.compile("Java([\\d.]+)(\\.java)?$");
public static JavaPsiFacadeEx getJavaFacade() {
return JavaPsiFacadeEx.getInstanceEx(ourProject);
@@ -1,6 +1,5 @@
package com.intellij.refactoring.typeMigration;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaPsiFacade;
@@ -15,8 +14,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class TypeConversionDescriptor extends TypeConversionDescriptorBase {
private static final Logger LOG = Logger.getInstance(TypeConversionDescriptor.class);
private String myStringToReplace = null;
private String myReplaceByString = "$";
private PsiExpression myExpression;
@@ -75,9 +72,15 @@ public class TypeConversionDescriptor extends TypeConversionDescriptorBase {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
if (getExpression() != null) expression = getExpression();
expression = adjustExpressionBeforeReplacement(expression);
return replaceExpression(expression, getStringToReplace(), getReplaceByString());
}
@NotNull
protected PsiExpression adjustExpressionBeforeReplacement(@NotNull PsiExpression expression) {
return expression;
}
@NotNull
public static PsiExpression replaceExpression(@NotNull PsiExpression expression,
String stringToReplace,
@@ -50,7 +50,7 @@ public class TypeMigrationVariableTypeFixProvider implements ChangeVariableTypeQ
@Nullable("is null when called from inspection") Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
runTypeMigrationOnVariable((PsiVariable)startElement, getReturnType(), editor, optimizeImports);
runTypeMigrationOnVariable((PsiVariable)startElement, getReturnType(), editor, optimizeImports, true);
}
@Override
@@ -63,14 +63,15 @@ public class TypeMigrationVariableTypeFixProvider implements ChangeVariableTypeQ
public static void runTypeMigrationOnVariable(@NotNull PsiVariable variable,
@NotNull PsiType targetType,
@Nullable("is null when called from inspection") Editor editor,
boolean optimizeImports) {
boolean optimizeImports,
boolean allowDependentRoots) {
Project project = variable.getProject();
if (!FileModificationService.getInstance().prepareFileForWrite(variable.getContainingFile())) return;
try {
WriteAction.run(() -> variable.normalizeDeclaration());
final TypeMigrationRules rules = new TypeMigrationRules();
rules.setBoundScope(GlobalSearchScope.projectScope(project));
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, variable, targetType, optimizeImports);
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, variable, targetType, optimizeImports, allowDependentRoots);
WriteAction.run(() -> JavaCodeStyleManager.getInstance(project).shortenClassReferences(variable));
UndoUtil.markPsiFileForUndo(variable.getContainingFile());
}
@@ -359,6 +359,7 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
rules,
elements.toArray(new PsiElement[elements.size()]),
createMigrationTypeFunction(elements, types),
true,
true);
}
@@ -41,7 +41,7 @@ public class ConvertAtomicToLongAdderIntention extends PsiElementBaseIntentionAc
if (variable != null) {
final PsiType longAdder =
JavaPsiFacade.getElementFactory(project).createTypeFromText(LongAdderConversionRule.JAVA_UTIL_CONCURRENT_ATOMIC_LONG_ADDER, element);
TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(variable, longAdder, null, false);
TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(variable, longAdder, null, false, false);
}
}
@@ -9,31 +9,21 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.AllowedApiFilterExtension;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
import com.intellij.refactoring.typeMigration.TypeEvaluator;
import com.intellij.refactoring.typeMigration.TypeMigrationReplacementUtil;
import com.intellij.refactoring.typeMigration.rules.AtomicConversionRule;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.typeMigration.TypeMigrationVariableTypeFixProvider;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.*;
import static com.intellij.psi.util.TypeConversionUtil.isBinaryOperatorApplicable;
import static com.intellij.util.ObjectUtils.assertNotNull;
/**
@@ -102,145 +92,118 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
final PsiVariable psiVariable = getVariable(element);
LOG.assertTrue(psiVariable != null);
final PsiVariable var = getVariable(element);
LOG.assertTrue(var != null);
final Query<PsiReference> refs = ReferencesSearch.search(psiVariable);
final PsiType fromType = var.getType();
PsiClassType toType = getMigrationTargetType(project, element, fromType);
if (toType == null) return;
final Set<PsiElement> elements = new HashSet<>();
elements.add(element);
for (PsiReference reference : refs) {
elements.add(reference.getElement());
if (!FileModificationService.getInstance().preparePsiElementsForWrite(var)) return;
addExplicitInitializer(var);
String toTypeCanonicalText = toType.getCanonicalText();
TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(var, toType, editor, false, false);
postProcessVariable(var, toTypeCanonicalText);
}
static void addExplicitInitializer(@NotNull PsiVariable var) {
PsiExpression currentInitializer = var.getInitializer();
if (currentInitializer != null) return;
final PsiType type = var.getType();
String initializerText = null;
if (PsiType.BOOLEAN.equals(type)) {
initializerText = "false";
}
if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) return;
else if (type instanceof PsiPrimitiveType) {
initializerText = "0";
}
if (initializerText != null) {
String finalInitializerText = initializerText;
WriteAction.run(() -> {
PsiExpression initializer = JavaPsiFacade.getElementFactory(var.getProject()).createExpressionFromText(finalInitializerText, var);
if (var instanceof PsiLocalVariable) {
((PsiLocalVariable)var).setInitializer(initializer);
}
else if (var instanceof PsiField) {
((PsiField)var).setInitializer(initializer);
}
});
}
}
WriteAction.run(() -> {
psiVariable.normalizeDeclaration();
static void postProcessVariable(@NotNull PsiVariable var, @NotNull String toType) {
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiType fromType = psiVariable.getType();
PsiClassType toType;
final String atomicQualifiedName = myFromToMap.get(fromType);
if (atomicQualifiedName != null) {
final PsiClass atomicClass = psiFacade.findClass(atomicQualifiedName, GlobalSearchScope.allScope(project));
if (atomicClass == null) {//show warning
return;
}
toType = factory.createType(atomicClass);
}
else if (fromType instanceof PsiArrayType) {
final PsiClass atomicReferenceArrayClass =
psiFacade.findClass(AtomicReferenceArray.class.getName(), GlobalSearchScope.allScope(project));
if (atomicReferenceArrayClass == null) {//show warning
return;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = atomicReferenceArrayClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType componentType = ((PsiArrayType)fromType).getComponentType();
if (componentType instanceof PsiPrimitiveType) componentType = ((PsiPrimitiveType)componentType).getBoxedType(element);
substitutor.put(typeParameters[0], componentType);
}
toType = factory.createType(atomicReferenceArrayClass, factory.createSubstitutor(substitutor));
}
else {
final PsiClass atomicReferenceClass = psiFacade.findClass(AtomicReference.class.getName(), GlobalSearchScope.allScope(project));
if (atomicReferenceClass == null) {//show warning
return;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = atomicReferenceClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType type = fromType;
if (type instanceof PsiPrimitiveType) type = ((PsiPrimitiveType)fromType).getBoxedType(element);
substitutor.put(typeParameters[0], type);
}
toType = factory.createType(atomicReferenceClass, factory.createSubstitutor(substitutor));
}
try {
for (PsiReference reference : refs) {
PsiElement refElement = reference.getElement();
PsiElement psiElement = refElement;
if (psiElement instanceof PsiExpression) {
final PsiElement parent = psiElement.getParent();
if (parent instanceof PsiExpression && !(parent instanceof PsiReferenceExpression || parent instanceof PsiPolyadicExpression)) {
psiElement = parent;
}
if (psiElement instanceof PsiBinaryExpression) {
PsiBinaryExpression binary = (PsiBinaryExpression)psiElement;
if (isBinaryOpApplicable(binary.getOperationTokenType(), binary.getLOperand(), binary.getROperand(), refElement, toType)) {
continue;
}
}
else if (psiElement instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignment = (PsiAssignmentExpression)psiElement;
final IElementType opSign = TypeConversionUtil.convertEQtoOperation(assignment.getOperationTokenType());
if (isBinaryOpApplicable(opSign, assignment.getLExpression(), assignment.getRExpression(), refElement, toType)) {
continue;
}
}
final TypeConversionDescriptor directConversion = AtomicConversionRule.findDirectConversion(psiElement, toType, fromType);
if (directConversion != null) {
TypeMigrationReplacementUtil
.replaceExpression((PsiExpression)psiElement, project, directConversion, new TypeEvaluator(null, null));
}
Project project = var.getProject();
if (var instanceof PsiField || CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS) {
PsiModifierList modifierList = assertNotNull(var.getModifierList());
WriteAction.run(() -> {
if (var.getInitializer() == null) {
final PsiExpression newInitializer = JavaPsiFacade.getElementFactory(project).createExpressionFromText("new " + toType + "()", var);
if (var instanceof PsiLocalVariable) {
((PsiLocalVariable)var).setInitializer(newInitializer);
}
else if (var instanceof PsiField) {
((PsiField)var).setInitializer(newInitializer);
}
JavaCodeStyleManager.getInstance(var.getProject()).shortenClassReferences(var.getInitializer());
}
PsiExpression initializer = psiVariable.getInitializer();
if (initializer != null) {
if (initializer instanceof PsiArrayInitializerExpression) {
PsiExpression normalizedExpr =
RefactoringUtil.createNewExpressionFromArrayInitializer((PsiArrayInitializerExpression)initializer, psiVariable.getType());
initializer = (PsiExpression)initializer.replace(normalizedExpr);
}
final TypeConversionDescriptor directConversion =
AtomicConversionRule.wrapWithNewExpression(toType, fromType, initializer, element);
if (directConversion != null) {
TypeMigrationReplacementUtil.replaceExpression(initializer, project, directConversion, new TypeEvaluator(null, null));
}
}
else if (!assertNotNull(psiVariable.getModifierList()).hasModifierProperty(PsiModifier.FINAL)) {
final PsiExpression newInitializer = factory.createExpressionFromText("new " + toType.getCanonicalText() + "()", psiVariable);
if (psiVariable instanceof PsiLocalVariable) {
((PsiLocalVariable)psiVariable).setInitializer(newInitializer);
}
else if (psiVariable instanceof PsiField) {
((PsiField)psiVariable).setInitializer(newInitializer);
}
JavaCodeStyleManager.getInstance(project).shortenClassReferences(psiVariable.getInitializer());
}
modifierList.setModifierProperty(PsiModifier.FINAL, true);
modifierList.setModifierProperty(PsiModifier.VOLATILE, false);
PsiElement replaced = assertNotNull(psiVariable.getTypeElement()).replace(factory.createTypeElement(toType));
JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced);
JavaCodeStyleManager.getInstance(project).shortenClassReferences(var);
CodeStyleManager.getInstance(project).reformat(var);
});
}
}
if (psiVariable instanceof PsiField || CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS) {
final PsiModifierList modifierList = assertNotNull(psiVariable.getModifierList());
modifierList.setModifierProperty(PsiModifier.FINAL, true);
modifierList.setModifierProperty(PsiModifier.VOLATILE, false);
}
@Nullable
private PsiClassType getMigrationTargetType(@NotNull Project project,
@NotNull PsiElement element,
@NotNull PsiType fromType) {
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
PsiElementFactory factory = psiFacade.getElementFactory();
final String atomicQualifiedName = myFromToMap.get(fromType);
if (atomicQualifiedName != null) {
final PsiClass atomicClass = psiFacade.findClass(atomicQualifiedName, GlobalSearchScope.allScope(project));
if (atomicClass == null) {//show warning
return null;
}
catch (IncorrectOperationException e) {
LOG.error(e);
return factory.createType(atomicClass);
}
else if (fromType instanceof PsiArrayType) {
final PsiClass atomicReferenceArrayClass =
psiFacade.findClass(AtomicReferenceArray.class.getName(), GlobalSearchScope.allScope(project));
if (atomicReferenceArrayClass == null) {//show warning
return null;
}
});
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = atomicReferenceArrayClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType componentType = ((PsiArrayType)fromType).getComponentType();
if (componentType instanceof PsiPrimitiveType) componentType = ((PsiPrimitiveType)componentType).getBoxedType(element);
substitutor.put(typeParameters[0], componentType);
}
return factory.createType(atomicReferenceArrayClass, factory.createSubstitutor(substitutor));
}
else {
final PsiClass atomicReferenceClass = psiFacade.findClass(AtomicReference.class.getName(), GlobalSearchScope.allScope(project));
if (atomicReferenceClass == null) {//show warning
return null;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = atomicReferenceClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType type = fromType;
if (type instanceof PsiPrimitiveType) type = ((PsiPrimitiveType)fromType).getBoxedType(element);
substitutor.put(typeParameters[0], type);
}
return factory.createType(atomicReferenceClass, factory.createSubstitutor(substitutor));
}
}
@Override
public boolean startInWriteAction() {
return false;
}
private static boolean isBinaryOpApplicable(@Nullable IElementType opSign,
@NotNull PsiExpression lExpr,
@Nullable PsiExpression rExpr,
@NotNull PsiElement varElement,
@NotNull PsiType migrationType) {
if (opSign == null || rExpr == null) return false;
PsiType lType = lExpr == varElement ? migrationType : lExpr.getType();
PsiType rType = rExpr == varElement ? migrationType : rExpr.getType();
return isBinaryOperatorApplicable(opSign, lType, rType, true);
}
}
@@ -4,32 +4,22 @@ import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.LowPriorityAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.AllowedApiFilterExtension;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.typeMigration.*;
import com.intellij.refactoring.typeMigration.rules.ThreadLocalConversionRule;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.typeMigration.TypeMigrationVariableTypeFixProvider;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.intellij.util.ObjectUtils.assertNotNull;
public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionAction implements LowPriorityAction {
private static final Logger LOG = Logger.getInstance(ConvertFieldToThreadLocalIntention.class);
@@ -66,101 +56,39 @@ public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionA
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
final PsiField psiField = PsiTreeUtil.getParentOfType(element, PsiField.class);
LOG.assertTrue(psiField != null);
final Query<PsiReference> refs = ReferencesSearch.search(psiField);
final Set<PsiElement> elements = new HashSet<>();
elements.add(element);
for (PsiReference reference : refs) {
elements.add(reference.getElement());
}
if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) return;
WriteAction.run(() -> {
psiField.normalizeDeclaration();
final PsiType fromType = psiField.getType();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiType fromType = psiField.getType();
final PsiClassType toType = getMigrationTargetType(fromType, project, element);
if (toType == null) return;
final PsiClass threadLocalClass = psiFacade.findClass(ThreadLocal.class.getName(), GlobalSearchScope.allScope(project));
if (threadLocalClass == null) {//show warning
return;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = threadLocalClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType type = fromType;
if (fromType instanceof PsiPrimitiveType) type = ((PsiPrimitiveType)fromType).getBoxedType(element);
substitutor.put(typeParameters[0], type);
}
final PsiClassType toType = factory.createType(threadLocalClass, factory.createSubstitutor(substitutor));
try {
final TypeMigrationRules rules = new TypeMigrationRules();
rules.setBoundScope(GlobalSearchScope.fileScope(element.getContainingFile()));
final TypeMigrationLabeler labeler = new TypeMigrationLabeler(rules, toType);
labeler.getMigratedUsages(false, psiField);
for (PsiReference reference : refs) {
PsiElement psiElement = reference.getElement();
if (psiElement instanceof PsiExpression) {
final PsiElement parent = psiElement.getParent();
if (parent instanceof PsiExpression && !(parent instanceof PsiReferenceExpression || parent instanceof PsiPolyadicExpression)) {
psiElement = parent;
}
final TypeConversionDescriptor conversion =
ThreadLocalConversionRule.findDirectConversion(psiElement, toType, fromType, labeler);
if (conversion != null) {
TypeMigrationReplacementUtil.replaceExpression((PsiExpression)psiElement, project, conversion, new TypeEvaluator(null, null));
}
}
}
PsiExpression initializer = psiField.getInitializer();
if (initializer == null &&
!psiField.hasModifierProperty(PsiModifier.FINAL)) {
final PsiType type = psiField.getType();
String initializerText = null;
if (PsiType.BOOLEAN.equals(type)) {
initializerText = "false";
}
else if (type instanceof PsiPrimitiveType) {
initializerText = "0";
}
if (initializerText != null) {
psiField.setInitializer(factory.createExpressionFromText(initializerText, psiField));
initializer = psiField.getInitializer();
}
}
if (initializer != null) {
if (initializer instanceof PsiArrayInitializerExpression) {
PsiExpression normalizedExpr =
RefactoringUtil.createNewExpressionFromArrayInitializer((PsiArrayInitializerExpression)initializer, psiField.getType());
initializer = (PsiExpression)initializer.replace(normalizedExpr);
}
final TypeConversionDescriptor conversion = ThreadLocalConversionRule.wrapWithNewExpression(toType, fromType, initializer);
TypeMigrationReplacementUtil.replaceExpression(initializer, project, conversion, new TypeEvaluator(null, null));
CodeStyleManager.getInstance(project).reformat(psiField);
}
else if (!assertNotNull(psiField.getModifierList()).hasModifierProperty(PsiModifier.FINAL)) {
final String text = "new " + PsiDiamondTypeUtil.getCollapsedType(toType, psiField) + "()";
final PsiExpression newInitializer = factory.createExpressionFromText(text, psiField);
psiField.setInitializer(newInitializer);
}
assertNotNull(psiField.getTypeElement()).replace(factory.createTypeElement(toType));
final PsiModifierList modifierList = assertNotNull(psiField.getModifierList());
modifierList.setModifierProperty(PsiModifier.FINAL, true);
modifierList.setModifierProperty(PsiModifier.VOLATILE, false);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
});
if (!FileModificationService.getInstance().preparePsiElementsForWrite(psiField)) return;
ConvertFieldToAtomicIntention.addExplicitInitializer(psiField);
String toTypeCanonicalText = toType.getCanonicalText();
TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(psiField, toType, editor, false, false);
ConvertFieldToAtomicIntention.postProcessVariable(psiField, toTypeCanonicalText);
}
@Override
public boolean startInWriteAction() {
return false;
}
@Nullable
private static PsiClassType getMigrationTargetType(@NotNull PsiType fromType, @NotNull Project project, @NotNull PsiElement context) {
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiClass threadLocalClass = psiFacade.findClass(ThreadLocal.class.getName(), GlobalSearchScope.allScope(project));
if (threadLocalClass == null) {//show warning
return null;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = threadLocalClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType type = fromType;
if (fromType instanceof PsiPrimitiveType) type = ((PsiPrimitiveType)fromType).getBoxedType(context);
substitutor.put(typeParameters[0], type);
}
PsiElementFactory factory = psiFacade.getElementFactory();
return factory.createType(threadLocalClass, factory.createSubstitutor(substitutor));
}
}
@@ -87,6 +87,9 @@ public class AtomicConversionRule extends TypeConversionRule {
final PsiClass toTypeClass = PsiUtil.resolveClassInType(to);
LOG.assertTrue(toTypeClass != null);
final String qualifiedName = toTypeClass.getQualifiedName();
if (context instanceof PsiParenthesizedExpression) {
context = ParenthesesUtils.stripParentheses((PsiExpression)context);
}
if (qualifiedName != null) {
if (qualifiedName.equals(AtomicInteger.class.getName()) || qualifiedName.equals(AtomicLong.class.getName())) {
@@ -271,12 +274,33 @@ public class AtomicConversionRule extends TypeConversionRule {
final PsiClassType boxedFromType = ((PsiPrimitiveType)from).getBoxedType(atomicClass);
LOG.assertTrue(boxedFromType != null);
if (!TypeConversionUtil.isAssignable(initial, boxedFromType)) {
return new TypeConversionDescriptor("$val$", "new " + typeText + "((" + unboxedInitialType.getCanonicalText() + ")$val$)", expression);
return new ArrayInitializerAwareConversionDescriptor("$val$", "new " + typeText + "((" + unboxedInitialType.getCanonicalText() + ")$val$)", expression);
}
}
}
}
return new TypeConversionDescriptor("$val$", "new " + typeText + "($val$)", expression);
return new ArrayInitializerAwareConversionDescriptor("$val$", "new " + typeText + "($val$)", expression);
}
static class ArrayInitializerAwareConversionDescriptor extends TypeConversionDescriptor {
public ArrayInitializerAwareConversionDescriptor(String stringToReplace,
String replaceByString,
PsiExpression expression) {
super(stringToReplace, replaceByString, expression);
}
@NotNull
@Override
protected PsiExpression adjustExpressionBeforeReplacement(@NotNull PsiExpression expression) {
if (expression instanceof PsiArrayInitializerExpression) {
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory();
return (PsiExpression)expression.replace(elementFactory.createExpressionFromText("new " +
TypeConversionUtil.erasure(expression.getType()).getCanonicalText() +
expression.getText(),
expression));
}
return expression;
}
}
@Nullable
@@ -286,6 +310,9 @@ public class AtomicConversionRule extends TypeConversionRule {
final PsiElement parent = context.getParent();
final PsiElement parentParent = parent.getParent();
if (context instanceof PsiReferenceExpression && isReferenceToLengthField((PsiReferenceExpression)context)) {
return new TypeConversionDescriptor("$qualifier$.length", "$qualifier$.length()");
}
if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
final IElementType operationSign = assignmentExpression.getOperationTokenType();
@@ -344,9 +371,6 @@ public class AtomicConversionRule extends TypeConversionRule {
if (context instanceof PsiArrayAccessExpression) {
return new TypeConversionDescriptor("$qualifier$[$idx$]", "$qualifier$.get($idx$)", (PsiExpression)context);
}
if (parent instanceof PsiReferenceExpression && isReferenceToLengthField((PsiReferenceExpression)parent)) {
return new TypeConversionDescriptor("$qualifier$.length", "$qualifier$.length()", (PsiExpression)parent);
}
return null;
}
@@ -91,6 +91,10 @@ public class ThreadLocalConversionRule extends TypeConversionRule {
return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", toPrimitive("$qualifier$.get()", from, context) + " " + sign + " $val$");
}
if (parent instanceof PsiVariable && ((PsiVariable)parent).getInitializer() == context) {
return wrapWithNewExpression(to, from, (PsiExpression)context);
}
if (parent instanceof PsiExpressionStatement) {
if (context instanceof PsiPostfixExpression) {
final PsiPostfixExpression postfixExpression = (PsiPostfixExpression)context;
@@ -169,12 +173,12 @@ public class ThreadLocalConversionRule extends TypeConversionRule {
PsiExpression initializer,
String boxedTypeName) {
if (PsiUtil.isLanguageLevel8OrHigher(initializer)) {
return "java.lang.ThreadLocal.withInitial(() -> " + initializer.getText() + ")";
return "java.lang.ThreadLocal.withInitial(() -> $qualifier$)";
}
return "new " +
to.getCanonicalText() +
"() {\n" +
"@Override \n" +
"@Override\n" +
"protected " +
boxedTypeName +
" initialValue() {\n" +
@@ -183,9 +187,7 @@ public class ThreadLocalConversionRule extends TypeConversionRule {
? initializer.getText()
: (from instanceof PsiPrimitiveType ? "new " +
((PsiPrimitiveType)from).getBoxedTypeName() +
"(" +
initializer.getText() +
")" : initializer.getText())) +
"($qualifier$)" : "$qualifier$")) +
";\n" +
"}\n" +
"}";
@@ -242,7 +244,7 @@ public class ThreadLocalConversionRule extends TypeConversionRule {
return toBoxed(arg, from, context);
}
private static class WrappingWithInnerClassOrLambdaDescriptor extends TypeConversionDescriptor {
private static class WrappingWithInnerClassOrLambdaDescriptor extends AtomicConversionRule.ArrayInitializerAwareConversionDescriptor {
private final List<PsiVariable> myVariablesToMakeFinal;
private WrappingWithInnerClassOrLambdaDescriptor(@NonNls final String stringToReplace,
@@ -1,6 +1,7 @@
package com.intellij.codeInsight;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.refactoring.typeMigration.TypeMigrationProcessor;
import com.intellij.testFramework.PlatformTestUtil;
import org.jetbrains.annotations.NotNull;
@@ -24,6 +25,18 @@ public class ConvertToAtomicIntentionTest extends LightQuickFixParameterizedTest
return PlatformTestUtil.getCommunityPath() + "/java/typeMigration/testData";
}
@Override
public void setUp() throws Exception {
super.setUp();
TypeMigrationProcessor.ourSkipFailedConversionInTestMode = true;
}
@Override
public void tearDown() throws Exception {
TypeMigrationProcessor.ourSkipFailedConversionInTestMode = false;
super.tearDown();
}
public void test() throws Exception {
doAllTests();
}
@@ -52,7 +52,8 @@ public class ChangeTypeSignatureTest extends LightCodeInsightTestCase {
new TypeMigrationProcessor(getProject(),
new PsiElement[]{parameterList},
Functions.constant(PsiSubstitutor.EMPTY.put(superClass.getTypeParameters()[0], migrationType).substitute(new PsiImmediateClassType(superClass, PsiSubstitutor.EMPTY))),
rules).run();
rules,
true).run();
if (success) {
checkResultByFile(dataPath + getTestName(false) + ".java.after");
} else {
@@ -229,7 +229,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase {
private static class TestTypeMigrationProcessor extends TypeMigrationProcessor {
public TestTypeMigrationProcessor(final Project project, final PsiElement[] roots, final PsiType migrationType, final TypeMigrationRules rules) {
super(project, roots, Functions.constant(migrationType), rules);
super(project, roots, Functions.constant(migrationType), rules, true);
}
}
}
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicIntegerArray;
// "Convert to atomic" "true"
class Test {
final AtomicIntegerArray field= new AtomicIntegerArray(foo());
final AtomicIntegerArray field = new AtomicIntegerArray(foo());
int[] foo() {
return null;
}
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger o = new AtomicInteger(0);
final AtomicInteger o = new AtomicInteger(0);
void foo() {
boolean b = this.o.get() == 1;
@@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger i = new AtomicInteger(0);
final AtomicInteger i = new AtomicInteger(0);
}
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicLong;
// "Convert to atomic" "true"
class T {
private final AtomicLong l = new AtomicLong(10L);
private final AtomicLong l = new AtomicLong(10L);
public synchronized void update(long m) {
l.set(m);
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
// "Convert to atomic" "true"
class Test {
final AtomicReferenceArray<Object> field= new AtomicReferenceArray<>(foo());
final AtomicReferenceArray<Object> field = new AtomicReferenceArray<>(foo());
Object[] foo() {
return null;
}
@@ -2,6 +2,6 @@ import java.util.concurrent.atomic.AtomicIntegerArray;
// "Convert to atomic" "true"
class Test {
final AtomicIntegerArray field= new AtomicIntegerArray(new int[]{1});
final AtomicIntegerArray field = new AtomicIntegerArray(new int[]{1});
}
@@ -2,8 +2,8 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger i = new AtomicInteger(0);
final AtomicInteger i = new AtomicInteger(0);
int j = i.get() + 5;
String s = "i = " + i.get();
String s = "i = " + i;
}
@@ -2,8 +2,8 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger i = new AtomicInteger(0 + 8);
final AtomicInteger i = new AtomicInteger(0 + 8);
int j = i.get() + 5;
String s = "i = " + i.get();
String s = "i = " + i;
}
@@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicIntegerArray;
// "Convert to atomic" "true"
class Test {
final AtomicIntegerArray i = new AtomicIntegerArray(new int[0]);
final AtomicIntegerArray i = new AtomicIntegerArray(new int[0]);
}
@@ -2,10 +2,10 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger o = new AtomicInteger(0);
final AtomicInteger o = new AtomicInteger(0);
int j = o.get();
void foo() {
while ((o = j) != 0) {}
while ((o.set(j)) != 0) {}
}
}
@@ -2,10 +2,10 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger o = new AtomicInteger();
final AtomicInteger o = new AtomicInteger(0);
int j = o.get();
void foo() {
while ((o = j) != 0) {}
while ((o.set(j)) != 0) {}
}
}
@@ -2,14 +2,14 @@ import java.util.concurrent.atomic.AtomicInteger;
// "Convert to atomic" "true"
class Test {
final AtomicInteger o;
final AtomicInteger o = new AtomicInteger(0);
int j = o.get();
Test(int o) {
this.o = new AtomicInteger(o);
this.o.set(o);
}
void foo() {
while ((o = j) != 0) {}
while ((o.set(j)) != 0) {}
}
}
@@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
// "Convert to atomic" "true"
class Test {
final AtomicReferenceArray<String> field= new AtomicReferenceArray<>(new String[]{});
final AtomicReferenceArray<String> field = new AtomicReferenceArray<>(new String[]{});
}
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicLong;
// "Convert to atomic" "true"
class A {
final AtomicLong x = new AtomicLong(0);
final AtomicLong x = new AtomicLong(0);
public void testAtomicLong() {
x.getAndIncrement();
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicIntegerArray;
// "Convert to atomic" "true"
class Test {
final AtomicIntegerArray ii = new AtomicIntegerArray(new int[12]);
final AtomicIntegerArray ii = new AtomicIntegerArray(new int[12]);
void m() {
int k = ii.length();
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
// "Convert to atomic" "true"
class Test {
final AtomicBoolean field= new AtomicBoolean(false);
final AtomicBoolean field = new AtomicBoolean(false);
{
boolean b = !field.get();
}
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicReference;
// "Convert to atomic" "true"
class X {
private final AtomicReference<String> s = new AtomicReference<>("");
private final AtomicReference<String> s = new AtomicReference<>("");
private String t;
private String u;
}
@@ -1,7 +1,7 @@
// "Convert to ThreadLocal" "true"
class Test {
static final ThreadLocal<Integer> field;
static final ThreadLocal<Integer> field = new ThreadLocal<Integer>();
static {
field = ThreadLocal.withInitial(() -> new Integer(0));
field.set(new Integer(0));
}
}
@@ -0,0 +1,8 @@
// "Convert to ThreadLocal" "true"
import java.util.Arrays;
class Foo {
private final ThreadLocal<char[]> lookahead = ThreadLocal.withInitial(() -> new char[0]);
{ lookahead.set(Arrays.copyOf(lookahead.get(), 42));}
}
@@ -1,12 +1,11 @@
// "Convert to ThreadLocal" "true"
class Main {
private final ThreadLocal<Boolean> property;
private final ThreadLocal<Boolean> property = ThreadLocal.withInitial(() -> false);
Main3(boolean property) {
if (property) {
property = false;
}
boolean finalProperty = property;
this.property = ThreadLocal.withInitial(() -> finalProperty);
this.property.set(property);
}
}
@@ -1,8 +1,8 @@
// "Convert to ThreadLocal" "true"
class Foo {
private final ThreadLocal<Boolean> property;
private final ThreadLocal<Boolean> property = ThreadLocal.withInitial(() -> false);
Foo(boolean property) {
this.property = ThreadLocal.withInitial(() -> property);
this.property.set(property);
}
}
@@ -0,0 +1,8 @@
// "Convert to ThreadLocal" "true"
import java.util.Arrays;
class Foo {
private char[] loo<caret>kahead = new char[0];
{ lookahead = Arrays.copyOf(lookahead, 42);}
}
@@ -1,13 +1,13 @@
// "Convert to ThreadLocal" "true"
class Main {
private final ThreadLocal<Boolean> property;
Main3(final boolean property) {
this.property = new ThreadLocal<Boolean>() {
private final ThreadLocal<Boolean> property = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return property;
return false;
}
};
Main3(boolean property) {
this.property.set(property);
}
}
@@ -6,6 +6,7 @@ PsiReferenceExpression:s : java.util.concurrent.atomic.AtomicReference<java.lang
Conversions:
"" -> new java.util.concurrent.atomic.AtomicReference<java.lang.String>($val$) $val$
s -> $qualifier$.get() $qualifier$ s
s -> $qualifier$.get() $qualifier$ s
New expression type changes:
Fails:
@@ -4,7 +4,7 @@ class Test {
AtomicReference<String> s = new AtomicReference<String>("");
void foo() {
if (s == null) {
if (s.get() == null) {
System.out.println(s.get());
}
}
@@ -4,8 +4,14 @@ PsiReferenceExpression:myS : java.lang.ThreadLocal<java.lang.String>
PsiReferenceExpression:myS : java.lang.ThreadLocal<java.lang.String>
Conversions:
"" -> new java.lang.ThreadLocal<java.lang.String>() {
@Override
protected java.lang.String initialValue() {
return "";
}
} $qualifier$ ""
myS -> $qualifier$.get() $qualifier$ myS
myS -> $qualifier$.get() $qualifier$ myS
New expression type changes:
Fails:
""->java.lang.ThreadLocal<java.lang.String>
@@ -1,8 +1,13 @@
class Test {
ThreadLocal<String> myS = "";
ThreadLocal<String> myS = new ThreadLocal<String>() {
@Override
protected String initialValue() {
return "";
}
};
void foo() {
if (myS == null) {
if (myS.get() == null) {
System.out.println(myS.get());
}
}
@@ -40,8 +40,7 @@ public class QuickFixWrapper implements IntentionAction {
private static final Logger LOG = Logger.getInstance("com.intellij.codeInspection.ex.QuickFixWrapper");
private final ProblemDescriptor myDescriptor;
private final int myFixNumber;
private final LocalQuickFix myFix;
@NotNull
public static IntentionAction wrap(@NotNull ProblemDescriptor descriptor, int fixNumber) {
@@ -50,12 +49,12 @@ public class QuickFixWrapper implements IntentionAction {
LOG.assertTrue(fixes != null && fixes.length > fixNumber);
final QuickFix fix = fixes[fixNumber];
return fix instanceof IntentionAction ? (IntentionAction)fix : new QuickFixWrapper(descriptor, fixNumber);
return fix instanceof IntentionAction ? (IntentionAction)fix : new QuickFixWrapper(descriptor, (LocalQuickFix)fix);
}
private QuickFixWrapper(@NotNull ProblemDescriptor descriptor, int fixNumber) {
private QuickFixWrapper(@NotNull ProblemDescriptor descriptor, @NotNull LocalQuickFix fix) {
myDescriptor = descriptor;
myFixNumber = fixNumber;
myFix = fix;
}
@Override
@@ -67,7 +66,7 @@ public class QuickFixWrapper implements IntentionAction {
@Override
@NotNull
public String getFamilyName() {
return myDescriptor.getFixes()[myFixNumber].getName();
return getFix().getName();
}
@Override
@@ -104,8 +103,9 @@ public class QuickFixWrapper implements IntentionAction {
return getFix().getElementToMakeWritable(file);
}
@NotNull
public LocalQuickFix getFix() {
return (LocalQuickFix)myDescriptor.getFixes()[myFixNumber];
return myFix;
}
@TestOnly
@@ -30,7 +30,7 @@ public interface BaseComponent extends NamedComponent {
}
/**
* @see {@link com.intellij.openapi.Disposable}
* @see com.intellij.openapi.Disposable
*/
default void disposeComponent() {
}
@@ -37,10 +37,6 @@ public class SimpleModificationTracker implements ModificationTracker {
}
public void incModificationCount() {
incAndGetModificationCount();
}
public long incAndGetModificationCount() {
return UPDATER.incrementAndGet(this);
UPDATER.incrementAndGet(this);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -86,7 +86,7 @@ public class ID<K, V> extends IndexId<K,V> {
myUniqueId = stringToId(name);
final ID old = ourRegistry.put(myUniqueId, this);
assert old == null;
assert old == null : "ID with name '" + name + "' is already registered";
}
private static short stringToId(String name) {
@@ -18,7 +18,6 @@ package com.intellij.psi.impl.source.resolve;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
@@ -143,6 +142,12 @@ public class ResolveCache {
if (result instanceof ResolveResult) {
ensureValidPsi((ResolveResult)result);
}
else if (result instanceof ResolveResult[]) {
ensureValidResults((ResolveResult[])result);
}
else if (result instanceof PsiElement) {
PsiUtilCore.ensureValid((PsiElement)result);
}
if (stamp.mayCacheNow()) {
cache(ref, map, result);
@@ -187,9 +192,7 @@ public class ResolveCache {
result = needToPreventRecursion ? myGuard.doPreventingRecursion(Pair.create(ref, incompleteCode), true,
() -> resolver.resolve(ref, containingFile, incompleteCode)) : resolver.resolve(ref, containingFile, incompleteCode);
if (result != null) {
for (ResolveResult resolveResult : result) {
ensureValidPsi(resolveResult);
}
ensureValidResults(result);
}
if (stamp.mayCacheNow()) {
@@ -198,6 +201,12 @@ public class ResolveCache {
return result == null ? ResolveResult.EMPTY_ARRAY : result;
}
private static void ensureValidResults(ResolveResult[] result) {
for (ResolveResult resolveResult : result) {
ensureValidPsi(resolveResult);
}
}
private static void ensureValidPsi(ResolveResult resolveResult) {
PsiElement element = resolveResult.getElement();
if (element != null) {
@@ -30,7 +30,6 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.util.ArrayUtil.toObjectArray;
@@ -165,13 +164,28 @@ public class SetEditorSettingsAction extends ActionGroup implements DumbAware {
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
List<AnAction> result = new ArrayList<>();
ContainerUtil.addAll(result, myActions);
result.add(Separator.getInstance());
result.add(ActionManager.getInstance().getAction(IdeActions.GROUP_DIFF_EDITOR_GUTTER_POPUP));
AnAction[] children = ((ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_DIFF_EDITOR_GUTTER_POPUP)).getChildren(e);
AnAction editorSettingsGroup = ActionManager.getInstance().getAction("Diff.EditorGutterPopupMenu.EditorSettings");
DefaultActionGroup ourGroup = new DefaultActionGroup();
ourGroup.add(Separator.getInstance());
ourGroup.addAll(myActions);
ourGroup.add(editorSettingsGroup);
ourGroup.add(Separator.getInstance());
List<AnAction> result = ContainerUtil.newArrayList(children);
replaceOrAppend(result, editorSettingsGroup, ourGroup);
return toObjectArray(result, AnAction.class);
}
private static <T> void replaceOrAppend(List<T> list, T from, T to) {
int index = list.indexOf(from);
if (index == -1) index = list.size();
list.remove(from);
list.add(index, to);
}
private abstract class EditorSettingToggleAction extends ToggleAction implements DumbAware, EditorSettingAction {
private EditorSettingToggleAction(@NotNull String actionId) {
ActionUtil.copyFrom(this, actionId);
@@ -140,6 +140,11 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
processOnSizeChanged();
}
}
@Override
public void componentHidden(ComponentEvent e) {
popupWindow.removeComponentListener(this);
}
});
if (dimensionKey != null) {
addPopupListener(new JBPopupAdapter() {

Some files were not shown because too many files have changed in this diff Show More