mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
Generated
+1
-1
@@ -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" />
|
||||
|
||||
@@ -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,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;
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -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
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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() : "";
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -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 + "]";
|
||||
}
|
||||
}
|
||||
+9
-10
@@ -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;
|
||||
}
|
||||
|
||||
+5
-1
@@ -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
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+19
-9
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -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) {
|
||||
|
||||
+3
@@ -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));
|
||||
|
||||
+23
-8
@@ -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 =
|
||||
|
||||
+8
-7
@@ -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();
|
||||
|
||||
+14
-4
@@ -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) {
|
||||
|
||||
+36
-22
@@ -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";
|
||||
|
||||
+16
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+29
@@ -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;
|
||||
}
|
||||
}
|
||||
+31
@@ -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;
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
int i;
|
||||
String s;
|
||||
int[] a1;
|
||||
int[] a2;
|
||||
<caret>
|
||||
}
|
||||
+13
@@ -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
-1
@@ -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 {
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class Test {
|
||||
{
|
||||
int x = 0, y;
|
||||
<selection>y = ++x;</selection>
|
||||
System.out.println("x = " + x);
|
||||
System.out.println("y = " + y);
|
||||
}
|
||||
}
|
||||
+23
@@ -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;
|
||||
}
|
||||
}
|
||||
+24
@@ -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);
|
||||
|
||||
+4
-4
@@ -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) {
|
||||
|
||||
+33
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+13
-1
@@ -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();
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -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();
|
||||
|
||||
+1
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
+4
@@ -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);
|
||||
|
||||
+6
-3
@@ -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,
|
||||
|
||||
+4
-3
@@ -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());
|
||||
}
|
||||
|
||||
+1
@@ -359,6 +359,7 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
rules,
|
||||
elements.toArray(new PsiElement[elements.size()]),
|
||||
createMigrationTypeFunction(elements, types),
|
||||
true,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+98
-135
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-100
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+29
-5
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -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));}
|
||||
}
|
||||
+2
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
@@ -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:
|
||||
|
||||
+1
-1
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -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>
|
||||
|
||||
+7
-2
@@ -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
Reference in New Issue
Block a user