mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch origin/master
This commit is contained in:
@@ -136,7 +136,7 @@ public class JavaParametersUtil {
|
||||
}
|
||||
final boolean isJdk = JavaSdk.checkForJdk(new File(jreHome));
|
||||
if (isJdk) {
|
||||
throw new CantRunException("Jre expected but jdk found");
|
||||
throw new CantRunException("Alternative JRE path needs to point to a JRE, not to a complete JDK installation");
|
||||
}
|
||||
final Sdk jdk = JavaSdk.getInstance().createJdk("", jreHome);
|
||||
if (jdk == null) throw CantRunException.noJdkConfigured();
|
||||
|
||||
+28
-22
@@ -48,22 +48,22 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreInference(listOwner, annotationFQN)) {
|
||||
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN);
|
||||
if (fromBytecode != null) {
|
||||
return fromBytecode;
|
||||
}
|
||||
if (ignoreInference(listOwner, annotationFQN)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN);
|
||||
if (fromBytecode != null) {
|
||||
return fromBytecode;
|
||||
}
|
||||
|
||||
if (canInferFromSource(listOwner)) {
|
||||
//noinspection ConstantConditions
|
||||
PsiMethod method = (PsiMethod)listOwner;
|
||||
if (listOwner instanceof PsiMethod) {
|
||||
if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN)) {
|
||||
return getInferredContractAnnotation(method);
|
||||
return getInferredContractAnnotation((PsiMethod)listOwner);
|
||||
}
|
||||
|
||||
|
||||
if ((AnnotationUtil.NOT_NULL.equals(annotationFQN) || AnnotationUtil.NULLABLE.equals(annotationFQN))) {
|
||||
PsiAnnotation anno = getInferredNullityAnnotation(method);
|
||||
PsiAnnotation anno = getInferredNullityAnnotation((PsiMethod)listOwner);
|
||||
return anno == null ? null : annotationFQN.equals(anno.getQualifiedName()) ? anno : null;
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,9 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
|
||||
|
||||
@Override
|
||||
public boolean ignoreInference(@NotNull PsiModifierListOwner owner, @Nullable String annotationFQN) {
|
||||
if (owner instanceof PsiMethod && PsiUtil.canBeOverriden((PsiMethod)owner)) {
|
||||
return true;
|
||||
}
|
||||
if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN) && hasHardcodedContracts(owner)) {
|
||||
return true;
|
||||
}
|
||||
@@ -138,10 +141,6 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
|
||||
return ProjectBytecodeAnalysis.getInstance(myProject).createContractAnnotation(attrs);
|
||||
}
|
||||
|
||||
private static boolean canInferFromSource(PsiModifierListOwner listOwner) {
|
||||
return listOwner instanceof PsiMethod && !PsiUtil.canBeOverriden((PsiMethod)listOwner);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) {
|
||||
@@ -150,17 +149,24 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
|
||||
PsiAnnotation[] fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotations(listOwner);
|
||||
for (PsiAnnotation annotation : fromBytecode) {
|
||||
if (!ignoreInference(listOwner, annotation.getQualifiedName())) {
|
||||
if (!ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotation.getQualifiedName()) || canInferFromSource(listOwner)) {
|
||||
result.add(annotation);
|
||||
}
|
||||
result.add(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (canInferFromSource(listOwner)) {
|
||||
if (listOwner instanceof PsiMethod) {
|
||||
PsiAnnotation hardcoded = getHardcodedContractAnnotation((PsiMethod)listOwner);
|
||||
ContainerUtil.addIfNotNull(result, hardcoded != null ? hardcoded : getInferredContractAnnotation((PsiMethod)listOwner));
|
||||
|
||||
ContainerUtil.addIfNotNull(result, getInferredNullityAnnotation((PsiMethod)listOwner));
|
||||
if (hardcoded != null) {
|
||||
result.add(hardcoded);
|
||||
} else if (!ignoreInference(listOwner, ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) {
|
||||
ContainerUtil.addIfNotNull(result, getInferredContractAnnotation((PsiMethod)listOwner));
|
||||
}
|
||||
|
||||
if (!ignoreInference(listOwner, AnnotationUtil.NOT_NULL) || !ignoreInference(listOwner, AnnotationUtil.NULLABLE)) {
|
||||
PsiAnnotation annotation = getInferredNullityAnnotation((PsiMethod)listOwner);
|
||||
if (annotation != null && !ignoreInference(listOwner, annotation.getQualifiedName())) {
|
||||
result.add(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : result.toArray(new PsiAnnotation[result.size()]);
|
||||
|
||||
+21
-4
@@ -89,8 +89,12 @@ class ContractInferenceInterpreter {
|
||||
|
||||
PsiTypeElement typeElement = myMethod.getReturnTypeElement();
|
||||
final PsiType returnType = typeElement == null ? null : typeElement.getType();
|
||||
final boolean notNull = !(returnType instanceof PsiPrimitiveType) &&
|
||||
boolean referenceTypeReturned = !(returnType instanceof PsiPrimitiveType);
|
||||
final boolean notNull = referenceTypeReturned &&
|
||||
NullableNotNullManager.getInstance(myMethod.getProject()).isNotNull(myMethod, false);
|
||||
if (referenceTypeReturned) {
|
||||
contracts = boxReturnValues(contracts);
|
||||
}
|
||||
return ContainerUtil.filter(contracts, new Condition<MethodContract>() {
|
||||
@Override
|
||||
public boolean value(MethodContract contract) {
|
||||
@@ -101,7 +105,20 @@ class ContractInferenceInterpreter {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static List<MethodContract> boxReturnValues(List<MethodContract> contracts) {
|
||||
return ContainerUtil.mapNotNull(contracts, new Function<MethodContract, MethodContract>() {
|
||||
@Override
|
||||
public MethodContract fun(MethodContract contract) {
|
||||
if (contract.returnValue == FALSE_VALUE || contract.returnValue == TRUE_VALUE) {
|
||||
return new MethodContract(contract.arguments, NOT_NULL_VALUE);
|
||||
}
|
||||
return contract;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<MethodContract> doInferContracts() {
|
||||
PsiCodeBlock body = myMethod.getBody();
|
||||
PsiStatement[] statements = body == null ? PsiStatement.EMPTY_ARRAY : body.getStatements();
|
||||
@@ -294,7 +311,7 @@ class ContractInferenceInterpreter {
|
||||
parameter = resolveParameter(op2);
|
||||
constraint = getLiteralConstraint(op1);
|
||||
}
|
||||
if (parameter >= 0 && constraint != null) {
|
||||
if (parameter >= 0 && constraint != null && constraint != NOT_NULL_VALUE) {
|
||||
List<MethodContract> result = ContainerUtil.newArrayList();
|
||||
for (ValueConstraint[] state : states) {
|
||||
ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, constraint, equality ? TRUE_VALUE : FALSE_VALUE));
|
||||
@@ -410,7 +427,7 @@ class ContractInferenceInterpreter {
|
||||
if (expr.textMatches(PsiKeyword.TRUE)) return TRUE_VALUE;
|
||||
if (expr.textMatches(PsiKeyword.FALSE)) return FALSE_VALUE;
|
||||
if (expr.textMatches(PsiKeyword.NULL)) return NULL_VALUE;
|
||||
if (((PsiLiteralExpression)expr).getValue() instanceof String) return NOT_NULL_VALUE;
|
||||
return NOT_NULL_VALUE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
-4
@@ -1490,10 +1490,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
final PsiAnnotation contractAnno = findContractAnnotation(method);
|
||||
final int paramCount = method.getParameterList().getParametersCount();
|
||||
if (contractAnno != null) {
|
||||
if (AnnotationUtil.isInferredAnnotation(contractAnno) && PsiUtil.canBeOverriden(method)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return CachedValuesManager.getCachedValue(contractAnno, new CachedValueProvider<List<MethodContract>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
|
||||
+4
@@ -536,6 +536,10 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
}
|
||||
|
||||
private static boolean isCompileConstantInIfCondition(PsiElement element) {
|
||||
if (element instanceof PsiPrefixExpression && ((PsiPrefixExpression)element).getOperationTokenType() == JavaTokenType.EXCL) {
|
||||
return isCompileConstantInIfCondition(((PsiPrefixExpression)element).getOperand());
|
||||
}
|
||||
|
||||
if (!(element instanceof PsiReferenceExpression)) return false;
|
||||
PsiElement resolved = ((PsiReferenceExpression)element).resolve();
|
||||
if (!(resolved instanceof PsiField)) return false;
|
||||
|
||||
+1
-4
@@ -253,10 +253,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
if (value instanceof DfaVariableValue) {
|
||||
setVariableState(var, getVariableState((DfaVariableValue)value));
|
||||
}
|
||||
else if (value instanceof DfaBoxedValue) {
|
||||
setVariableState(var, getVariableState(var).withNullable(false));
|
||||
applyCondition(compareToNull(var, true));
|
||||
}
|
||||
}
|
||||
|
||||
if (getVariableState(var).isNotNull()) {
|
||||
@@ -477,6 +473,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
@Override
|
||||
public boolean isNotNull(DfaValue dfaVar) {
|
||||
if (dfaVar instanceof DfaConstValue) return ((DfaConstValue)dfaVar).getValue() != null;
|
||||
if (dfaVar instanceof DfaBoxedValue) return true;
|
||||
if (dfaVar instanceof DfaTypeValue) return ((DfaTypeValue)dfaVar).isNotNull();
|
||||
if (dfaVar instanceof DfaVariableValue) {
|
||||
if (getVariableState((DfaVariableValue)dfaVar).isNotNull()) return true;
|
||||
|
||||
+25
-17
@@ -26,7 +26,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@@ -68,25 +68,34 @@ public class NullityInference {
|
||||
final AtomicBoolean hasNotNulls = new AtomicBoolean();
|
||||
final AtomicBoolean hasNulls = new AtomicBoolean();
|
||||
final AtomicBoolean hasUnknowns = new AtomicBoolean();
|
||||
final List<PsiMethodCallExpression> calls = ContainerUtil.newArrayList();
|
||||
final Set<PsiMethod> delegates = ContainerUtil.newLinkedHashSet();
|
||||
body.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitReturnStatement(PsiReturnStatement statement) {
|
||||
PsiExpression value = statement.getReturnValue();
|
||||
if (value == null) {
|
||||
hasErrors.set(true);
|
||||
} else {
|
||||
if (value instanceof PsiLiteralExpression) {
|
||||
if (value.textMatches(PsiKeyword.NULL)) {
|
||||
hasNulls.set(true);
|
||||
} else {
|
||||
hasNotNulls.set(true);
|
||||
}
|
||||
} else if (value instanceof PsiMethodCallExpression) {
|
||||
calls.add((PsiMethodCallExpression)value);
|
||||
} else {
|
||||
hasUnknowns.set(true);
|
||||
} else if (value instanceof PsiLiteralExpression) {
|
||||
if (value.textMatches(PsiKeyword.NULL)) {
|
||||
hasNulls.set(true);
|
||||
}
|
||||
else {
|
||||
hasNotNulls.set(true);
|
||||
}
|
||||
}
|
||||
else if (value.getType() instanceof PsiPrimitiveType) {
|
||||
hasNotNulls.set(true);
|
||||
}
|
||||
else if (value instanceof PsiMethodCallExpression) {
|
||||
PsiMethod target = ((PsiMethodCallExpression)value).resolveMethod();
|
||||
if (target == null) {
|
||||
hasUnknowns.set(true);
|
||||
} else {
|
||||
delegates.add(target);
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasUnknowns.set(true);
|
||||
}
|
||||
super.visitReturnStatement(statement);
|
||||
}
|
||||
@@ -102,13 +111,12 @@ public class NullityInference {
|
||||
return Nullness.NULLABLE;
|
||||
}
|
||||
|
||||
if (calls.size() > 1) {
|
||||
if (hasErrors.get() || delegates.size() > 1) {
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
if (calls.size() == 1) {
|
||||
PsiMethod target = calls.get(0).resolveMethod();
|
||||
if (target != null && NullableNotNullManager.isNotNull(target)) {
|
||||
if (delegates.size() == 1) {
|
||||
if (NullableNotNullManager.isNotNull(delegates.iterator().next())) {
|
||||
return Nullness.NOT_NULL;
|
||||
}
|
||||
return Nullness.UNKNOWN;
|
||||
|
||||
@@ -880,11 +880,17 @@ public class ExpectedTypesProvider {
|
||||
if (statement.getException() == myExpr) {
|
||||
PsiManager manager = statement.getManager();
|
||||
PsiType throwableType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Throwable", myExpr.getResolveScope());
|
||||
PsiMember container = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiClass.class);
|
||||
PsiElement container = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiLambdaExpression.class, PsiClass.class);
|
||||
PsiType[] throwsTypes = PsiType.EMPTY_ARRAY;
|
||||
if (container instanceof PsiMethod) {
|
||||
throwsTypes = ((PsiMethod)container).getThrowsList().getReferencedTypes();
|
||||
}
|
||||
else if (container instanceof PsiLambdaExpression) {
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(container);
|
||||
if (method != null) {
|
||||
throwsTypes = method.getThrowsList().getReferencedTypes();
|
||||
}
|
||||
}
|
||||
|
||||
if (throwsTypes.length == 0) {
|
||||
final PsiClassType exceptionType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Exception", myExpr.getResolveScope());
|
||||
|
||||
@@ -106,8 +106,8 @@ public class ControlFlowWrapper {
|
||||
}
|
||||
|
||||
if (myExitPoints.size() != 1) {
|
||||
areExitStatementsTheSame();
|
||||
myGenerateConditionalExit = true;
|
||||
areExitStatementsTheSame();
|
||||
}
|
||||
return myExitStatements;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.ui.*;
|
||||
import com.intellij.refactoring.util.ConflictsUtil;
|
||||
@@ -241,6 +242,9 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
|
||||
|
||||
@Nullable
|
||||
private JPanel createReturnTypePanel() {
|
||||
if (TypeConversionUtil.isPrimitiveWrapper(myReturnType) && myNullness == Nullness.NULLABLE) {
|
||||
return null;
|
||||
}
|
||||
mySelector = new TypeSelectorManagerImpl(myProject, myReturnType, findOccurrences(), areTypesDirected()).getTypeSelector();
|
||||
final JComponent component = mySelector.getComponent();
|
||||
if (component instanceof JComboBox) {
|
||||
@@ -532,7 +536,7 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
|
||||
buffer.append(myTargetClass.getName());
|
||||
}
|
||||
else {
|
||||
buffer.append(PsiFormatUtil.formatType(mySelector.getSelectedType(), 0, PsiSubstitutor.EMPTY));
|
||||
buffer.append(PsiFormatUtil.formatType(mySelector != null ? mySelector.getSelectedType() : myReturnType, 0, PsiSubstitutor.EMPTY));
|
||||
buffer.append(" ");
|
||||
buffer.append(myNameField.getText());
|
||||
}
|
||||
@@ -602,6 +606,6 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
|
||||
}
|
||||
|
||||
public PsiType getReturnType() {
|
||||
return mySelector.getSelectedType();
|
||||
return mySelector != null ? mySelector.getSelectedType() : myReturnType;
|
||||
}
|
||||
}
|
||||
|
||||
+48
-23
@@ -68,10 +68,8 @@ import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
|
||||
import com.intellij.refactoring.util.*;
|
||||
import com.intellij.refactoring.util.classMembers.ElementNeedsThis;
|
||||
import com.intellij.refactoring.util.duplicates.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -241,8 +239,11 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
}
|
||||
catch (ControlFlowWrapper.ExitStatementsNotSameException e) {
|
||||
myExitStatements = myControlFlowWrapper.getExitStatements();
|
||||
showMultipleExitPointsMessage();
|
||||
return false;
|
||||
myNotNullConditionalCheck = areAllExitPointsAreNotNull(getExpectedReturnType());
|
||||
if (!myNotNullConditionalCheck) {
|
||||
showMultipleExitPointsMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
myOutputVariables = myControlFlowWrapper.getOutputVariables();
|
||||
@@ -265,11 +266,7 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
}
|
||||
myHasExpressionOutput = expressionType != PsiType.VOID;
|
||||
|
||||
final PsiType returnStatementType = myCodeFragmentMember instanceof PsiMethod
|
||||
? ((PsiMethod)myCodeFragmentMember).getReturnType()
|
||||
: myCodeFragmentMember instanceof PsiLambdaExpression
|
||||
? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
|
||||
: null;
|
||||
final PsiType returnStatementType = getExpectedReturnType();
|
||||
myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && returnStatementType != PsiType.VOID;
|
||||
|
||||
if (myGenerateConditionalExit && myOutputVariables.length == 1) {
|
||||
@@ -284,15 +281,7 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
myNullConditionalCheck &= isNullInferred(myOutputVariables[0].getName(), false);
|
||||
}
|
||||
|
||||
if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
|
||||
myNotNullConditionalCheck = returnStatementType != null && returnStatementType != PsiType.VOID;
|
||||
for (PsiStatement statement : myExitStatements) {
|
||||
if (statement instanceof PsiReturnStatement) {
|
||||
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
|
||||
myNotNullConditionalCheck &= returnValue != null && !isNullInferred(returnValue.getText(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
myNotNullConditionalCheck = areAllExitPointsAreNotNull(returnStatementType);
|
||||
}
|
||||
|
||||
if (!myHasReturnStatementOutput && checkOutputVariablesCount() && !myNullConditionalCheck && !myNotNullConditionalCheck) {
|
||||
@@ -342,6 +331,28 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
private PsiType getExpectedReturnType() {
|
||||
return myCodeFragmentMember instanceof PsiMethod
|
||||
? ((PsiMethod)myCodeFragmentMember).getReturnType()
|
||||
: myCodeFragmentMember instanceof PsiLambdaExpression
|
||||
? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
|
||||
: null;
|
||||
}
|
||||
|
||||
private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) {
|
||||
if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
|
||||
boolean isNotNull = returnStatementType != null && returnStatementType != PsiType.VOID;
|
||||
for (PsiStatement statement : myExitStatements) {
|
||||
if (statement instanceof PsiReturnStatement) {
|
||||
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
|
||||
isNotNull &= returnValue != null && !isNullInferred(returnValue.getText(), true);
|
||||
}
|
||||
}
|
||||
return isNotNull;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean insertNotNullCheckIfPossible() {
|
||||
return true;
|
||||
}
|
||||
@@ -553,7 +564,19 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
: PsiTreeUtil.findCommonParent(myElements);
|
||||
return CodeInsightUtil.findReferenceExpressions(scope, myOutputVariable);
|
||||
}
|
||||
return PsiExpression.EMPTY_ARRAY;
|
||||
final List<PsiStatement> filter = ContainerUtil.filter(myExitStatements, new Condition<PsiStatement>() {
|
||||
@Override
|
||||
public boolean value(PsiStatement statement) {
|
||||
return statement instanceof PsiReturnStatement;
|
||||
}
|
||||
});
|
||||
final List<PsiExpression> map = ContainerUtil.map(filter, new Function<PsiStatement, PsiExpression>() {
|
||||
@Override
|
||||
public PsiExpression fun(PsiStatement statement) {
|
||||
return ((PsiReturnStatement) statement).getReturnValue();
|
||||
}
|
||||
});
|
||||
return map.toArray(new PsiExpression[map.size()]);
|
||||
}
|
||||
|
||||
private Nullness initNullness() {
|
||||
@@ -796,7 +819,7 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
CodeStyleManager.getInstance(myProject).reformat(ifStatement);
|
||||
}
|
||||
else if (myNotNullConditionalCheck) {
|
||||
String varName = myOutputVariable.getName();
|
||||
String varName = myOutputVariable != null ? myOutputVariable.getName() : "x";
|
||||
varName = declareVariableAtMethodCallLocation(varName, myReturnType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)myReturnType).getBoxedType(myCodeFragmentMember) : myReturnType);
|
||||
addToMethodCallLocation(myElementFactory.createStatementFromText("if (" + varName + " != null) return " + varName + ";", null));
|
||||
}
|
||||
@@ -1021,7 +1044,9 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
statement = (PsiDeclarationStatement)addToMethodCallLocation(statement);
|
||||
PsiVariable var = (PsiVariable)statement.getDeclaredElements()[0];
|
||||
myMethodCall = (PsiMethodCallExpression)var.getInitializer();
|
||||
var.getModifierList().replace(myOutputVariable.getModifierList());
|
||||
if (myOutputVariable != null) {
|
||||
var.getModifierList().replace(myOutputVariable.getModifierList());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizableStringList;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jdom.Element;
|
||||
@@ -168,30 +167,16 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
myDefaultNotNull = defaultNotNull;
|
||||
}
|
||||
|
||||
private static boolean skipAnnotation(@NotNull PsiAnnotation annotation, @NotNull PsiModifierListOwner owner) {
|
||||
return owner instanceof PsiMethod &&
|
||||
PsiUtil.canBeOverriden((PsiMethod)owner) &&
|
||||
AnnotationUtil.isInferredAnnotation(annotation) &&
|
||||
AnnotationUtil.NOT_NULL.equals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiAnnotation findNullabilityAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases, boolean nullable) {
|
||||
Set<String> qNames = ContainerUtil.newHashSet(nullable ? getNullables() : getNotNulls());
|
||||
PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, qNames);
|
||||
if (annotation != null && !skipAnnotation(annotation, owner)) {
|
||||
PsiAnnotation annotation = checkBases && (owner instanceof PsiClass || owner instanceof PsiMethod)
|
||||
? AnnotationUtil.findAnnotationInHierarchy(owner, qNames)
|
||||
: AnnotationUtil.findAnnotation(owner, qNames);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
if (checkBases && owner instanceof PsiMethod) {
|
||||
for (PsiModifierListOwner superOwner : AnnotationUtil.getSuperAnnotationOwners(owner)) {
|
||||
annotation = AnnotationUtil.findAnnotation(superOwner, qNames);
|
||||
if (annotation != null && !skipAnnotation(annotation, superOwner)) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PsiType type = getOwnerType(owner);
|
||||
if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null;
|
||||
|
||||
@@ -317,7 +302,6 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
}
|
||||
|
||||
try {
|
||||
//noinspection deprecation
|
||||
DefaultJDOMExternalizer.writeExternal(this, component);
|
||||
}
|
||||
catch (WriteExternalException e) {
|
||||
@@ -329,7 +313,6 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
@Override
|
||||
public void loadState(Element state) {
|
||||
try {
|
||||
//noinspection deprecation
|
||||
DefaultJDOMExternalizer.readExternal(this, state);
|
||||
if (myNullables.isEmpty()) {
|
||||
Collections.addAll(myNullables, DEFAULT_NULLABLES);
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Create Local Variable 'v'" "true"
|
||||
public class A {
|
||||
void foo() {
|
||||
L l = () -> {
|
||||
MyException v;
|
||||
throw v
|
||||
}
|
||||
}
|
||||
|
||||
interface L {
|
||||
void g() throws MyException;
|
||||
}
|
||||
class MyException extends Exception {}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Create Local Variable 'v'" "true"
|
||||
public class A {
|
||||
void foo() {
|
||||
L l = () -> {
|
||||
throw v<caret>
|
||||
}
|
||||
}
|
||||
|
||||
interface L {
|
||||
void g() throws MyException;
|
||||
}
|
||||
class MyException extends Exception {}
|
||||
}
|
||||
-5
@@ -2346,11 +2346,6 @@
|
||||
<item name="java.lang.System void checkKey(java.lang.String) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull"/>
|
||||
</item>
|
||||
<item name="java.lang.System void exit(int)">
|
||||
<annotation name="org.jetbrains.annotations.Contract">
|
||||
<val val=""_ -> fail""/>
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="java.lang.System void setProperties(java.util.Properties) 0">
|
||||
<annotation name="org.jetbrains.annotations.Nullable"/>
|
||||
</item>
|
||||
|
||||
+4
-10
@@ -3834,18 +3834,12 @@
|
||||
<item name="org.apache.commons.lang.Validate void notEmpty(java.util.Map, java.lang.String) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull"/>
|
||||
</item>
|
||||
<!-- hardcoded start -->
|
||||
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object)">
|
||||
<annotation name="org.jetbrains.annotations.Contract">
|
||||
<val val="value = "null -> fail", pure = true"/>
|
||||
</annotation>
|
||||
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull"/>
|
||||
</item>
|
||||
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object, java.lang.String)">
|
||||
<annotation name="org.jetbrains.annotations.Contract">
|
||||
<val val="value = "null, _ -> fail", pure = true"/>
|
||||
</annotation>
|
||||
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object, java.lang.String) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull"/>
|
||||
</item>
|
||||
<!-- hardcoded end -->
|
||||
<item name="org.apache.commons.lang.WordUtils WordUtils()">
|
||||
<annotation name="org.jetbrains.annotations.Contract">
|
||||
<val val="pure=true"/>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
class Fun {
|
||||
public static final boolean isDebug = true;
|
||||
|
||||
void foo() {
|
||||
if (isDebug) {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
void fooNegated() {
|
||||
if (!isDebug) {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class Test {
|
||||
Integer method() {
|
||||
<selection>try {
|
||||
if(cond1) return 0;
|
||||
else if(cond2) return null;
|
||||
System.out.println("Text");
|
||||
} finally {
|
||||
doSomething();
|
||||
}</selection>
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class Test {
|
||||
int method() {
|
||||
Integer x = newMethod();
|
||||
if (x != null) return x;
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Integer newMethod() {
|
||||
try {
|
||||
if(cond1) return 0;
|
||||
else if(cond2) return 1;
|
||||
System.out.println("Text");
|
||||
} finally {
|
||||
doSomething();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class Test {
|
||||
String foo(boolean b) {
|
||||
<selection>
|
||||
if (b) {
|
||||
return "a";
|
||||
}
|
||||
if (!b) {
|
||||
return "b";
|
||||
}
|
||||
</selection>
|
||||
return "42";
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -126,7 +126,7 @@ public class TemplatesCompletionTest extends CompletionAutoPopupTestCase {
|
||||
doAutoPopupTest("instanceof", null);
|
||||
}
|
||||
|
||||
public void testDoNotAutoCompleteCompletionElementIfTemplateUnique() {
|
||||
public void testDoNotAutoCompleteCompletionElementIfTemplateUnique() {
|
||||
LiveTemplateCompletionContributor.ourShowTemplatesInTests = true;
|
||||
configureByFile();
|
||||
myFixture.completeBasic();
|
||||
|
||||
+31
@@ -239,6 +239,28 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
|
||||
assert c == []
|
||||
}
|
||||
|
||||
public void "test return boxed integer"() {
|
||||
def c = inferContracts("""
|
||||
static Object test1(Object o1) {
|
||||
return o1 == null ? 1 : smth();
|
||||
}
|
||||
|
||||
static native Object smth()
|
||||
""")
|
||||
assert c == ['null -> !null']
|
||||
}
|
||||
|
||||
public void "test return boxed boolean"() {
|
||||
def c = inferContracts("""
|
||||
static Object test1(Object o1) {
|
||||
return o1 == null ? false : smth();
|
||||
}
|
||||
|
||||
static native Object smth()
|
||||
""")
|
||||
assert c == ['null -> !null']
|
||||
}
|
||||
|
||||
public void "test boolean autoboxing in delegation"() {
|
||||
def c = inferContracts("""
|
||||
static Boolean test04(String s) {
|
||||
@@ -391,6 +413,15 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
|
||||
assert c == ['null -> null']
|
||||
}
|
||||
|
||||
public void "test compare with string literal"() {
|
||||
def c = inferContracts("""
|
||||
String cast(String s) {
|
||||
return s == "a" ? "b" : null;
|
||||
}
|
||||
""")
|
||||
assert c == []
|
||||
}
|
||||
|
||||
public void "test return after if without else"() {
|
||||
def c = inferContracts("""
|
||||
public static boolean isBlank(String s) {
|
||||
|
||||
@@ -184,6 +184,8 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testUnknownFloatMayBeNaN() { doTest(); }
|
||||
public void testFloatEquality() { doTest(); }
|
||||
public void testLastConstantConditionInAnd() { doTest(); }
|
||||
|
||||
public void testCompileTimeConstant() { doTest(); }
|
||||
|
||||
public void testTransientFinalField() { doTest(); }
|
||||
public void testRememberLocalTransientFieldState() { doTest(); }
|
||||
|
||||
+28
-1
@@ -42,6 +42,17 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur
|
||||
assert inferNullity(parse('String foo() { return bar(); }; String bar() { return "z"; }; ')) == NOT_NULL
|
||||
}
|
||||
|
||||
void "test same delegate method invoked twice"() {
|
||||
assert inferNullity(parse('''
|
||||
String foo() {
|
||||
if (equals(2)) return bar();
|
||||
if (equals(3)) return bar();
|
||||
return "abc";
|
||||
}
|
||||
String bar() { return "z"; }
|
||||
''')) == NOT_NULL
|
||||
}
|
||||
|
||||
void "test if branch returns null"() {
|
||||
assert inferNullity(parse('String bar() { if (equals(2)) return null; return "a"; }; ')) == NULLABLE
|
||||
}
|
||||
@@ -50,9 +61,21 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur
|
||||
assert inferNullity(parse('String foo() { return bar(); }; String bar() { if (equals(2)) return null; return "a"; }; ')) == UNKNOWN
|
||||
}
|
||||
|
||||
void "test return boxed boolean constant"() {
|
||||
assert inferNullity(parse('Object foo() { return true; }')) == NOT_NULL
|
||||
}
|
||||
|
||||
void "test return boxed boolean value"() {
|
||||
assert inferNullity(parse('Object foo(Object o) { return o == null; }')) == NOT_NULL
|
||||
}
|
||||
|
||||
void "test return boxed integer"() {
|
||||
assert inferNullity(parse('Object foo() { return 1; }')) == NOT_NULL
|
||||
}
|
||||
|
||||
protected abstract Nullness inferNullity(PsiMethod method)
|
||||
|
||||
private PsiMethod parse(String method) {
|
||||
protected PsiMethod parse(String method) {
|
||||
return myFixture.addClass("final class Foo { $method }").methods[0]
|
||||
}
|
||||
|
||||
@@ -60,6 +83,10 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur
|
||||
Nullness inferNullity(PsiMethod method) {
|
||||
return NullableNotNullManager.isNotNull(method) ? NOT_NULL : NullableNotNullManager.isNullable(method) ? NULLABLE : UNKNOWN
|
||||
}
|
||||
|
||||
void "test skip when errors"() {
|
||||
assert inferNullity(parse('String foo() { if(); return 2; } ')) == UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
static class DfaInferenceTest extends NullityInferenceFromSourceTestCase {
|
||||
|
||||
+1
-2
@@ -17,7 +17,6 @@ package com.intellij.codeInspection.bytecodeAnalysis;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
||||
import com.intellij.codeInsight.InferredAnnotationsManager;
|
||||
import com.intellij.codeInsight.daemon.GutterMark;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
@@ -257,7 +256,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
|
||||
|
||||
@Nullable
|
||||
private PsiAnnotation findInferredAnnotation(PsiModifierListOwner owner, String fqn) {
|
||||
return InferredAnnotationsManager.getInstance(myModule.getProject()).findInferredAnnotation(owner, fqn);
|
||||
return ProjectBytecodeAnalysis.getInstance(getProject()).findInferredAnnotation(owner, fqn);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+5
-6
@@ -16,7 +16,6 @@
|
||||
package com.intellij.codeInspection.bytecodeAnalysis;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.InferredAnnotationsManager;
|
||||
import com.intellij.codeInspection.bytecodeAnalysis.asm.LeakingParameters;
|
||||
import com.intellij.codeInspection.bytecodeAnalysis.data.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -48,7 +47,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
|
||||
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
|
||||
private final String myClassesProjectRelativePath = "/classes/" + Test01.class.getPackage().getName().replace('.', '/');
|
||||
private JavaPsiFacade myJavaPsiFacade;
|
||||
private InferredAnnotationsManager myInferredAnnotationsManager;
|
||||
private ProjectBytecodeAnalysis myBytecodeAnalysisService;
|
||||
private MessageDigest myMessageDigest;
|
||||
|
||||
|
||||
@@ -56,7 +55,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myJavaPsiFacade = JavaPsiFacade.getInstance(myModule.getProject());
|
||||
myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
|
||||
myBytecodeAnalysisService = ProjectBytecodeAnalysis.getInstance(myModule.getProject());
|
||||
myMessageDigest = MessageDigest.getInstance("MD5");
|
||||
setUpDataClasses();
|
||||
}
|
||||
@@ -131,7 +130,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
|
||||
params: for (int i = 0; i < annotations.length; i++) {
|
||||
Annotation[] parameterAnnotations = annotations[i];
|
||||
PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i];
|
||||
PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
|
||||
PsiAnnotation inferredAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
|
||||
for (Annotation parameterAnnotation : parameterAnnotations) {
|
||||
if (parameterAnnotation.annotationType() == ExpectNotNull.class) {
|
||||
assertNotNull(javaMethod.toString() + " " + i, inferredAnnotation);
|
||||
@@ -143,13 +142,13 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
|
||||
|
||||
// not-null result
|
||||
ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class);
|
||||
PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
|
||||
PsiAnnotation actualAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
|
||||
assertEquals(javaMethod.toString(), expectedAnnotation == null, actualAnnotation == null);
|
||||
|
||||
|
||||
// contracts
|
||||
ExpectContract expectedContract = javaMethod.getAnnotation(ExpectContract.class);
|
||||
PsiAnnotation actualContract = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
|
||||
PsiAnnotation actualContract = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
|
||||
|
||||
String expectedText = expectedContract == null ? "null" : expectedContract.toString();
|
||||
String inferredText = actualContract == null ? "null" : actualContract.getText();
|
||||
|
||||
@@ -58,6 +58,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
|
||||
public void testExitPoints4() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testExitPoints4Nullable() throws Exception {
|
||||
doExitPointsTest(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ public class ReplaceMethodDuplicatesTestSuite {
|
||||
testSuite.addTestSuite(FindMethodDuplicatesMiscTest.class);
|
||||
testSuite.addTestSuite(FindMethodDuplicatesTest.class);
|
||||
testSuite.addTestSuite(SuggestedParamTypesTest.class);
|
||||
testSuite.addTestSuite(SuggestedReturnTypesTest.class);
|
||||
return testSuite;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,10 @@ public class SuggestedReturnTypesTest extends LightCodeInsightTestCase {
|
||||
doTest("Integer", "int");
|
||||
}
|
||||
|
||||
public void testOutputUsedInReturn() throws Exception {
|
||||
doTest("String");
|
||||
}
|
||||
|
||||
private void doTest(String... types) throws Exception {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
|
||||
|
||||
+5
-2
@@ -432,6 +432,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
|
||||
Color color = myEditor.getColorsScheme().getColor(EditorColors.LINE_NUMBERS_COLOR);
|
||||
g.setColor(color != null ? color : JBColor.blue);
|
||||
g.setFont(myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
|
||||
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
@@ -453,8 +454,10 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
if (logLine >= 0) {
|
||||
String s = String.valueOf(logLine + 1);
|
||||
int startY = (i + 1) * lineHeight;
|
||||
Color fgColor = myTextFgColors.get(i);
|
||||
g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue);
|
||||
if (myEditor.isInDistractionFreeMode()) {
|
||||
Color fgColor = myTextFgColors.get(i);
|
||||
g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue);
|
||||
}
|
||||
g.drawString(s,
|
||||
getLineNumberAreaOffset() + getLineNumberAreaWidth() -
|
||||
myEditor.getFontMetrics(Font.PLAIN).stringWidth(s) -
|
||||
|
||||
@@ -207,7 +207,7 @@ failed.to.generate.wrapper.error.message=Failed to generate temporary html wrapp
|
||||
|
||||
application.configuration.use.classpath.and.jdk.of.module.label=Use classpath of m&odule:
|
||||
application.configuration.main.class.label=Main &class:
|
||||
jre.path.is.not.valid.jre.home.error.mesage=''{0}'' is not valid JRE home
|
||||
jre.path.is.not.valid.jre.home.error.mesage=''{0}'' is not a valid JRE home
|
||||
main.method.not.found.in.class.error.message=Main method not found in class {0}
|
||||
no.user.process.input.error.message=No process input
|
||||
fix.run.configuration.problem.button=Fix
|
||||
|
||||
+5
-3
@@ -555,9 +555,11 @@ public class SMTestProxy extends AbstractTestProxy {
|
||||
return (AssertEqualsDiffViewerProvider)myState;
|
||||
}
|
||||
|
||||
for (SMTestProxy child : myChildren) {
|
||||
if (child.myState instanceof AssertEqualsDiffViewerProvider) {
|
||||
return (AssertEqualsDiffViewerProvider)child.myState;
|
||||
if (myChildren != null) {
|
||||
for (SMTestProxy child : myChildren) {
|
||||
if (child.myState instanceof AssertEqualsDiffViewerProvider) {
|
||||
return (AssertEqualsDiffViewerProvider)child.myState;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -25,6 +25,8 @@ import javax.swing.*;
|
||||
*/
|
||||
@SuppressWarnings("JUnitTestClassNamingConvention")
|
||||
public class _FirstInSuiteTest extends TestCase {
|
||||
public static long suiteStarted = 0L;
|
||||
|
||||
public void testNothing() throws Exception {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
@@ -46,6 +48,7 @@ public class _FirstInSuiteTest extends TestCase {
|
||||
|
||||
// performance tests
|
||||
public void testNothingPerformance() throws Exception {
|
||||
suiteStarted = System.nanoTime();
|
||||
testNothing();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,11 @@ public class _LastInSuiteTest extends TestCase {
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public void testStatistics() throws Exception {
|
||||
if (_FirstInSuiteTest.suiteStarted != 0) {
|
||||
long testSuiteDuration = System.nanoTime() - _FirstInSuiteTest.suiteStarted;
|
||||
System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTimeMs' value='%d']",
|
||||
testSuiteDuration / 1000000));
|
||||
}
|
||||
LightPlatformTestCase.reportTestExecutionStatistics();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -281,7 +281,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
|
||||
|
||||
/**
|
||||
* Runs highlighting test for the given files.
|
||||
* The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with all options set.
|
||||
* The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with {@code checkInfos=false}.
|
||||
*
|
||||
* @param filePaths the first file is tested only; the others are just copied along with the first.
|
||||
* @return highlighting duration in milliseconds
|
||||
|
||||
@@ -24,16 +24,19 @@ import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
class ConcurrentHashSet<K> implements Set<K> {
|
||||
/**
|
||||
* @deprecated use {@link ContainerUtil#newConcurrentSet()} instead
|
||||
*/
|
||||
public class ConcurrentHashSet<K> implements Set<K> {
|
||||
private final ConcurrentMap<K, Boolean> map;
|
||||
|
||||
ConcurrentHashSet(int initialCapacity) {
|
||||
public ConcurrentHashSet(int initialCapacity) {
|
||||
map = ContainerUtil.newConcurrentMap(initialCapacity);
|
||||
}
|
||||
ConcurrentHashSet() {
|
||||
public ConcurrentHashSet() {
|
||||
map = ContainerUtil.newConcurrentMap();
|
||||
}
|
||||
ConcurrentHashSet(@NotNull TObjectHashingStrategy<K> hashingStrategy) {
|
||||
public ConcurrentHashSet(@NotNull TObjectHashingStrategy<K> hashingStrategy) {
|
||||
map = ContainerUtil.newConcurrentMap(hashingStrategy);
|
||||
}
|
||||
|
||||
|
||||
+14
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Bas Leijdekkers
|
||||
* Copyright 2007-2014 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.siyeh.ipp.exceptions;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -36,8 +37,18 @@ public class ConvertCatchToThrowsIntention extends Intention {
|
||||
@Override
|
||||
protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiCatchSection catchSection = (PsiCatchSection)element.getParent();
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class);
|
||||
if (method == null) {
|
||||
final NavigatablePsiElement owner = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class, PsiLambdaExpression.class);
|
||||
final PsiMethod method;
|
||||
if (owner instanceof PsiMethod) {
|
||||
method = (PsiMethod)owner;
|
||||
}
|
||||
else if (owner instanceof PsiLambdaExpression) {
|
||||
method = LambdaUtil.getFunctionalInterfaceMethod(owner);
|
||||
if (method == null || !FileModificationService.getInstance().preparePsiElementsForWrite(method)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
// todo warn if method implements or overrides some base method
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2013 Bas Leijdekkers
|
||||
* Copyright 2007-2014 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,7 +29,7 @@ class ConvertCatchToThrowsPredicate implements PsiElementPredicate {
|
||||
if (element instanceof PsiCodeBlock) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, true, PsiClass.class);
|
||||
return method != null;
|
||||
final PsiElement owner = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiClass.class, PsiLambdaExpression.class);
|
||||
return owner instanceof PsiMethod || owner instanceof PsiLambdaExpression;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
class Lambda {
|
||||
|
||||
void bar() throws E {}
|
||||
|
||||
void foo() {
|
||||
U u = () -> {
|
||||
try {
|
||||
|
||||
} <caret>catch (E e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
interface U {
|
||||
void f();
|
||||
}
|
||||
class E extends Exception {}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
class Lambda {
|
||||
|
||||
void bar() throws E {}
|
||||
|
||||
void foo() {
|
||||
U u = () -> {
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
interface U {
|
||||
void f() throws E;
|
||||
}
|
||||
class E extends Exception {}
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,7 @@ public class ConvertCatchToThrowsTest extends IPPTestCase {
|
||||
public void testArmWithPluralCatches() { doTest(); }
|
||||
public void testArmWithSingleCatch() { doTest(); }
|
||||
public void testExistingThrows() { doTest(); }
|
||||
public void testLambda() { doTest(); }
|
||||
|
||||
@Override
|
||||
protected String getIntentionName() {
|
||||
|
||||
@@ -50,10 +50,7 @@ import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.NotNullPredicate;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
@@ -847,13 +844,7 @@ public class PyUtil {
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T as(@Nullable final Object expression, @NotNull final Class<T> clazz) {
|
||||
if (expression == null) {
|
||||
return null;
|
||||
}
|
||||
if (clazz.isAssignableFrom(expression.getClass())) {
|
||||
return (T)expression;
|
||||
}
|
||||
return null;
|
||||
return ObjectUtils.tryCast(expression, clazz);
|
||||
}
|
||||
|
||||
// TODO: Move to PsiElement?
|
||||
@@ -968,24 +959,25 @@ public class PyUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* If target is a PsiDirectory, that is also a valid Python package, return PsiFile that points to __init__.py,
|
||||
* If directory is a PsiDirectory, that is also a valid Python package, return PsiFile that points to __init__.py,
|
||||
* if such file exists, or directory itself (i.e. namespace package). Otherwise, return {@code null}.
|
||||
* Unlike {@link #turnDirIntoInit(com.intellij.psi.PsiElement)} this function handles namespace packages and
|
||||
* accepts only PsiDirectories as target.
|
||||
*
|
||||
* @param target directory to check
|
||||
* @param directory directory to check
|
||||
* @param anchor optional PSI element to determine language level as for {@link #isPackage(com.intellij.psi.PsiDirectory, com.intellij.psi.PsiElement)}
|
||||
* @return PsiFile or PsiDirectory, if target is a Python package and {@code null} null otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiElement turnDirIntoPackageElement(@NotNull PsiDirectory target, @Nullable PsiElement anchor) {
|
||||
if (isPackage(target, anchor)) {
|
||||
final PsiFile file = target.findFile(PyNames.INIT_DOT_PY);
|
||||
return file != null ? file : target;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) {
|
||||
if (isPackage(directory, anchor)) {
|
||||
final PsiElement init = turnDirIntoInit(directory);
|
||||
if (init != null) {
|
||||
return init;
|
||||
}
|
||||
return directory;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1019,18 +1011,6 @@ public class PyUtil {
|
||||
return PyNames.INIT_DOT_PY.equals(file.getName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) {
|
||||
if (isPackage(directory, anchor)) {
|
||||
final PsiElement init = turnDirIntoInit(directory);
|
||||
if (init != null) {
|
||||
return init;
|
||||
}
|
||||
return directory;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isSetuptoolsNamespacePackage(@NotNull PsiDirectory directory) {
|
||||
final String packagePath = getPackagePath(directory);
|
||||
return packagePath != null && !PySetuptoolsNamespaceIndex.find(packagePath, directory.getProject()).isEmpty();
|
||||
@@ -1165,8 +1145,8 @@ public class PyUtil {
|
||||
public static Collection<VirtualFile> getSourceRoots(@NotNull Module module) {
|
||||
final Set<VirtualFile> result = new LinkedHashSet<VirtualFile>();
|
||||
final ModuleRootManager manager = ModuleRootManager.getInstance(module);
|
||||
result.addAll(Arrays.asList(manager.getSourceRoots()));
|
||||
result.addAll(Arrays.asList(manager.getContentRoots()));
|
||||
Collections.addAll(result, manager.getSourceRoots());
|
||||
Collections.addAll(result, manager.getContentRoots());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1708,10 +1688,7 @@ public class PyUtil {
|
||||
|
||||
private static boolean isObject(@NotNull final PyMemberInfo<PyElement> classMemberInfo) {
|
||||
final PyElement element = classMemberInfo.getMember();
|
||||
if ((element instanceof PyClass) && PyNames.OBJECT.equals(element.getName())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (element instanceof PyClass) && PyNames.OBJECT.equals(element.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1751,10 +1728,7 @@ public class PyUtil {
|
||||
*/
|
||||
public static boolean isObjectClass(@NotNull PyClass cls) {
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(cls);
|
||||
if (cls == builtinCache.getClass(PyNames.OBJECT) || cls == builtinCache.getClass(PyNames.FAKE_OLD_BASE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return cls == builtinCache.getClass(PyNames.OBJECT) || cls == builtinCache.getClass(PyNames.FAKE_OLD_BASE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1768,9 +1742,6 @@ public class PyUtil {
|
||||
*/
|
||||
public static boolean isObjectType(@NotNull PyType type, @NotNull PsiElement anchor) {
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor);
|
||||
if (type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -175,7 +174,7 @@ public class ResolveImportUtil {
|
||||
if (qualifiedName == null || sourceFile == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final String marker = StringUtil.join(qualifiedName.getComponents(), ".") + "#" + Integer.toString(relativeLevel);
|
||||
final String marker = qualifiedName + "#" + Integer.toString(relativeLevel);
|
||||
final Set<String> beingImported = ourBeingImported.get();
|
||||
if (beingImported.contains(marker)) {
|
||||
return Collections.emptyList(); // break endless loop in import
|
||||
|
||||
@@ -297,8 +297,8 @@ public class PyRefactoringUtil {
|
||||
final FindUsagesHandler handler = new PyFindUsagesHandlerFactory().createFindUsagesHandler(element, forHighlightUsages);
|
||||
assert handler != null;
|
||||
final List<PsiElement> elementsToProcess = new ArrayList<PsiElement>();
|
||||
elementsToProcess.addAll(Arrays.asList(handler.getPrimaryElements()));
|
||||
elementsToProcess.addAll(Arrays.asList(handler.getSecondaryElements()));
|
||||
Collections.addAll(elementsToProcess, handler.getPrimaryElements());
|
||||
Collections.addAll(elementsToProcess, handler.getSecondaryElements());
|
||||
for (PsiElement e : elementsToProcess) {
|
||||
handler.processElementUsages(e, new Processor<UsageInfo>() {
|
||||
@Override
|
||||
|
||||
@@ -245,7 +245,7 @@ public final class PyClassRefactoringUtil {
|
||||
final String asName = node.getCopyableUserData(ENCODED_IMPORT_AS);
|
||||
final Boolean useFromImport = node.getCopyableUserData(ENCODED_USE_FROM_IMPORT);
|
||||
if (target instanceof PsiDirectory) {
|
||||
target = (PsiNamedElement)PyUtil.turnDirIntoPackageElement((PsiDirectory)target, node);
|
||||
target = (PsiNamedElement)PyUtil.getPackageElement((PsiDirectory)target, node);
|
||||
}
|
||||
if (target instanceof PyFunction) {
|
||||
final PyFunction f = (PyFunction)target;
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
package com.jetbrains.python.refactoring.move;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
@@ -40,8 +42,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.vfs.VirtualFileManager.*;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
@@ -91,32 +91,29 @@ public class PyMoveFileHandler extends MoveFileHandler {
|
||||
continue;
|
||||
}
|
||||
final QualifiedName newName = QualifiedNameFinder.findShortestImportableQName(sourceElement);
|
||||
final PsiElement fromKeyword = statement.getFirstChild();
|
||||
final PsiElement firstDot = fromKeyword.getNextSibling().getNextSibling();
|
||||
assert firstDot.getNode().getElementType() == PyTokenTypes.DOT;
|
||||
final PsiWhiteSpace nextWhitespace = PsiTreeUtil.getNextSiblingOfType(firstDot, PsiWhiteSpace.class);
|
||||
final PsiElement replacementEnd = nextWhitespace == null ? statement.getLastChild() : nextWhitespace.getPrevSibling();
|
||||
if (replacementEnd != firstDot) {
|
||||
statement.deleteChildRange(firstDot.getNextSibling(), replacementEnd);
|
||||
}
|
||||
replaceWithQualifiedExpression(firstDot, newName);
|
||||
replaceRelativeImportSourceWithQualifiedExpression(statement, newName);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiFileSystemItem resolveRelativeImportSourceFromModuleLocation(@NotNull String moduleLocation,
|
||||
@NotNull PyFromImportStatement statement) {
|
||||
String relativeImportBasePath = extractPath(moduleLocation);
|
||||
String relativeImportBasePath = VirtualFileManager.extractPath(moduleLocation);
|
||||
for (int level = 0; level < statement.getRelativeLevel(); level++) {
|
||||
relativeImportBasePath = PathUtil.getParentPath(relativeImportBasePath);
|
||||
}
|
||||
if (!relativeImportBasePath.isEmpty()) {
|
||||
//noinspection ConstantConditions
|
||||
final String relativeImportBaseUrl = constructUrl(extractProtocol(moduleLocation), relativeImportBasePath);
|
||||
final VirtualFile relativeImportBaseDir = getInstance().findFileByUrl(relativeImportBaseUrl);
|
||||
final String protocol = VirtualFileManager.extractProtocol(moduleLocation);
|
||||
assert protocol != null : "Original location: " + moduleLocation;
|
||||
final String relativeImportBaseUrl = VirtualFileManager.constructUrl(protocol, relativeImportBasePath);
|
||||
final VirtualFile relativeImportBaseDir = VirtualFileManager.getInstance().findFileByUrl(relativeImportBaseUrl);
|
||||
VirtualFile sourceFile = relativeImportBaseDir;
|
||||
if (relativeImportBaseDir != null && relativeImportBaseDir.exists() && statement.getImportSource() != null) {
|
||||
final String relativePath = statement.getImportSource().getText().replace('.', '/');
|
||||
final QualifiedName qualifiedName = statement.getImportSource().asQualifiedName();
|
||||
if (qualifiedName == null) {
|
||||
return null;
|
||||
}
|
||||
final String relativePath = qualifiedName.join("/");
|
||||
sourceFile = relativeImportBaseDir.findFileByRelativePath(relativePath);
|
||||
if (sourceFile == null) {
|
||||
sourceFile = relativeImportBaseDir.findFileByRelativePath(relativePath + PyNames.DOT_PY);
|
||||
@@ -186,8 +183,12 @@ public class PyMoveFileHandler extends MoveFileHandler {
|
||||
continue;
|
||||
}
|
||||
final QualifiedName newElementName = QualifiedNameFinder.findCanonicalImportPath(newElement, element);
|
||||
removeLeadingDots(element);
|
||||
replaceWithQualifiedExpression(element, newElementName);
|
||||
if (importStmt instanceof PyFromImportStatement) {
|
||||
replaceRelativeImportSourceWithQualifiedExpression((PyFromImportStatement)importStmt, newElementName);
|
||||
}
|
||||
else {
|
||||
replaceWithQualifiedExpression(element, newElementName);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyReferenceExpression) {
|
||||
updatedFiles.add(file);
|
||||
@@ -227,21 +228,58 @@ public class PyMoveFileHandler extends MoveFileHandler {
|
||||
return oldElement;
|
||||
}
|
||||
|
||||
private static void removeLeadingDots(@NotNull PsiElement element) {
|
||||
PsiElement lastDot = null;
|
||||
PsiElement firstDot = null;
|
||||
for (PsiElement prev = element.getPrevSibling(); prev != null; prev = prev.getPrevSibling()) {
|
||||
if (prev.getNode().getElementType() != PyTokenTypes.DOT) {
|
||||
break;
|
||||
/**
|
||||
* Replace import source with leading dots (if any) with reference expression created from given qualified name.
|
||||
* Basically it does the same thing as {@link #replaceWithQualifiedExpression}, but also removes leading dots.
|
||||
*
|
||||
* @param importStatement import statement to update
|
||||
* @param qualifiedName qualified name of new import source
|
||||
* @return updated import statement
|
||||
* @see #replaceWithQualifiedExpression(com.intellij.psi.PsiElement, com.intellij.psi.util.QualifiedName)
|
||||
*/
|
||||
@NotNull
|
||||
private static PsiElement replaceRelativeImportSourceWithQualifiedExpression(@NotNull PyFromImportStatement importStatement,
|
||||
@Nullable QualifiedName qualifiedName) {
|
||||
final Couple<PsiElement> range = getRelativeImportSourceRange(importStatement);
|
||||
if (range != null && qualifiedName != null) {
|
||||
if (range.getFirst() == range.getSecond()) {
|
||||
replaceWithQualifiedExpression(range.getFirst(), qualifiedName);
|
||||
}
|
||||
if (lastDot == null) {
|
||||
lastDot = prev;
|
||||
else {
|
||||
importStatement.deleteChildRange(range.getFirst().getNextSibling(), range.getSecond());
|
||||
replaceWithQualifiedExpression(range.getFirst(), qualifiedName);
|
||||
}
|
||||
firstDot = prev;
|
||||
}
|
||||
if (lastDot != null && firstDot != null) {
|
||||
element.getParent().deleteChildRange(firstDot, lastDot);
|
||||
return importStatement;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Couple<PsiElement> getRelativeImportSourceRange(@NotNull PyFromImportStatement statement) {
|
||||
final PsiElement fromKeyword = statement.getFirstChild();
|
||||
assert fromKeyword.getNode().getElementType() == PyTokenTypes.FROM_KEYWORD;
|
||||
final PsiElement elementAfterFrom = PsiTreeUtil.skipSiblingsForward(fromKeyword, PsiWhiteSpace.class);
|
||||
if (elementAfterFrom == null) {
|
||||
return null;
|
||||
}
|
||||
else if (elementAfterFrom instanceof PyReferenceExpression) {
|
||||
return Couple.of(elementAfterFrom, elementAfterFrom);
|
||||
}
|
||||
else if (elementAfterFrom.getNode().getElementType() == PyTokenTypes.DOT) {
|
||||
PsiElement lastDot;
|
||||
PsiElement next = elementAfterFrom;
|
||||
do {
|
||||
lastDot = next;
|
||||
next = PsiTreeUtil.skipSiblingsForward(next, PsiWhiteSpace.class);
|
||||
}
|
||||
while (next != null && next.getNode().getElementType() == PyTokenTypes.DOT);
|
||||
if (next instanceof PyReferenceExpression) {
|
||||
return Couple.of(elementAfterFrom, next);
|
||||
}
|
||||
else {
|
||||
return Couple.of(elementAfterFrom, lastDot);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from .case import TestCase
|
||||
@@ -1,2 +0,0 @@
|
||||
class TestCase(object):
|
||||
pass
|
||||
@@ -1 +0,0 @@
|
||||
from .case import TestCase
|
||||
@@ -1,2 +0,0 @@
|
||||
class TestCase(object):
|
||||
pass
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
from pkg.subpkg2.subsubpkg import b
|
||||
|
||||
print(b)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
from .. subpkg2 . subsubpkg import b
|
||||
|
||||
print(b)
|
||||
@@ -75,7 +75,7 @@ public class PyPep8NamingInspectionTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testTest() {
|
||||
doTest();
|
||||
doMultiFileTest();
|
||||
}
|
||||
|
||||
public void testOverrideFromModule() {
|
||||
@@ -90,4 +90,12 @@ public class PyPep8NamingInspectionTest extends PyTestCase {
|
||||
myFixture.enableInspections(PyPep8NamingInspection.class);
|
||||
myFixture.checkHighlighting(false, false, true);
|
||||
}
|
||||
|
||||
private void doMultiFileTest() {
|
||||
myFixture.copyDirectoryToProject("inspections/PyPep8NamingInspection/" + getTestName(true), "");
|
||||
myFixture.configureByFile("a.py");
|
||||
myFixture.enableInspections(PyPep8NamingInspection.class);
|
||||
myFixture.checkHighlighting(false, false, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -200,6 +200,12 @@ public class PyMoveTest extends PyTestCase {
|
||||
doMoveFileTest("pkg1/subpkg1", "");
|
||||
}
|
||||
|
||||
|
||||
// PY-14432
|
||||
public void testRelativeImportSourceWithSpacesInsideMovedModule() {
|
||||
doMoveFileTest("pkg/subpkg1/a.py", "");
|
||||
}
|
||||
|
||||
// PY-14595
|
||||
public void testNamespacePackageUsedInMovedFunction() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() {
|
||||
|
||||
Reference in New Issue
Block a user