Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2014-12-31 00:57:04 +01:00
58 changed files with 922 additions and 688 deletions
@@ -198,22 +198,28 @@ public class LineBreakpoint extends BreakpointWithHighlighter {
final VirtualFile breakpointFile = position.getFile().getVirtualFile();
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
if (breakpointFile != null && fileIndex.isUnderSourceRootOfType(breakpointFile, JavaModuleSourceRootTypes.SOURCES)) {
if (debugProcess.getSearchScope().contains(breakpointFile)) {
return true;
}
// apply filtering to breakpoints from content sources only, not for sources attached to libraries
final Collection<VirtualFile> candidates = findClassCandidatesInSourceContent(className, debugProcess.getSearchScope(), fileIndex);
if (LOG.isDebugEnabled()) {
LOG.debug("Found "+ (candidates == null? "null" : candidates.size()) + " candidate containing files for class " + className);
}
if (candidates == null) {
// If no candidates are found in scope then assume that class is loaded dynamically and allow breakpoint
return true;
}
for (VirtualFile classFile : candidates) {
if (LOG.isDebugEnabled()) {
LOG.debug("Breakpoint file: " + breakpointFile.getPath()+ "; candidate file: " + classFile.getPath());
}
if (breakpointFile.equals(classFile)) {
return true;
}
}
// breakpointFile is not in scope here and there are some candidates in scope
//for (VirtualFile classFile : candidates) {
// if (LOG.isDebugEnabled()) {
// LOG.debug("Breakpoint file: " + breakpointFile.getPath()+ "; candidate file: " + classFile.getPath());
// }
// if (breakpointFile.equals(classFile)) {
// return true;
// }
//}
if (LOG.isDebugEnabled()) {
final GlobalSearchScope scope = debugProcess.getSearchScope();
final boolean contains = scope.contains(breakpointFile);
@@ -159,10 +159,7 @@ public class HighlightNamesUtil {
@Nullable
public static HighlightInfo highlightClassNameInQualifier(final PsiJavaCodeReferenceElement element,
@NotNull TextAttributesScheme colorsScheme) {
PsiExpression qualifierExpression = null;
if (element instanceof PsiReferenceExpression) {
qualifierExpression = ((PsiReferenceExpression)element).getQualifierExpression();
}
PsiElement qualifierExpression = element.getQualifier();
if (qualifierExpression instanceof PsiJavaCodeReferenceElement) {
PsiElement resolved = ((PsiJavaCodeReferenceElement)qualifierExpression).resolve();
if (resolved instanceof PsiClass) {
@@ -647,12 +647,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
final String refName = ref.getReferenceName();
final JavaResolveResult[] results = ref.multiResolve(false);
final PsiElement referenceNameElement = ref.getReferenceNameElement();
if (results.length == 0) {
final String description = JavaErrorMessages.message("cannot.resolve.symbol", refName);
final PsiElement nameElement = ref.getReferenceNameElement();
assert nameElement != null : ref;
assert referenceNameElement != null : ref;
final HighlightInfo info =
HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(nameElement).descriptionAndTooltip(description).create();
HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(referenceNameElement).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createSetupJDKFix());
myHolder.add(info);
}
@@ -690,6 +690,22 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
}
}
if (!myHolder.hasErrorResults()) {
final PsiElement resolved = results.length == 1 ? results[0].getElement() : null;
final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
if (resolved instanceof PsiClass) {
myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass)resolved, ref, colorsScheme));
}
else{
myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(ref, colorsScheme));
if (resolved instanceof PsiVariable) {
myHolder.add(HighlightNamesUtil.highlightVariableName((PsiVariable)resolved, referenceNameElement, colorsScheme));
}
else if (resolved instanceof PsiMethod) {
myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)resolved, referenceNameElement, false, colorsScheme));
}
}
}
}
@Override
@@ -215,7 +215,9 @@ public class TargetElementUtil extends TargetElementUtilBase {
@Override
public Collection<PsiElement> getTargetCandidates(final PsiReference reference) {
PsiElement parent = reference.getElement().getParent();
if (parent instanceof PsiCallExpression) {
if (parent instanceof PsiMethodCallExpression || parent instanceof PsiNewExpression &&
((PsiNewExpression)parent).getArrayDimensions().length == 0 &&
((PsiNewExpression)parent).getArrayInitializer() == null) {
PsiCallExpression callExpr = (PsiCallExpression)parent;
boolean allowStatics = false;
PsiExpression qualifier = callExpr instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression)callExpr).getMethodExpression().getQualifierExpression()
@@ -392,6 +392,12 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer
return super.getCaretOffset();
}
@Override
public void finish(boolean success) {
super.finish(success);
myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, null);
}
@Override
protected String[] suggestNames(PsiType defaultType, String propName) {
return IntroduceVariableBase.getSuggestedName(defaultType, myExpr).names;
@@ -107,7 +107,7 @@ public class JavaTestFinder implements TestFinder {
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(klass.getProject());
String klassName = klass.getName();
Pattern pattern = Pattern.compile(".*" + klassName + ".*");
Pattern pattern = Pattern.compile(".*" + klassName + ".*", Pattern.CASE_INSENSITIVE);
HashSet<String> names = new HashSet<String>();
cache.getAllClassNames(names);
@@ -1,4 +1,6 @@
import <symbolName descr="null" type="CLASS_NAME">java.io</symbolName>.*; // highlight on demand import as class name
import static <symbolName descr="null" type="CLASS_NAME">java.io.File</symbolName>.<symbolName descr="null" type="STATIC_FINAL_FIELD">pathSeparator</symbolName>;
import static <symbolName descr="null" type="CLASS_NAME">java.io.File</symbolName>.*;
class <symbolName descr="null" type="CLASS_NAME">a</symbolName> {
void <symbolName descr="null" type="METHOD_DECLARATION">method</symbolName>() {
@@ -24,7 +24,7 @@ class JavaPredefinedConfigurations {
// Expression patterns
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.method.calls"), "'_Instance?.'MethodCall('_Parameter*)", EXPRESSION_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.new.expressions"), "new 'Constructor('_Argument*)", EXPRESSION_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.lambdas"), "('_Parameter) -> ", EXPRESSION_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.lambdas"), "('_Parameter*) -> ", EXPRESSION_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.field.selections"),"'_Instance?.'Field",EXPRESSION_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.array.access"),"'_Field['_Index]",EXPRESSION_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.assignments"),"'_Inst = '_Expr",EXPRESSION_TYPE),
@@ -21,6 +21,8 @@ import com.intellij.structuralsearch.impl.matcher.iterators.HierarchyNodeIterato
import com.intellij.structuralsearch.impl.matcher.predicates.NotPredicate;
import com.intellij.structuralsearch.impl.matcher.predicates.RegExpPredicate;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -383,17 +385,23 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
final PsiLambdaExpression expression2 = (PsiLambdaExpression)myMatchingVisitor.getElement();
boolean result = true;
final PsiParameterList parameterList1 = expression.getParameterList();
if (parameterList1.getParametersCount() != 0) {
result = myMatchingVisitor.matchSons(parameterList1, expression2.getParameterList());
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiLambdaExpression) {
final PsiLambdaExpression expression2 = (PsiLambdaExpression)other;
boolean result = true;
final PsiParameterList parameterList1 = expression.getParameterList();
if (parameterList1.getParametersCount() != 0) {
result = myMatchingVisitor.matchSons(parameterList1, expression2.getParameterList());
}
final PsiElement body1 = getElementToMatch(expression.getBody());
if (body1 != null && result) {
result = myMatchingVisitor.matchSequentially(body1, getElementToMatch(expression2.getBody()));
}
myMatchingVisitor.setResult(result);
}
final PsiElement body1 = getElementToMatch(expression.getBody());
if (body1 != null) {
result = myMatchingVisitor.matchSequentially(body1, getElementToMatch(expression2.getBody()));
else {
myMatchingVisitor.setResult(false);
}
myMatchingVisitor.setResult(result);
}
private static PsiElement getElementToMatch(PsiElement element) {
@@ -570,10 +578,15 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitArrayAccessExpression(final PsiArrayAccessExpression slice) {
final PsiArrayAccessExpression slice2 = (PsiArrayAccessExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(slice.getArrayExpression(), slice2.getArrayExpression()) &&
myMatchingVisitor.match(slice.getIndexExpression(), slice2.getIndexExpression()));
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiArrayAccessExpression) {
final PsiArrayAccessExpression slice2 = (PsiArrayAccessExpression)other;
myMatchingVisitor.setResult(myMatchingVisitor.match(slice.getArrayExpression(), slice2.getArrayExpression()) &&
myMatchingVisitor.match(slice.getIndexExpression(), slice2.getIndexExpression()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
@@ -731,9 +744,6 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
PsiElement[] typeparams = null;
if (el2 instanceof PsiJavaCodeReferenceElement) {
typeparams = ((PsiJavaCodeReferenceElement)el2).getParameterList().getTypeParameterElements();
if (typeparams.length > 0) {
el2 = ((PsiJavaCodeReferenceElement)el2).getReferenceNameElement();
}
}
else if (el2 instanceof PsiTypeParameter) {
el2 = ((PsiTypeParameter)el2).getNameIdentifier();
@@ -752,13 +762,13 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
PsiReferenceParameterList list = null;
if (el instanceof PsiJavaCodeReferenceElement) {
list = ((PsiJavaCodeReferenceElement)el).getParameterList();
el = ((PsiJavaCodeReferenceElement)el).getReferenceNameElement();
}
if (list != null && list.getTypeParameterElements().length > 0) {
boolean result = typeparams != null && myMatchingVisitor.matchSequentially(list.getTypeParameterElements(), typeparams);
if (!result) return false;
el = ((PsiJavaCodeReferenceElement)el).getReferenceNameElement();
}
else {
if (_type2 instanceof PsiTypeElement) {
@@ -831,25 +841,17 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
el2 = parent;
}
}
final String text = stripTypeParameters(el.getText());
String text2;
if (el2 instanceof PsiClass) {
text2 = ((PsiClass)el2).getQualifiedName();
if (text2 == null) text2 = el2.getText();
} else {
text2 = el2.getText();
}
final boolean equalsIgnorePackage = MatchUtils.compareWithNoDifferenceToPackage(text, stripTypeParameters(text2));
final String text = getText(el);
final String text2 = getText(el2);
final boolean equalsIgnorePackage = MatchUtils.compareWithNoDifferenceToPackage(text, text2);
if (equalsIgnorePackage || !(el2 instanceof PsiJavaReference)) {
return equalsIgnorePackage;
}
else {
PsiElement element2 = ((PsiJavaReference)el2).resolve();
final PsiElement element2 = ((PsiJavaReference)el2).resolve();
if (element2 instanceof PsiClass) {
final PsiClass aClass = (PsiClass)element2;
return text.equals(aClass.getQualifiedName()) || text.equals(aClass.getName());
return text.equals(((PsiClass)element2).getQualifiedName());
}
else {
return MatchUtils.compareWithNoDifferenceToPackage(text, text2);
@@ -857,12 +859,33 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
}
}
private static String stripTypeParameters(String string) {
final int index = string.indexOf('<');
if (index == -1) {
return string;
@Contract(pure = true)
private static String getText(@NotNull PsiElement element) {
String result;
if (element instanceof PsiClass) {
result = ((PsiClass)element).getQualifiedName();
if (result == null) result = element.getText();
} else {
result = element.getText();
}
return string.substring(0, index);
final int whitespace = lastIndexOfWhitespace(result);
if (whitespace >= 0) {
// strips off any annotations
result = result.substring(whitespace + 1);
}
final int index = result.indexOf('<');
if (index == -1) {
return result;
}
return result.substring(0, index);
}
@Contract(pure = true)
private static int lastIndexOfWhitespace(@NotNull CharSequence s) {
for (int i = s.length() - 1; i >= 0; i--) {
if (Character.isWhitespace(s.charAt(i))) return i;
}
return -1;
}
private boolean checkMatchWithingHierarchy(PsiElement el2, SubstitutionHandler handler, PsiElement context) {
@@ -1119,9 +1142,14 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitExpressionStatement(final PsiExpressionStatement expr) {
final PsiExpressionStatement expr2 = (PsiExpressionStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getExpression(), expr2.getExpression()));
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiExpressionStatement) {
final PsiExpressionStatement expr2 = (PsiExpressionStatement)other;
myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getExpression(), expr2.getExpression()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
@@ -1156,11 +1184,17 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitAssignmentExpression(final PsiAssignmentExpression assign) {
final PsiAssignmentExpression assign2 = (PsiAssignmentExpression)myMatchingVisitor.getElement();
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assign2 = (PsiAssignmentExpression)other;
myMatchingVisitor.setResult(assign.getOperationTokenType().equals(assign2.getOperationTokenType()) &&
myMatchingVisitor.match(assign.getLExpression(), assign2.getLExpression()) &&
myMatchingVisitor.match(assign.getRExpression(), assign2.getRExpression()));
myMatchingVisitor.setResult(assign.getOperationTokenType().equals(assign2.getOperationTokenType()) &&
myMatchingVisitor.match(assign.getLExpression(), assign2.getLExpression()) &&
myMatchingVisitor.match(assign.getRExpression(), assign2.getRExpression()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
@@ -1212,13 +1246,13 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitBlockStatement(final PsiBlockStatement block) {
if (myMatchingVisitor.getElement() instanceof PsiCodeBlock &&
!(myMatchingVisitor.getElement().getParent() instanceof PsiBlockStatement)
) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(block.getCodeBlock(), myMatchingVisitor.getElement()));
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiCodeBlock) {
myMatchingVisitor.setResult(!(other.getParent() instanceof PsiBlockStatement) &&
myMatchingVisitor.matchSons(block.getCodeBlock(), other));
}
else {
final PsiBlockStatement block2 = (PsiBlockStatement)myMatchingVisitor.getElement();
final PsiBlockStatement block2 = (PsiBlockStatement)other;
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(block, block2));
}
}
@@ -1414,14 +1448,20 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitInstanceOfExpression(final PsiInstanceOfExpression instanceOf) {
final PsiInstanceOfExpression instanceOf2 = (PsiInstanceOfExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getOperand(), instanceOf2.getOperand()));
if (myMatchingVisitor.getResult()) {
final PsiTypeElement checkType = instanceOf.getCheckType();
if (checkType != null) {
myMatchingVisitor.setResult(matchType(checkType, instanceOf2.getCheckType()));
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiInstanceOfExpression) {
final PsiInstanceOfExpression instanceOf2 = (PsiInstanceOfExpression)other;
myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getOperand(), instanceOf2.getOperand()));
if (myMatchingVisitor.getResult()) {
final PsiTypeElement checkType = instanceOf.getCheckType();
if (checkType != null) {
myMatchingVisitor.setResult(matchType(checkType, instanceOf2.getCheckType()));
}
}
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
@@ -1501,22 +1541,39 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
@Override
public void visitTypeCastExpression(final PsiTypeCastExpression cast) {
final PsiTypeCastExpression cast2 = (PsiTypeCastExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(cast.getCastType(), cast2.getCastType()) &&
myMatchingVisitor.match(cast.getOperand(), cast2.getOperand()));
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiTypeCastExpression) {
final PsiTypeCastExpression cast2 = (PsiTypeCastExpression)other;
myMatchingVisitor.setResult(myMatchingVisitor.match(cast.getCastType(), cast2.getCastType()) &&
myMatchingVisitor.match(cast.getOperand(), cast2.getOperand()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
public void visitClassObjectAccessExpression(final PsiClassObjectAccessExpression expr) {
final PsiClassObjectAccessExpression expr2 = (PsiClassObjectAccessExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getOperand(), expr2.getOperand()));
final PsiElement other = myMatchingVisitor.getElement();
if (other instanceof PsiClassObjectAccessExpression) {
final PsiClassObjectAccessExpression expr2 = (PsiClassObjectAccessExpression)other;
myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getOperand(), expr2.getOperand()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
public void visitReferenceElement(final PsiJavaCodeReferenceElement ref) {
myMatchingVisitor.setResult(matchType(ref, myMatchingVisitor.getElement()));
final PsiElement other = myMatchingVisitor.getElement();
final PsiAnnotation[] annotations = PsiTreeUtil.getChildrenOfType(ref, PsiAnnotation.class);
if (annotations != null) {
final PsiAnnotation[] otherAnnotations = PsiTreeUtil.getChildrenOfType(other, PsiAnnotation.class);
myMatchingVisitor.setResult(otherAnnotations != null && myMatchingVisitor.matchInAnyOrder(annotations, otherAnnotations));
if (!myMatchingVisitor.getResult()) return;
}
myMatchingVisitor.setResult(matchType(ref, other));
}
@Override
@@ -26,6 +26,10 @@ import org.jetbrains.annotations.NotNull;
* @author Eugene.Kudelevsky
*/
public class WebReference extends PsiReferenceBase<PsiElement> {
public WebReference(@NotNull PsiElement element) {
super(element, true);
}
public WebReference(@NotNull PsiElement element, @NotNull TextRange textRange) {
super(element, textRange, true);
}
@@ -35,6 +39,10 @@ public class WebReference extends PsiReferenceBase<PsiElement> {
return new MyFakePsiElement();
}
protected String getUrl() {
return getValue();
}
@NotNull
@Override
public Object[] getVariants() {
@@ -43,25 +51,31 @@ public class WebReference extends PsiReferenceBase<PsiElement> {
class MyFakePsiElement extends FakePsiElement {
@Override
public PsiElement getParent() {
return myElement;
}
@Override
public void navigate(boolean requestFocus) {
BrowserUtil.browse(getValue());
public PsiElement getParent() {
return myElement;
}
@Override
public String getPresentableText() {
return getValue();
}
public void navigate(boolean requestFocus) {
BrowserUtil.browse(getUrl());
}
@Override
public TextRange getTextRange() {
final TextRange rangeInElement = getRangeInElement();
final TextRange elementRange = myElement.getTextRange();
return elementRange != null ? rangeInElement.shiftRight(elementRange.getStartOffset()) : rangeInElement;
}
@Override
public String getPresentableText() {
return getUrl();
}
@Override
public String getName() {
return getUrl();
}
@Override
public TextRange getTextRange() {
final TextRange rangeInElement = getRangeInElement();
final TextRange elementRange = myElement.getTextRange();
return elementRange != null ? rangeInElement.shiftRight(elementRange.getStartOffset()) : rangeInElement;
}
}
}
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiQualifiedNamedElement;
import com.intellij.psi.search.scope.packageSet.*;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.listeners.RefactoringElementAdapter;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.listeners.RefactoringElementListenerComposite;
@@ -39,10 +40,30 @@ public class RefactoringScopeElementListenerProvider implements RefactoringEleme
@Override
public RefactoringElementListener getListener(PsiElement element) {
final PsiFile containingFile = element.getContainingFile();
if (!(element instanceof PsiQualifiedNamedElement) && !(element instanceof PsiDirectory)) return null;
final String oldName = getQualifiedName(element);
final PsiFile containingFile = element.getContainingFile();
RefactoringElementListenerComposite composite = null;
String oldName = getQualifiedName(element, false);
if (oldName != null) {
composite = getComposite(element, containingFile, null, oldName);
}
if (element instanceof PsiQualifiedNamedElement) {
oldName = getQualifiedName(element, true);
if (oldName != null) {
composite = getComposite(element, containingFile, composite, oldName);
}
}
return composite;
}
private static RefactoringElementListenerComposite getComposite(PsiElement element,
PsiFile containingFile,
RefactoringElementListenerComposite composite,
String oldName) {
for (final NamedScopesHolder holder : NamedScopesHolder.getAllNamedScopeHolders(element.getProject())) {
final NamedScope[] scopes = holder.getEditableScopes();
for (int i = 0; i < scopes.length; i++) {
@@ -56,13 +77,16 @@ public class RefactoringScopeElementListenerProvider implements RefactoringEleme
return composite;
}
private static String getQualifiedName(PsiElement element) {
if (element instanceof PsiQualifiedNamedElement) {
private static String getQualifiedName(PsiElement element, boolean acceptQNames) {
if (element instanceof PsiQualifiedNamedElement && acceptQNames) {
return ((PsiQualifiedNamedElement)element).getQualifiedName();
}
else {
final Project project = element.getProject();
final VirtualFile virtualFile = ((PsiDirectory)element).getVirtualFile();
final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
if (virtualFile == null) {
return null;
}
return FilePatternPackageSet.getRelativePath(virtualFile,
ProjectRootManager.getInstance(project).getFileIndex(),
true,
@@ -106,12 +130,16 @@ public class RefactoringScopeElementListenerProvider implements RefactoringEleme
public void elementRenamedOrMoved(@NotNull PsiElement newElement) {
LOG.assertTrue(newElement instanceof PsiQualifiedNamedElement || newElement instanceof PsiDirectory);
try {
final String newPattern = text.replace(descriptor.getOldQName(), getQualifiedName(newElement));
final PackageSet newSet = PackageSetFactory.getInstance().compile(newPattern);
NamedScope newScope = new NamedScope(descriptor.getScope().getName(), newSet);
final NamedScope[] currentScopes = descriptor.getHolder().getEditableScopes();
currentScopes[descriptor.getIdx()] = newScope;
descriptor.getHolder().setScopes(currentScopes);
final PackageSet currentPackageSet = currentScopes[descriptor.getIdx()].getValue();
final String qualifiedName = getQualifiedName(newElement, !(currentPackageSet instanceof FilePatternPackageSet));
if (qualifiedName != null) {
final String newPattern = text.replace(descriptor.getOldQName(), qualifiedName);
final PackageSet newSet = PackageSetFactory.getInstance().compile(newPattern);
NamedScope newScope = new NamedScope(descriptor.getScope().getName(), newSet);
currentScopes[descriptor.getIdx()] = newScope;
descriptor.getHolder().setScopes(currentScopes);
}
}
catch (ParsingException ignore) {
}
@@ -124,9 +152,7 @@ public class RefactoringScopeElementListenerProvider implements RefactoringEleme
final NamedScope[] currentScopes = descriptor.getHolder().getEditableScopes();
final PatternBasedPackageSet packageSet = (PatternBasedPackageSet)currentScopes[descriptor.getIdx()].getValue();
if (packageSet == null) return;
final String oldPattern = packageSet.getPattern().replace(getQualifiedName(newElement), oldQualifiedName);
final PackageSet newSet = PackageSetFactory.getInstance().compile(oldPattern);
NamedScope newScope = new NamedScope(descriptor.getScope().getName(), newSet);
NamedScope newScope = new NamedScope(descriptor.getScope().getName(), PackageSetFactory.getInstance().compile(text));
currentScopes[descriptor.getIdx()] = newScope;
descriptor.getHolder().setScopes(currentScopes);
}
@@ -19,10 +19,8 @@ import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.GraphicsConfig;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.JBInsets;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
@@ -39,8 +37,6 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -686,25 +682,10 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co
}
// 2. Waved effect
if (attributes.isWaved()) {
GraphicsConfig config = GraphicsUtil.setupAAPainting(g);
Stroke oldStroke = g.getStroke();
try {
g.setStroke(new BasicStroke(.7F));
if (attributes.getWaveColor() != null) {
g.setColor(attributes.getWaveColor());
}
final int wavedAt = textBaseline + 1;
GeneralPath wavePath = new GeneralPath(PathIterator.WIND_EVEN_ODD);
wavePath.moveTo(offset, wavedAt);
for (int x = offset; x <= offset + fragmentWidth; x += 4) {
wavePath.lineTo(x + 2, wavedAt + 2);
wavePath.lineTo(x + 4, wavedAt);
}
g.draw(wavePath);
} finally {
config.restore();
g.setStroke(oldStroke);
if (attributes.getWaveColor() != null) {
g.setColor(attributes.getWaveColor());
}
UIUtil.drawWave(g, new Rectangle(offset, textBaseline + 1, fragmentWidth, Math.max(2, metrics.getDescent())));
}
// 3. Underline
if (attributes.isUnderline()) {
@@ -86,6 +86,10 @@ public class InstallPluginAction extends AnAction implements DumbAware {
install(null);
}
public static boolean isInstalling(IdeaPluginDescriptor node) {
return ourInstallingNodes.contains(node);
}
public void install(@Nullable final Runnable onSuccess) {
IdeaPluginDescriptor[] selection = getPluginTable().getSelectedObjects();
@@ -141,10 +141,14 @@ public class PluginHeaderPanel {
myActionId = null;
}
}
UIUtil.setEnabled(myButtonPanel, true, true);
if (myManager == null || myActionId == null || (myManager.getInstalled() != myManager.getAvailable() && myActionId == ACTION_ID.UNINSTALL)) {
myActionId = ACTION_ID.INSTALL;
myButtonPanel.setVisible(false);
}
else if (InstallPluginAction.isInstalling(plugin)) {
UIUtil.setEnabled(myButtonPanel, false, true);
}
myRoot.revalidate();
((JComponent)myInstallButton.getParent()).revalidate();
myInstallButton.revalidate();
@@ -1713,7 +1713,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
else {
endVisLine = offsetToVisualLine(myDocument.getLineEndOffset(Math.min(myDocument.getLineCount() - 1, endLine)));
}
int height = endVisLine * getLineHeight() - yStartLine + getLineHeight() + WAVE_HEIGHT;
int height = endVisLine * getLineHeight() - yStartLine + getLineHeight() + 2;
myEditorComponent.repaintEditorComponent(visibleArea.x, yStartLine, visibleArea.x + visibleArea.width, height);
myGutterComponent.repaint(0, yStartLine, myGutterComponent.getWidth(), height);
@@ -2236,7 +2236,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int y = visibleLineToY(visibleStartLine) + getAscent() + 1;
g.setColor(attributes.getEffectColor());
if (attributes.getEffectType() == EffectType.WAVE_UNDERSCORE) {
drawWave(g, end.x, end.x + charWidth - 1, y);
UIUtil.drawWave((Graphics2D)g, new Rectangle(end.x, y, charWidth - 1, 2));
}
else if (attributes.getEffectType() == EffectType.BOLD_DOTTED_LINE) {
final int dottedAt = SystemInfo.isMac ? y - 1 : y;
@@ -3368,7 +3368,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
else if (effectType == EffectType.WAVE_UNDERSCORE) {
g.setColor(effectColor);
drawWave(g, xStart, xEnd, y + 1);
UIUtil.drawWave((Graphics2D)g, new Rectangle(xStart, y+1, xEnd - xStart, getDescent() - 1));
g.setColor(savedColor);
}
else if (effectType == EffectType.BOLD_DOTTED_LINE) {
@@ -3515,25 +3515,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
private static final int WAVE_HEIGHT = 2;
private static final int WAVE_SEGMENT_LENGTH = 4;
private static void drawWave(Graphics g, int xStart, int xEnd, int y) {
int startSegment = xStart / WAVE_SEGMENT_LENGTH;
int endSegment = xEnd / WAVE_SEGMENT_LENGTH;
for (int i = startSegment; i < endSegment; i++) {
drawWaveSegment(g, WAVE_SEGMENT_LENGTH * i, y);
}
int x = WAVE_SEGMENT_LENGTH * endSegment;
UIUtil.drawLine(g, x, y + WAVE_HEIGHT, x + WAVE_SEGMENT_LENGTH / 2, y);
}
private static void drawWaveSegment(Graphics g, int x, int y) {
UIUtil.drawLine(g, x, y + WAVE_HEIGHT, x + WAVE_SEGMENT_LENGTH / 2, y);
UIUtil.drawLine(g, x + WAVE_SEGMENT_LENGTH / 2, y, x + WAVE_SEGMENT_LENGTH, y + WAVE_HEIGHT);
}
private int getTextSegmentWidth(@NotNull CharSequence text,
int start,
int end,
@@ -48,7 +48,7 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear
@Override
public JComponent createComponent() {
myUpdatesSettingsPanel = new UpdatesSettingsPanel();
myUpdatesSettingsPanel.myCheckNow.setEnabled(myCheckNowEnabled);
myUpdatesSettingsPanel.myCheckNow.setVisible(myCheckNowEnabled);
return myUpdatesSettingsPanel.myPanel;
}
@@ -1,59 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl;
import com.intellij.ide.BrowserUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReferenceBase;
import org.jetbrains.annotations.NotNull;
public class UrlPsiReference extends PsiReferenceBase<PsiElement> {
public UrlPsiReference(PsiElement element) {
super(element);
}
protected String getUrl() {
return getValue();
}
public PsiElement resolve() {
return new FakePsiElement() {
public PsiElement getParent() {
return getElement();
}
@Override
public String getName() {
return getUrl();
}
@Override
public void navigate(boolean requestFocus) {
BrowserUtil.browse(getUrl());
}
};
}
@NotNull
public Object[] getVariants() {
return EMPTY_ARRAY;
}
@Override
public boolean isSoft() {
return true;
}
}
@@ -921,7 +921,7 @@ updates.more.info.button=&More Info...
updates.ignore.update.button=&Ignore This Update
updates.remind.later.button=&Remind Me Later
updates.buy.online.button=&Buy Upgrade Online
updates.new.version.available=<b>A new version of {0} is available!</b>
updates.new.version.available=<b>A new version of {0} is <a href=\"#\">available</a>!</b>
updates.current.version=Current version:
updates.available.version=New version:
updates.patch.label=Patch size:
@@ -40,6 +40,11 @@ public abstract class ServerRuntimeInstance<D extends DeploymentConfiguration> {
void addDeployment(@NotNull String deploymentName, @Nullable DeploymentRuntime deploymentRuntime);
void addDeployment(@NotNull String deploymentName,
@Nullable DeploymentRuntime deploymentRuntime,
@Nullable DeploymentStatus deploymentStatus,
@Nullable String deploymentStatusText);
void succeeded();
}
}
@@ -177,7 +177,19 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements
@Override
public void addDeployment(@NotNull String deploymentName, @Nullable DeploymentRuntime deploymentRuntime) {
myDeployments.add(new DeploymentImpl(deploymentName, DeploymentStatus.DEPLOYED, null, deploymentRuntime, null));
addDeployment(deploymentName, deploymentRuntime, null, null);
}
@Override
public void addDeployment(@NotNull String deploymentName,
@Nullable DeploymentRuntime deploymentRuntime,
@Nullable DeploymentStatus deploymentStatus,
@Nullable String deploymentStatusText) {
myDeployments.add(new DeploymentImpl(deploymentName,
deploymentStatus == null ? DeploymentStatus.DEPLOYED : deploymentStatus,
deploymentStatusText,
deploymentRuntime,
null));
}
@Override
@@ -16,6 +16,8 @@
package com.intellij.remoteServer.util;
import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime;
import com.intellij.remoteServer.runtime.deployment.DeploymentStatus;
import org.jetbrains.annotations.Nullable;
public abstract class CloudApplicationRuntime extends DeploymentRuntime {
@@ -28,4 +30,14 @@ public abstract class CloudApplicationRuntime extends DeploymentRuntime {
public String getApplicationName() {
return myApplicationName;
}
@Nullable
public DeploymentStatus getStatus() {
return null;
}
@Nullable
public String getStatusText() {
return null;
}
}
@@ -95,7 +95,7 @@ public abstract class CloudServerRuntimeInstance
public void run() throws Exception {
try {
for (CloudApplicationRuntime application : getApplications()) {
callback.addDeployment(application.getApplicationName(), application);
callback.addDeployment(application.getApplicationName(), application, application.getStatus(), application.getStatusText());
}
callback.succeeded();
}
@@ -2,7 +2,6 @@ package com.intellij.structuralsearch;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.*;
import com.intellij.openapi.fileTypes.impl.AbstractFileType;
import com.intellij.psi.PsiElement;
import com.intellij.structuralsearch.impl.matcher.MatchUtils;
import com.intellij.structuralsearch.plugin.ui.Configuration;
@@ -67,7 +66,7 @@ public class StructuralSearchUtil {
ourDefaultFileType = StdFileTypes.XML;
}
}
assert isValidFileType(ourDefaultFileType) : "file type not valid for structural search: " + ourDefaultFileType.getName();
assert ourDefaultFileType instanceof LanguageFileType : "file type not valid for structural search: " + ourDefaultFileType.getName();
return ourDefaultFileType;
}
@@ -116,7 +115,7 @@ public class StructuralSearchUtil {
List<FileType> result = new ArrayList<FileType>();
for (FileType fileType : allFileTypes) {
if (isValidFileType(fileType)) {
if (fileType instanceof LanguageFileType) {
result.add(fileType);
}
}
@@ -124,19 +123,6 @@ public class StructuralSearchUtil {
return result.toArray(new FileType[result.size()]);
}
private static boolean isValidFileType(FileType fileType) {
return fileType != StdFileTypes.GUI_DESIGNER_FORM &&
fileType != StdFileTypes.IDEA_MODULE &&
fileType != StdFileTypes.IDEA_PROJECT &&
fileType != StdFileTypes.IDEA_WORKSPACE &&
fileType != FileTypes.ARCHIVE &&
fileType != FileTypes.UNKNOWN &&
fileType != FileTypes.PLAIN_TEXT &&
!(fileType instanceof AbstractFileType) &&
!fileType.isBinary() &&
!fileType.isReadOnly();
}
public static String shieldSpecialChars(String word) {
final StringBuilder buf = new StringBuilder(word.length());
@@ -145,10 +145,7 @@ public class MatcherImpl {
visitor.matchContext(matchedNodes);
} finally {
matchedNodes.reset();
final MatchOptions options = matchContext.getOptions();
if (options != null) {
options.setScope(null);
}
context.getOptions().setScope(null);
}
}
@@ -2446,10 +2446,11 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
assertEquals("Find all annotations", 4, findMatchesCount(source2, "@'_Annotation"));
String source3 = "class A {\n" +
" @HH final String s = (@HH String) new Object();\n" +
" @HH final String s = (@HH String) new @HH Object();\n" +
" final String t = (String) new Object();\n" +
"}\n";
assertEquals("Find annotated casts", 1, findMatchesCount(source3, "(@'_A 'Cast) '_Expression"));
assertEquals("Find annotated new expressions", 1, findMatchesCount(source3, "new @'_A 'Type()"));
}
public void testBoxingAndUnboxing() {
@@ -2954,6 +2955,9 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
String pattern5 = "()->{/*comment*/}";
assertEquals("should find lambdas with comment body", 1, findMatchesCount(source, pattern5));
String pattern6 = "('_Parameter+) -> System.out.println()";
assertEquals("should find lambdas with at least one parameter and matching body", 0, findMatchesCount(source, pattern6));
}
public void testFindDefaultMethods() {
@@ -19,6 +19,7 @@ import com.intellij.BundleBase;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.GraphicsConfig;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
@@ -57,6 +58,7 @@ import javax.swing.undo.UndoManager;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.GeneralPath;
import java.awt.im.InputContext;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
@@ -590,6 +592,26 @@ public class UIUtil {
}
}
public static void drawWave(Graphics2D g, Rectangle rectangle) {
GraphicsConfig config = GraphicsUtil.setupAAPainting(g);
Stroke oldStroke = g.getStroke();
try {
g.setStroke(new BasicStroke(0.7F));
double cycle = 4;
final double wavedAt = rectangle.y + (double)rectangle.height /2 - .5;
GeneralPath wavePath = new GeneralPath();
wavePath.moveTo(rectangle.x, wavedAt - Math.cos(rectangle.x * 2 * Math.PI / cycle));
for (int x = rectangle.x + 1; x <= rectangle.x + rectangle.width; x++) {
wavePath.lineTo(x, wavedAt - Math.cos(x * 2 * Math.PI / cycle) );
}
g.draw(wavePath);
}
finally {
config.restore();
g.setStroke(oldStroke);
}
}
@NotNull
public static String[] splitText(String text, FontMetrics fontMetrics, int widthLimit, char separator) {
ArrayList<String> lines = new ArrayList<String>();
Binary file not shown.
Binary file not shown.
@@ -99,6 +99,7 @@ public class JaCoCoCoverageRunner extends JavaCoverageRunner {
for (int i = firstLine; i <= lastLine; i++) {
final ILine methodLine = method.getLine(i);
final int methodLineStatus = methodLine.getStatus();
if (methodLineStatus == ICounter.EMPTY) continue;
final LineData lineData = new LineData(i , desc) {
@Override
public int getStatus() {
@@ -91,7 +91,7 @@
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="4d15a" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="4d15a" layout-manager="GridLayoutManager" row-count="7" column-count="8" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -99,27 +99,9 @@
<properties/>
<border type="none"/>
<children>
<component id="9d661" class="javax.swing.JCheckBox" binding="myAutoUpdateIfPushRejected">
<constraints>
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<iconTextGap value="4"/>
<text value="Auto-update if &amp;push of the current branch was rejected"/>
</properties>
</component>
<component id="2e80d" class="com.intellij.ui.components.JBCheckBox" binding="mySyncControl">
<constraints>
<grid row="2" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="com/intellij/dvcs/ui/DvcsBundle" key="sync.setting"/>
<toolTipText value=""/>
</properties>
</component>
<component id="5a98" class="javax.swing.JCheckBox" binding="myAutoCommitOnCherryPick">
<constraints>
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="1" column="0" row-span="1" col-span="8" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<iconTextGap value="4"/>
@@ -128,7 +110,7 @@
</component>
<component id="1ad55" class="com.intellij.ui.components.JBCheckBox" binding="myWarnAboutCrlf" default-binding="true">
<constraints>
<grid row="3" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="8" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Warn if &amp;CRLF line separators are about to be committed"/>
@@ -136,7 +118,7 @@
</component>
<component id="29d5c" class="javax.swing.JCheckBox" binding="myWarnAboutDetachedHead">
<constraints>
<grid row="4" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="3" column="0" row-span="1" col-span="8" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
@@ -145,7 +127,7 @@
</component>
<component id="885e3" class="javax.swing.JCheckBox" binding="myEnableForcePush">
<constraints>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="6" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
@@ -154,7 +136,7 @@
</component>
<component id="b0317" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myProtectedBranchesButton" custom-create="true" default-binding="true">
<constraints>
<grid row="5" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
<grid row="6" column="7" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value=""/>
@@ -162,12 +144,45 @@
</component>
<component id="e7b92" class="com.intellij.ui.components.JBLabel" binding="myProtectedBranchesLabel">
<constraints>
<grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
<grid row="6" column="6" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Protected branches:"/>
</properties>
</component>
<component id="2e80d" class="com.intellij.ui.components.JBCheckBox" binding="mySyncControl">
<constraints>
<grid row="0" column="0" row-span="1" col-span="8" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="com/intellij/dvcs/ui/DvcsBundle" key="sync.setting"/>
<toolTipText value=""/>
</properties>
</component>
<component id="5884f" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
</constraints>
<properties>
<labelFor value="840a6"/>
<text value="Update method:"/>
</properties>
</component>
<component id="9d661" class="javax.swing.JCheckBox" binding="myAutoUpdateIfPushRejected">
<constraints>
<grid row="5" column="0" row-span="1" col-span="8" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<iconTextGap value="4"/>
<text value="Auto-update if &amp;push of the current branch was rejected"/>
</properties>
</component>
<component id="840a6" class="javax.swing.JComboBox" binding="myUpdateMethodComboBox" custom-create="true" default-binding="true">
<constraints>
<grid row="4" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
</children>
</grid>
</children>
@@ -22,12 +22,15 @@ import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.ui.EnumComboBoxModel;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.execution.ParametersListUtil;
import com.intellij.util.ui.UIUtil;
import git4idea.GitVcs;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitRepositoryManager;
@@ -36,6 +39,8 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.List;
/**
@@ -61,6 +66,7 @@ public class GitVcsPanel {
private JCheckBox myEnableForcePush;
private TextFieldWithBrowseButton myProtectedBranchesButton;
private JBLabel myProtectedBranchesLabel;
private JComboBox myUpdateMethodComboBox;
public GitVcsPanel(@NotNull Project project) {
myVcs = GitVcs.getInstance(project);
@@ -81,6 +87,13 @@ public class GitVcsPanel {
mySyncControl.setVisible(repositoryManager != null && repositoryManager.moreThanOneRoot());
mySyncControl.setToolTipText(DvcsBundle.message("sync.setting.description", "Git"));
myProtectedBranchesLabel.setLabelFor(myProtectedBranchesButton);
myEnableForcePush.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
UIUtil.setEnabled(myProtectedBranchesButton, myEnableForcePush.isSelected(), true);
UIUtil.setEnabled(myProtectedBranchesLabel, myEnableForcePush.isSelected(), false);
}
});
}
/**
@@ -135,6 +148,7 @@ public class GitVcsPanel {
myWarnAboutCrlf.setSelected(settings.warnAboutCrlf());
myWarnAboutDetachedHead.setSelected(settings.warnAboutDetachedHead());
myEnableForcePush.setSelected(settings.isForcePushAllowed());
myUpdateMethodComboBox.setSelectedItem(settings.getUpdateType());
myProtectedBranchesButton.setText(ParametersListUtil.COLON_LINE_JOINER.fun(sharedSettings.getForcePushProhibitedPatterns()));
}
@@ -152,6 +166,7 @@ public class GitVcsPanel {
settings.warnAboutCrlf() != myWarnAboutCrlf.isSelected() ||
settings.warnAboutDetachedHead() != myWarnAboutDetachedHead.isSelected() ||
settings.isForcePushAllowed() != myEnableForcePush.isSelected() ||
settings.getUpdateType() != myUpdateMethodComboBox.getModel().getSelectedItem() ||
!ContainerUtil.sorted(sharedSettings.getForcePushProhibitedPatterns()).equals(
ContainerUtil.sorted(getProtectedBranchesPatterns())));
}
@@ -174,6 +189,7 @@ public class GitVcsPanel {
settings.setWarnAboutCrlf(myWarnAboutCrlf.isSelected());
settings.setWarnAboutDetachedHead(myWarnAboutDetachedHead.isSelected());
settings.setForcePushAllowed(myEnableForcePush.isSelected());
settings.setUpdateType((UpdateMethod)myUpdateMethodComboBox.getSelectedItem());
sharedSettings.setForcePushProhibitedPatters(getProtectedBranchesPatterns());
}
@@ -191,5 +207,6 @@ public class GitVcsPanel {
}
});
myProtectedBranchesButton.setButtonIcon(AllIcons.Actions.ShowViewer);
myUpdateMethodComboBox = new ComboBox(new EnumComboBoxModel<UpdateMethod>(UpdateMethod.class));
}
}
@@ -68,6 +68,7 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
public UpdateChangesPolicy UPDATE_CHANGES_POLICY = UpdateChangesPolicy.STASH;
public UpdateMethod UPDATE_TYPE = UpdateMethod.BRANCH_DEFAULT;
public boolean PUSH_AUTO_UPDATE = false;
public boolean PUSH_UPDATE_ALL_ROOTS = true;
public Value ROOT_SYNC = Value.NOT_DECIDED;
public String RECENT_GIT_ROOT_PATH = null;
public Map<String, String> RECENT_BRANCH_BY_REPOSITORY = new HashMap<String, String>();
@@ -96,8 +97,9 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
return PeriodicalTasksCloser.getInstance().safeGetService(project, GitVcsSettings.class);
}
@NotNull
public UpdateMethod getUpdateType() {
return myState.UPDATE_TYPE;
return ObjectUtils.notNull(myState.UPDATE_TYPE, UpdateMethod.BRANCH_DEFAULT);
}
public void setUpdateType(UpdateMethod updateType) {
@@ -146,6 +148,14 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
myState.PUSH_AUTO_UPDATE = autoUpdate;
}
public boolean shouldUpdateAllRootsIfPushRejected() {
return myState.PUSH_UPDATE_ALL_ROOTS;
}
public void setUpdateAllRootsIfPushRejected(boolean updateAllRoots) {
myState.PUSH_UPDATE_ALL_ROOTS = updateAllRoots;
}
@NotNull
public Value getSyncSetting() {
return myState.ROOT_SYNC;
@@ -15,6 +15,8 @@
*/
package git4idea.config;
import com.intellij.openapi.util.text.StringUtil;
/**
* The type of update to perform
*/
@@ -30,5 +32,10 @@ public enum UpdateMethod {
/**
* Rebase local commits upon the fetched branch
*/
REBASE
REBASE;
@Override
public String toString() {
return StringUtil.capitalize(StringUtil.toLowerCase(name().replace('_', ' ')));
}
}
@@ -49,7 +49,6 @@ import git4idea.merge.MergeChangeCollector;
import git4idea.repo.GitBranchTrackInfo;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
import git4idea.settings.GitPushSettings;
import git4idea.update.GitRebaseOverMergeProblem;
import git4idea.update.GitUpdateProcess;
import git4idea.update.GitUpdateResult;
@@ -80,7 +79,6 @@ public class GitPushOperation {
private final Git myGit;
private final ProgressIndicator myProgressIndicator;
private final GitVcsSettings mySettings;
private final GitPushSettings myPushSettings;
private final GitPlatformFacade myPlatformFacade;
private final GitRepositoryManager myRepositoryManager;
@@ -97,7 +95,6 @@ public class GitPushOperation {
myGit = ServiceManager.getService(Git.class);
myProgressIndicator = ObjectUtils.notNull(ProgressManager.getInstance().getProgressIndicator(), new EmptyProgressIndicator());
mySettings = GitVcsSettings.getInstance(myProject);
myPushSettings = GitPushSettings.getInstance(myProject);
myPlatformFacade = ServiceManager.getService(project, GitPlatformFacade.class);
myRepositoryManager = ServiceManager.getService(myProject, GitRepositoryManager.class);
@@ -154,7 +151,7 @@ public class GitPushOperation {
updateSettings = showDialogAndGetExitCode(result.rejected.keySet(), updateSettings,
rebaseOverMergeProblemDetected.booleanValue());
if (updateSettings != null) {
savePushUpdateSettings(updateSettings);
savePushUpdateSettings(updateSettings, rebaseOverMergeProblemDetected.booleanValue());
}
else {
shouldUpdate = false;
@@ -383,16 +380,18 @@ public class GitPushOperation {
});
}
private void savePushUpdateSettings(@NotNull PushUpdateSettings settings) {
private void savePushUpdateSettings(@NotNull PushUpdateSettings settings, boolean rebaseOverMergeDetected) {
UpdateMethod updateMethod = settings.getUpdateMethod();
myPushSettings.setUpdateAllRoots(settings.shouldUpdateAllRoots());
myPushSettings.setUpdateMethod(updateMethod);
mySettings.setUpdateAllRootsIfPushRejected(settings.shouldUpdateAllRoots());
if (!rebaseOverMergeDetected) { // don't overwrite explicit "rebase" with temporary "merge" caused by merge commits
mySettings.setUpdateType(updateMethod);
}
}
@NotNull
private PushUpdateSettings readPushUpdateSettings() {
boolean updateAllRoots = myPushSettings.shouldUpdateAllRoots();
UpdateMethod updateMethod = myPushSettings.getUpdateMethod();
boolean updateAllRoots = mySettings.shouldUpdateAllRootsIfPushRejected();
UpdateMethod updateMethod = mySettings.getUpdateType();
return new PushUpdateSettings(updateAllRoots, updateMethod);
}
@@ -73,18 +73,28 @@ class GitRejectedPushUpdateDialog extends DialogWrapper {
myMergeAction = new MergeAction();
myRebaseAction = new RebaseAction();
getDefaultAction(initialSettings.getUpdateMethod()).putValue(DEFAULT_ACTION, Boolean.TRUE);
getCancelAction().putValue(FOCUSED_ACTION, Boolean.TRUE);
setDefaultAndFocusedActions(initialSettings.getUpdateMethod());
init();
setTitle("Push Rejected");
}
private AbstractAction getDefaultAction(@Nullable UpdateMethod updateMethod) {
if (updateMethod == UpdateMethod.REBASE && !myRebaseOverMergeProblemDetected) {
return myRebaseAction;
private void setDefaultAndFocusedActions(@Nullable UpdateMethod updateMethod) {
Action defaultAction;
Action focusedAction;
if (myRebaseOverMergeProblemDetected) {
defaultAction = myMergeAction;
focusedAction = getCancelAction();
}
return myMergeAction;
else if (updateMethod == UpdateMethod.REBASE) {
defaultAction = myRebaseAction;
focusedAction = myMergeAction;
}
else {
defaultAction = myMergeAction;
focusedAction = myRebaseAction;
}
defaultAction.putValue(DEFAULT_ACTION, Boolean.TRUE);
focusedAction.putValue(FOCUSED_ACTION, Boolean.TRUE);
}
@Override
@@ -1,70 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.settings;
import com.intellij.openapi.components.*;
import com.intellij.openapi.project.Project;
import com.intellij.util.ObjectUtils;
import git4idea.config.UpdateMethod;
import org.jetbrains.annotations.NotNull;
/**
* @author Kirill Likhodedov
*/
@State(name = "Git.Push.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
public class GitPushSettings implements PersistentStateComponent<GitPushSettings.State> {
private static final UpdateMethod DEFAULT_UPDATE_METHOD = UpdateMethod.MERGE;
private State myState = new State();
public static class State {
public boolean myUpdateAllRoots = true;
public UpdateMethod myUpdateMethod = DEFAULT_UPDATE_METHOD;
}
public static GitPushSettings getInstance(Project project) {
return ServiceManager.getService(project, GitPushSettings.class);
}
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
public boolean shouldUpdateAllRoots() {
return myState.myUpdateAllRoots;
}
public void setUpdateAllRoots(boolean updateAllRoots) {
myState.myUpdateAllRoots = updateAllRoots;
}
@NotNull
public UpdateMethod getUpdateMethod() {
return ObjectUtils.notNull(myState.myUpdateMethod, DEFAULT_UPDATE_METHOD);
}
public void setUpdateMethod(@NotNull UpdateMethod updateMethod) {
myState.myUpdateMethod = updateMethod;
}
}
@@ -29,7 +29,6 @@ import com.intellij.util.containers.ContainerUtil;
import git4idea.branch.GitBranchUtil;
import git4idea.config.UpdateMethod;
import git4idea.repo.GitRepository;
import git4idea.settings.GitPushSettings;
import git4idea.test.TestDialogHandler;
import git4idea.test.TestMessageHandler;
import git4idea.update.GitRebaseOverMergeProblem;
@@ -255,13 +254,7 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
}
public void test_warn_if_rebasing_over_merge() throws IOException {
pushCommitFromBro();
cd(myRepository);
git("checkout -b branch1");
makeCommit("branch1.txt");
git("checkout master");
makeCommit("master.txt");
git("merge branch1");
generateUnpushedMergedCommitProblem();
final Ref<Boolean> rebaseOverMergeProblemDetected = Ref.create(false);
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@@ -276,16 +269,10 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
}
public void test_warn_if_silently_rebasing_over_merge() throws IOException {
pushCommitFromBro();
cd(myRepository);
git("checkout -b branch1");
makeCommit("branch1.txt");
git("checkout master");
makeCommit("master.txt");
git("merge branch1");
generateUnpushedMergedCommitProblem();
myGitSettings.setAutoUpdateIfPushRejected(true);
GitPushSettings.getInstance(myProject).setUpdateMethod(UpdateMethod.REBASE);
myGitSettings.setUpdateType(UpdateMethod.REBASE);
final Ref<Boolean> rebaseOverMergeProblemDetected = Ref.create(false);
myDialogManager.registerMessageHandler(new TestMessageHandler() {
@@ -299,6 +286,35 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
assertTrue(rebaseOverMergeProblemDetected.get());
}
public void test_dont_overwrite_rebase_setting_when_chose_to_merge_due_to_unpushed_merge_commits() throws IOException {
generateUnpushedMergedCommitProblem();
myGitSettings.setUpdateType(UpdateMethod.REBASE);
final Ref<Boolean> rebaseOverMergeProblemDetected = Ref.create(false);
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(@NotNull GitRejectedPushUpdateDialog dialog) {
rebaseOverMergeProblemDetected.set(dialog.warnsAboutRebaseOverMerge());
return GitRejectedPushUpdateDialog.MERGE_EXIT_CODE;
}
});
push("master", "origin/master");
assertTrue(rebaseOverMergeProblemDetected.get());
assertEquals("Update method was overwritten by temporary update-via-merge decision",
UpdateMethod.REBASE, myGitSettings.getUpdateType());
}
private void generateUnpushedMergedCommitProblem() throws IOException {
pushCommitFromBro();
cd(myRepository);
git("checkout -b branch1");
makeCommit("branch1.txt");
git("checkout master");
makeCommit("master.txt");
git("merge branch1");
}
@NotNull
private GitPushResult push(@NotNull String from, @NotNull String to) {
return push(from, to, false);
@@ -56,6 +56,12 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
@NonNls public static final String TEST_DIRECTORY = "directory";
@NonNls public static final String TEST_CATEGORY = "category";
@NonNls public static final String TEST_METHOD = "method";
//fork modes
@NonNls public static final String FORK_NONE = "none";
@NonNls public static final String FORK_METHOD = "method";
@NonNls public static final String FORK_KLASS = "class";
@NonNls private static final String PATTERN_EL_NAME = "pattern";
@NonNls public static final String TEST_PATTERN = PATTERN_EL_NAME;
@@ -56,6 +56,10 @@ public class TestClassConfigurationProducer extends JUnitConfigurationProducer {
final Module originalModule = configuration.getConfigurationModule().getModule();
configuration.beClassConfiguration(testClass);
configuration.restoreOriginalModule(originalModule);
final String forkMode = configuration.getForkMode();
if (JUnitConfiguration.FORK_KLASS.equals(forkMode)) {
configuration.setForkMode(JUnitConfiguration.FORK_NONE);
}
return true;
}
@@ -62,6 +62,7 @@ public class TestMethodConfigurationProducer extends JUnitConfigurationProducer
configuration.beMethodConfiguration(methodLocation);
configuration.restoreOriginalModule(originalModule);
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, contextLocation);
configuration.setForkMode(JUnitConfiguration.FORK_NONE);
return true;
}
@@ -53,7 +53,6 @@ import com.intellij.util.IconUtil;
import com.intellij.util.TextFieldCompletionProvider;
import com.intellij.util.ui.UIUtil;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -105,11 +104,8 @@ public class JUnitConfigurable extends SettingsEditor<JUnitConfiguration> implem
private JComboBox myTypeChooser;
private JBLabel mySearchForTestsLabel;
private JPanel myScopesPanel;
@NonNls private static final String NONE = "none";
@NonNls private static final String METHOD = "method";
@NonNls private static final String KLASS = "class";
private static final String[] FORK_MODE_ALL = {NONE, METHOD, KLASS};
private static final String[] FORK_MODE = {NONE, METHOD};
private static final String[] FORK_MODE_ALL = {JUnitConfiguration.FORK_NONE, JUnitConfiguration.FORK_METHOD, JUnitConfiguration.FORK_KLASS};
private static final String[] FORK_MODE = {JUnitConfiguration.FORK_NONE, JUnitConfiguration.FORK_METHOD};
private Project myProject;
private JComponent anchor;
@@ -273,7 +269,7 @@ public class JUnitConfigurable extends SettingsEditor<JUnitConfiguration> implem
private void changePanel () {
String selectedItem = (String)myForkCb.getSelectedItem();
if (selectedItem == null) {
selectedItem = NONE;
selectedItem = JUnitConfiguration.FORK_NONE;
}
final Integer selectedType = (Integer)myTypeChooser.getSelectedItem();
if (selectedType == JUnitConfigurationModel.ALL_IN_PACKAGE) {
@@ -309,7 +305,7 @@ public class JUnitConfigurable extends SettingsEditor<JUnitConfiguration> implem
myMethod.setVisible(false);
myForkCb.setEnabled(true);
myForkCb.setModel(new DefaultComboBoxModel(FORK_MODE));
myForkCb.setSelectedItem(selectedItem != KLASS ? selectedItem : METHOD);
myForkCb.setSelectedItem(selectedItem != JUnitConfiguration.FORK_KLASS ? selectedItem : JUnitConfiguration.FORK_METHOD);
}
else if (selectedType == JUnitConfigurationModel.METHOD){
myPackagePanel.setVisible(false);
@@ -320,7 +316,7 @@ public class JUnitConfigurable extends SettingsEditor<JUnitConfiguration> implem
myCategory.setVisible(false);
myMethod.setVisible(true);
myForkCb.setEnabled(false);
myForkCb.setSelectedItem(NONE);
myForkCb.setSelectedItem(JUnitConfiguration.FORK_NONE);
} else if (selectedType == JUnitConfigurationModel.CATEGORY) {
myPackagePanel.setVisible(false);
myScopesPanel.setVisible(true);
@@ -15,10 +15,10 @@
*/
package org.jetbrains.idea.maven.dom.converters;
import com.intellij.openapi.paths.WebReference;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.UrlPsiReference;
import com.intellij.util.xml.ConvertContext;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
@@ -35,6 +35,6 @@ public class MavenUrlConverter extends MavenReferenceConverter<String> {
}
protected PsiReference createReference(PsiElement element, String text, TextRange range) {
return new UrlPsiReference(element);
return new WebReference(element, range);
}
}
@@ -18,10 +18,10 @@ package org.jetbrains.idea.maven.dom.converters.repositories;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.paths.WebReference;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.UrlPsiReference;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.GenericDomValue;
import com.intellij.util.xml.ResolvingConverter;
@@ -76,8 +76,7 @@ public abstract class MavenRepositoryConverter extends ResolvingConverter<String
@NotNull
@Override
public PsiReference[] createReferences(GenericDomValue value, final PsiElement element, final ConvertContext context) {
return new PsiReference[]{new UrlPsiReference(element) {
return new PsiReference[]{new WebReference(element) {
@NotNull
@Override
public Object[] getVariants() {
@@ -8,9 +8,11 @@ import com.intellij.execution.process.KillableColoredProcessHandler;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ProjectFileIndex;
@@ -23,6 +25,8 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.HyperlinkAdapter;
import com.intellij.util.Alarm;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
@@ -35,11 +39,12 @@ import org.jetbrains.plugins.ipnb.format.cells.output.IpnbOutputCell;
import org.jetbrains.plugins.ipnb.protocol.IpnbConnection;
import org.jetbrains.plugins.ipnb.protocol.IpnbConnectionListenerBase;
import java.io.BufferedReader;
import javax.swing.event.HyperlinkEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -67,7 +72,13 @@ public final class IpnbConnectionManager implements ProjectComponent {
if (!myKernels.containsKey(path)) {
String url = IpnbSettings.getInstance(myProject).getURL();
if (StringUtil.isEmptyOrSpaces(url)) {
showWarning(fileEditor, "Please, specify IPython Notebook URL in <a href=\"\">Settings->IPython Notebook</a>");
showWarning(fileEditor, "Please, specify IPython Notebook URL in <a href=\"\">Settings->Tools->IPython Notebook</a>",
new HyperlinkAdapter() {
@Override
protected void hyperlinkActivated(HyperlinkEvent e) {
ShowSettingsUtil.getInstance().showSettingsDialog(myProject, "IPython Notebook");
}
});
return;
}
if (startConnection(codePanel, path, url, false)) {
@@ -78,20 +89,33 @@ public final class IpnbConnectionManager implements ProjectComponent {
IpnbSettings.getInstance(myProject).setURL(url);
boolean connectionStarted = startConnection(codePanel, path, url, false);
if (!connectionStarted) {
final boolean serverStarted = startIpythonServer(url, fileEditor);
if (!serverStarted) {
return;
}
waitForIpythonServer();
final Notification notification =
new Notification("IPythonNotebook", "", "<html>IPython notebook started at <a href=\"" + url +
"\">" + url + "</a></html>", NotificationType.INFORMATION,
NotificationListener.URL_OPENING_LISTENER);
notification.notify(myProject);
IpnbSettings.getInstance(myProject).setURL(url);
final String finalUrl = url;
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
final boolean serverStarted = startIpythonServer(finalUrl, fileEditor);
if (!serverStarted) {
return;
}
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
new Alarm(Alarm.ThreadToUse.SWING_THREAD).addRequest(new Runnable() {
@Override
public void run() {
final Notification notification =
new Notification("IPythonNotebook", "", "<html>IPython notebook started at <a href=\"" + finalUrl +
"\">" + finalUrl + "</a></html>", NotificationType.INFORMATION,
NotificationListener.URL_OPENING_LISTENER);
notification.notify(myProject);
startConnection(codePanel, path, finalUrl, true);
}
}, 3000);
}
});
}
});
}
startConnection(codePanel, path, url, true);
}
else {
final IpnbConnection connection = myKernels.get(path);
@@ -102,52 +126,25 @@ public final class IpnbConnectionManager implements ProjectComponent {
}
}
private void waitForIpythonServer() {
final long startTime = System.currentTimeMillis();
final InputStream stream = myProcessHandler.getProcess().getErrorStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
try {
long time = System.currentTimeMillis() - startTime;
while (time < 50000) {
final String line = reader.readLine();
if (line != null && line.contains("The IPython Notebook is running")) {
break;
}
time = System.currentTimeMillis() - startTime;
}
}
catch (IOException ignored) {
}
finally {
try {
reader.close();
}
catch (IOException ignored) {
}
}
}
private static String showDialogUrl(@NotNull final String initialUrl) {
final String url = Messages.showInputDialog("IPython Notebook URL:", "Start IPython Notebook", null, initialUrl,
new InputValidator() {
@Override
public boolean checkInput(String inputString) {
try {
new URL(inputString);
new InputValidator() {
@Override
public boolean checkInput(String inputString) {
try {
new URL(inputString);
}
catch (MalformedURLException e) {
return false;
}
return !inputString.isEmpty();
}
catch (MalformedURLException e) {
return false;
}
return !inputString.isEmpty();
}
@Override
public boolean canClose(String inputString) {
return true;
}
});
@Override
public boolean canClose(String inputString) {
return true;
}
});
return url == null ? null : StringUtil.trimEnd(url, "/");
}
@@ -176,7 +173,13 @@ public final class IpnbConnectionManager implements ProjectComponent {
}
catch (URISyntaxException e) {
if (showNotification)
showWarning(codePanel.getFileEditor(), "Please, check IPython Notebook URL in Settings->IPython Notebook");
showWarning(codePanel.getFileEditor(), "Please, check IPython Notebook URL in <a href=\"\">Settings->Tools->IPython Notebook</a>",
new HyperlinkAdapter() {
@Override
protected void hyperlinkActivated(HyperlinkEvent e) {
ShowSettingsUtil.getInstance().showSettingsDialog(myProject, "IPython Notebook");
}
});
LOG.warn("IPython Notebook URI Syntax Error: " + e.getMessage());
return false;
}
@@ -189,13 +192,18 @@ public final class IpnbConnectionManager implements ProjectComponent {
return true;
}
private static void showWarning(@NotNull final IpnbFileEditor fileEditor, @NotNull final String message) {
private static void showWarning(@NotNull final IpnbFileEditor fileEditor, @NotNull final String message,
@Nullable final HyperlinkAdapter listener) {
BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(
message, null, MessageType.WARNING.getPopupBackground(), null);
message, null, MessageType.WARNING.getPopupBackground(), listener);
final Balloon balloon = balloonBuilder.createBalloon();
balloon.showInCenterOf(fileEditor.getRunCellButton());
}
private static void showWarning(@NotNull final IpnbFileEditor fileEditor, @NotNull final String message) {
showWarning(fileEditor, message, null);
}
private boolean startIpythonServer(@NotNull final String url, @NotNull final IpnbFileEditor fileEditor) {
final Module module = ProjectFileIndex.SERVICE.getInstance(myProject).getModuleForFile(fileEditor.getVirtualFile());
if (module == null) return false;
@@ -22,7 +22,19 @@ public class IpnbPyParser extends PyParser {
@NotNull
@Override
public ASTNode parse(IElementType root, PsiBuilder builder) {
final PsiBuilder.Marker rootMarker = builder.mark();
myIPythonStartSymbol = PyConsoleParser.startsWithIPythonSpecialSymbol(builder);
return super.parse(root, builder);
ParsingContext context = createParsingContext(builder, LanguageLevel.getDefault(), null);
StatementParsing statementParser = context.getStatementParser();
builder.setTokenTypeRemapper(statementParser);
while (!builder.eof()) {
statementParser.parseStatement(context.emptyParsingScope());
}
rootMarker.done(root);
return builder.getTreeBuilt();
}
}
@@ -45,6 +45,11 @@ public class PyCustomMember {
boolean myFunction = false;
/**
* Force resolving to {@link MyInstanceElement} even if element is function
*/
private boolean myAlwaysResolveToCustomElement;
public PyCustomMember(@NotNull final String name, @Nullable final String type, final boolean resolveToInstance) {
myName = name;
myResolveToInstance = resolveToInstance;
@@ -82,6 +87,7 @@ public class PyCustomMember {
myTypeName = typeName;
myTypeCallback = null;
}
public PyCustomMember(@NotNull final String name, @Nullable final PsiElement target) {
this(name, target, null);
}
@@ -96,6 +102,15 @@ public class PyCustomMember {
return this;
}
/**
* Force resolving to {@link MyInstanceElement} even if element is function
*/
@NotNull
public final PyCustomMember alwaysResolveToCustomElement() {
myAlwaysResolveToCustomElement = true;
return this;
}
public PyCustomMember toClass(String name) {
myPsiPath = new PyPsiPath.ToClass(myPsiPath, name);
return this;
@@ -156,7 +171,7 @@ public class PyCustomMember {
PyClass targetClass =
myTypeName != null && myTypeName.indexOf('.') > 0 ? PyPsiFacade.getInstance(context.getProject()).findClass(myTypeName) : null;
final PsiElement resolveTarget = findResolveTarget(context);
if (resolveTarget instanceof PyFunction) {
if (resolveTarget instanceof PyFunction && !myAlwaysResolveToCustomElement) {
return resolveTarget;
}
if (resolveTarget != null || targetClass != null) {
@@ -211,4 +226,4 @@ public class PyCustomMember {
return null;
}
}
}
}
@@ -30,7 +30,7 @@ public interface PyClassMembersProvider {
ExtensionPointName<PyClassMembersProvider> EP_NAME = ExtensionPointName.create("Pythonid.pyClassMembersProvider");
@NotNull
Collection<PyCustomMember> getMembers(PyClassType clazz, @Nullable PsiElement location);
Collection<PyCustomMember> getMembers(final PyClassType clazz, PsiElement location);
@Nullable
PsiElement resolveMember(PyClassType clazz, String name, @Nullable PsiElement location);
@@ -102,6 +102,7 @@ public class PyTypeProviderBase implements PyTypeProvider {
return null;
}
@Nullable
@Override
public PyType getCallType(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
ReturnTypeDescriptor descriptor;
@@ -191,7 +191,7 @@ public class TypeEvalContext {
}
}
final PyType type = element.getType(this, Key.INSTANCE);
assertValid(type, element);
assertValid(type, element);
synchronized (myEvaluated) {
myEvaluated.put(element, type);
}
@@ -850,5 +850,4 @@ remote.interpreter.configure.path.label=Python interpreter path:
remote.interpreter.configure.temp.files.path.label=PyCharm helpers path:
# Message we display for inspection if user uses custom class type members that do not exist
custom.type.name=Dynamic class
custom.type.mimic.name=Dynamic class based on {0}
@@ -1,204 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.codeInsight.PyCustomMember;
import com.jetbrains.python.codeInsight.PyCustomMemberUtils;
import com.jetbrains.python.psi.AccessDirection;
import com.jetbrains.python.psi.PyCallSiteExpression;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Custom (aka dynamic) type that has some members you pass to it. To be used for cases like "type()"
* This class can also mimic any other class (optionally). When mimics, it has all methods from this class and its own.
* @author Ilya.Kazakevich
*/
public class PyCustomMembersType implements PyClassLikeType {
@NotNull
private final Map<String, PyCustomMember> myMembers;
@Nullable
private final PyClassType myTypeToMimic;
/**
* @param typeToMimic this type may mimic some other class-based type. Pass it to have all members from this class + custom.
* Check class manual for more info.
* @param members custom members
*/
public PyCustomMembersType(@Nullable final PyClassType typeToMimic, @NotNull final PyCustomMember... members) {
myTypeToMimic = typeToMimic;
myMembers = new HashMap<String, PyCustomMember>(members.length);
for (final PyCustomMember member : members) {
myMembers.put(member.getName(), member);
}
}
/**
* @return class we mimic (if any). Check class manual for more info.
*/
@Nullable
public PyClassType getTypeToMimic() {
return myTypeToMimic;
}
@Override
public boolean isDefinition() {
return false;
}
@Override
public PyClassLikeType toInstance() {
return this;
}
@Nullable
@Override
public String getClassQName() {
return null;
}
@NotNull
@Override
public List<PyClassLikeType> getSuperClassTypes(@NotNull TypeEvalContext context) {
return Collections.emptyList();
}
@Nullable
@Override
public List<? extends RatedResolveResult> resolveMember(@NotNull final String name,
@Nullable final PyExpression location,
@NotNull final AccessDirection direction,
@NotNull final PyResolveContext resolveContext,
final boolean inherited) {
if (myMembers.containsKey(name)) {
PsiElement context = null;
if (location != null) {
context = location;
}
if (context == null) {
context = resolveContext.getTypeEvalContext().getOrigin();
}
if (context != null) {
final PsiElement resolveResult = myMembers.get(name).resolve(context);
if (resolveResult != null) {
return Collections.singletonList(new RatedResolveResult(0, resolveResult));
}
}
}
if (myTypeToMimic != null) {
return myTypeToMimic.resolveMember(name, location, direction, resolveContext, inherited);
}
return null;
}
@Override
public boolean isValid() {
return true;
}
@Nullable
@Override
public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context, boolean inherited) {
return null;
}
@Override
public boolean isCallable() {
return true;
}
@Nullable
@Override
public PyType getReturnType(@NotNull TypeEvalContext context) {
return null;
}
@Nullable
@Override
public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
return this;
}
@Nullable
@Override
public List<PyCallableParameter> getParameters(@NotNull TypeEvalContext context) {
return null;
}
@Nullable
@Override
public List<? extends RatedResolveResult> resolveMember(@NotNull final String name,
@Nullable final PyExpression location,
@NotNull final AccessDirection direction,
@NotNull final PyResolveContext resolveContext) {
return resolveMember(name, location, direction, resolveContext, true);
}
@Override
public Object[] getCompletionVariants(final String completionPrefix, final PsiElement location, final ProcessingContext context) {
final Collection<LookupElement> lookupElements = new ArrayList<LookupElement>(myMembers.size());
for (final PyCustomMember member : myMembers.values()) {
lookupElements.add(PyCustomMemberUtils.toLookUpElement(member, member.getShortType()));
}
return ArrayUtil.mergeArrays(ArrayUtil.toObjectArray(lookupElements),
((myTypeToMimic != null)
? myTypeToMimic.getCompletionVariants(completionPrefix, location, context)
: PsiElement.EMPTY_ARRAY));
}
@Nullable
@Override
public String getName() {
String mimicName = null;
if (myTypeToMimic != null) {
mimicName = myTypeToMimic.getName();
}
if (mimicName != null) {
return PyBundle.message("custom.type.mimic.name", mimicName);
}
return PyBundle.message("custom.type.name");
}
@Override
public boolean isBuiltin() {
return false;
}
@Override
public void assertValid(final String message) {
}
/**
* @param name name to check
* @return True if this class (not the one it mimics!) has member with passed name
*/
public boolean hasMember(@NotNull final String name) {
return myMembers.containsKey(name);
}
}
@@ -0,0 +1,245 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Custom (aka dynamic) type that delegates calls to some classes you pass to it.
* We say this this class <strong>mimics</strong> such classes.
* To be used for cases like "type()".
* It optionally filters methods using {@link ParentsMemberFilter}
*
* @author Ilya.Kazakevich
*/
public class PyCustomType implements PyClassLikeType, Predicate<RatedResolveResult> {
@NotNull
private final List<PyClassLikeType> myTypesToMimic = new ArrayList<PyClassLikeType>();
@Nullable
private final ParentsMemberFilter myFilter;
private final boolean myInstanceType;
/**
* @param filter filter to filter methods from classes (may be null to do no filtering)
* @param instanceType if true, then this class implements instance (it reports it is not definition and returns "this
* for {@link #toInstance()} call).
* @param typesToMimic types to "mimic": delegate calls to (must be one at least!)
*/
public PyCustomType(@Nullable final ParentsMemberFilter filter,
final boolean instanceType,
@NotNull final PyClassLikeType... typesToMimic) {
Preconditions.checkArgument(typesToMimic.length > 0, "Provide at least one class");
myFilter = filter;
myTypesToMimic.addAll(Arrays.asList(typesToMimic));
myInstanceType = instanceType;
}
/**
* @return class we mimic (if any). Check class manual for more info.
*/
@NotNull
public final List<PyClassLikeType> getTypesToMimic() {
return Collections.unmodifiableList(myTypesToMimic);
}
@Override
public final boolean isDefinition() {
return !myInstanceType;
}
@Override
public final PyClassLikeType toInstance() {
return myInstanceType ? this : new PyCustomType(myFilter, true, myTypesToMimic.toArray(new PyClassLikeType[myTypesToMimic.size()]));
}
@Nullable
@Override
public final String getClassQName() {
return null;
}
@NotNull
@Override
public final List<PyClassLikeType> getSuperClassTypes(@NotNull final TypeEvalContext context) {
return Collections.emptyList();
}
@Nullable
@Override
public final List<? extends RatedResolveResult> resolveMember(@NotNull final String name,
@Nullable final PyExpression location,
@NotNull final AccessDirection direction,
@NotNull final PyResolveContext resolveContext,
final boolean inherited) {
final List<RatedResolveResult> globalResult = new ArrayList<RatedResolveResult>();
// Delegate calls to classes, we mimic but filter if filter is set.
for (final PyClassLikeType parentType : myTypesToMimic) {
final List<? extends RatedResolveResult> results = parentType.resolveMember(name, location, direction, resolveContext, inherited);
if (results != null) {
globalResult.addAll(Collections2.filter(results, this));
}
}
return globalResult;
}
@Override
public final boolean isValid() {
return true;
}
@Nullable
@Override
public final PyClassLikeType getMetaClassType(@NotNull final TypeEvalContext context, final boolean inherited) {
return null;
}
@Override
public final boolean isCallable() {
return true; // We do not know, actually
}
@Nullable
@Override
public final PyType getReturnType(@NotNull final TypeEvalContext context) {
return (myInstanceType ? null : toInstance());
}
@Nullable
@Override
public final PyType getCallType(@NotNull final TypeEvalContext context, @NotNull final PyCallSiteExpression callSite) {
return getReturnType(context);
}
@Nullable
@Override
public final List<PyCallableParameter> getParameters(@NotNull final TypeEvalContext context) {
return null;
}
@Nullable
@Override
public final List<? extends RatedResolveResult> resolveMember(@NotNull final String name,
@Nullable final PyExpression location,
@NotNull final AccessDirection direction,
@NotNull final PyResolveContext resolveContext) {
return resolveMember(name, location, direction, resolveContext, true);
}
@Override
public final Object[] getCompletionVariants(final String completionPrefix, final PsiElement location, final ProcessingContext context) {
final Collection<Object> lookupElements = new ArrayList<Object>();
for (final PyClassLikeType parentType : myTypesToMimic) {
lookupElements.addAll(Collections2.filter(Arrays.asList(parentType.getCompletionVariants(completionPrefix, location, context)),
new CompletionFilter()));
}
return lookupElements.toArray(new Object[lookupElements.size()]);
}
@Nullable
@Override
public final String getName() {
final Collection<String> classNames = new ArrayList<String>(myTypesToMimic.size());
for (final PyClassLikeType type : myTypesToMimic) {
String name = type.getName();
if (name == null && (type instanceof PyClassType)) {
name = ((PyClassType)type).getPyClass().getName();
}
if (name != null) {
classNames.add(name);
}
}
return PyBundle.message("custom.type.mimic.name", StringUtil.join(classNames, ","));
}
@Override
public final boolean isBuiltin() {
return false;
}
@Override
public final void assertValid(final String message) {
for (final PyClassLikeType type : myTypesToMimic) {
type.assertValid(message);
}
}
@Override
public final boolean apply(@Nullable final RatedResolveResult input) {
if (input == null) {
return false;
}
if (myFilter == null) {
return true; // No need to check
}
final PyElement pyElement = PyUtil.as(input.getElement(), PyElement.class);
if (pyElement == null) {
return false;
}
return myFilter.acceptMember(pyElement);
}
public interface ParentsMemberFilter {
boolean acceptMember(@NotNull PyElement element);
}
/**
* Predicate that filters completion using {@link #myFilter}
*/
private class CompletionFilter implements Predicate<Object> {
@Override
public final boolean apply(@Nullable final Object input) {
if (input == null) {
return false;
}
if (myFilter == null) {
return true; // No need to check
}
if (!(input instanceof LookupElement)) {
return true; // Do not know how to check
}
final PyElement pyElement = PyUtil.as(((LookupElement)input).getPsiElement(), PyElement.class);
if (pyElement == null) {
return false;
}
return myFilter.acceptMember(pyElement);
}
}
}
@@ -38,7 +38,7 @@ import com.intellij.util.PlatformUtils;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyCustomMembersType;
import com.jetbrains.python.PyCustomType;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.codeInsight.PyCustomMember;
@@ -607,13 +607,15 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
/**
* Checks if type is custom-member based and has custom member with certain name
* Checks if type is custom type and has custom member with certain name
* @param refName name to check
* @param type type
* @return true if has one
*/
private static boolean isHasCustomMember(@NotNull final String refName, @NotNull final PyType type) {
return (type instanceof PyCustomMembersType) && ((PyCustomMembersType)type).hasMember(refName);
// TODO: check
return false;
/*return (type instanceof PyCustomType) && ((PyCustomType)type).hasMember(refName);*/
}
/**
@@ -713,11 +715,15 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
return true;
}
}
if (type instanceof PyCustomMembersType) {
if (type instanceof PyCustomType) {
// Skip custom member types that mimics another class with fuzzy parents
PyClassType mimic = ((PyCustomMembersType)type).getTypeToMimic();
if (mimic != null && PyUtil.hasUnresolvedAncestors(mimic.getPyClass(), myTypeEvalContext)) {
return true;
for (final PyClassLikeType mimic : ((PyCustomType)type).getTypesToMimic()) {
if (!(mimic instanceof PyClassType)) {
continue;
}
if (PyUtil.hasUnresolvedAncestors(((PyClassType)mimic).getPyClass(), myTypeEvalContext)) {
return true;
}
}
}
if (type instanceof PyClassTypeImpl) {
@@ -360,6 +360,9 @@ public class PyCallExpressionHelper {
}
}
}
else if (qtype instanceof PyClassLikeType) {
return ((PyClassLikeType)qtype).isDefinition(); //Any definition means callable is classmethod
}
return false;
}
@@ -522,6 +525,10 @@ public class PyCallExpressionHelper {
final Callable callable = (Callable)target;
return Ref.create(callable.getCallType(context, call));
}
/*PyCallExpression.PyMarkedCallee markedCallee = call.resolveCallee(PyResolveContext.defaultContext().withTypeEvalContext(context));
if (markedCallee != null) {
return Ref.create(markedCallee.getCallable().getCallType(context, call));
}*/
return null;
}
@@ -1219,6 +1219,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
}
else {
for (PyExpression expression : getSuperClassExpressions()) {
context.getType(expression);
expression = unfoldClass(expression);
if (expression instanceof PyKeywordArgument) {
continue;
@@ -420,7 +420,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
@Nullable PsiElement anchor) {
for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
final PyType result = provider.getReferenceType(target, context, anchor);
if (result != null) return result;
if (result != null) {
return result;
}
}
return null;
@@ -32,6 +32,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashMap;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCustomMember;
import com.jetbrains.python.codeInsight.PyCustomMemberUtils;
@@ -138,7 +139,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
resolving.add(key);
try {
return doResolveMember(name, location, direction, resolveContext, inherited);
return doResolveMember(name, location, direction, resolveContext, inherited, null);
}
finally {
resolving.remove(key);
@@ -146,14 +147,16 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
@Nullable
private List<? extends RatedResolveResult> doResolveMember(@NotNull String name,
@Nullable PyExpression location,
@NotNull AccessDirection direction,
@NotNull PyResolveContext resolveContext,
boolean inherited) {
public List<? extends RatedResolveResult> doResolveMember(@NotNull String name,
@Nullable PyExpression location,
@NotNull AccessDirection direction,
@NotNull PyResolveContext resolveContext,
boolean inherited,
@Nullable PyClassMembersProvider providerToSkip) {
final TypeEvalContext context = resolveContext.getTypeEvalContext();
PsiElement classMember =
resolveByOverridingMembersProviders(this, name, location); //overriding members provers have priority to normal resolve
resolveByOverridingMembersProviders(this, name, location,
providerToSkip); //overriding members provers have priority to normal resolve
if (classMember != null) {
return ResolveResultList.to(classMember);
}
@@ -188,7 +191,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
return ResolveResultList.to(classMember);
}
classMember = resolveByOverridingAncestorsMembersProviders(this, name, location);
classMember = resolveByOverridingAncestorsMembersProviders(this, name, location, providerToSkip);
if (classMember != null) {
return ResolveResultList.to(classMember);
}
@@ -225,7 +228,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
if (inherited) {
classMember =
resolveByMembersProviders(this, name, location); //ask providers after real class introspection as providers have less priority
resolveByMembersProviders(this, name, location,
providerToSkip); //ask providers after real class introspection as providers have less priority
}
if (classMember != null) {
@@ -236,7 +240,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
for (PyClassLikeType type : myClass.getAncestorTypes(context)) {
if (type instanceof PyClassType) {
final PyClass pyClass = ((PyClassType)type).getPyClass();
PsiElement superMember = resolveByMembersProviders(new PyClassTypeImpl(pyClass, isDefinition()), name, location);
PsiElement superMember = resolveByMembersProviders(new PyClassTypeImpl(pyClass, isDefinition()), name, location, providerToSkip);
if (superMember != null) {
return ResolveResultList.to(superMember);
@@ -345,8 +349,13 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
@Nullable
private static PsiElement resolveByMembersProviders(PyClassType aClass, String name, @Nullable PsiElement location) {
private static PsiElement resolveByMembersProviders(PyClassType aClass, String name,
@Nullable PsiElement location,
@Nullable PyClassMembersProvider providerToSkip) {
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
if (provider == providerToSkip) {
continue;
}
final PsiElement resolveResult = provider.resolveMember(aClass, name, location);
if (resolveResult != null) return resolveResult;
}
@@ -355,9 +364,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
@Nullable
private static PsiElement resolveByOverridingMembersProviders(PyClassType aClass, String name, @Nullable PsiElement location) {
private static PsiElement resolveByOverridingMembersProviders(PyClassType aClass, String name, @Nullable PsiElement location,
@Nullable PyClassMembersProvider providerToSkip) {
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
if (provider instanceof PyOverridingClassMembersProvider) {
if (provider instanceof PyOverridingClassMembersProvider && provider != providerToSkip) {
final PsiElement resolveResult = provider.resolveMember(aClass, name, location);
if (resolveResult != null) return resolveResult;
}
@@ -367,9 +377,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
@Nullable
private static PsiElement resolveByOverridingAncestorsMembersProviders(PyClassType type, String name, @Nullable PyExpression location) {
private static PsiElement resolveByOverridingAncestorsMembersProviders(PyClassType type, String name, @Nullable PyExpression location,
@Nullable PyClassMembersProvider providerToSkip) {
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
if (provider instanceof PyOverridingAncestorsClassMembersProvider) {
if (provider instanceof PyOverridingAncestorsClassMembersProvider && !(provider == providerToSkip)) {
final PsiElement resolveResult = provider.resolveMember(type, name, location);
if (resolveResult != null) return resolveResult;
}
@@ -409,28 +420,50 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
if (namesAlready == null) {
namesAlready = new HashSet<String>();
}
List<Object> ret = new ArrayList<Object>();
// TODO: Doc
final Map<String, Pair<ElementType, Object>> usedNames = new HashMap<String, Pair<ElementType, Object>>();
boolean suppressParentheses = context.get(CTX_SUPPRESS_PARENTHESES) != null;
addOwnClassMembers(location, namesAlready, suppressParentheses, ret);
addOwnClassMembers(location, namesAlready, suppressParentheses, usedNames);
namesAlready.addAll(usedNames.keySet());
PsiFile origin = (location != null) ?
CompletionUtil.getOriginalOrSelf(location)
.getContainingFile() :
null;
final TypeEvalContext typeEvalContext = TypeEvalContext.codeCompletion(myClass.getProject(), origin);
addInheritedMembers(prefix, location, namesAlready, context, ret, typeEvalContext);
final List<Object> inheritedMembers = addInheritedMembers(prefix, location, namesAlready, context, usedNames, typeEvalContext);
namesAlready.addAll(usedNames.keySet());
// Move to func
// TODO: Override only if Overriding
// from providers
for (final PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
for (final PyCustomMember member : provider.getMembers(this, location)) {
final String name = member.getName();
if (!namesAlready.contains(name)) {
ret.add(PyCustomMemberUtils.toLookUpElement(member, getName()));
final LookupElementBuilder element = PyCustomMemberUtils.toLookUpElement(member, getName());
final Pair<ElementType, Object> usedNameInfo = usedNames.get(name);
// TODO: Doc
if (usedNameInfo == null ||
(usedNameInfo.first == ElementType.INHERITED && provider instanceof PyOverridingAncestorsClassMembersProvider) ||
(usedNameInfo.first == ElementType.OWN && provider instanceof PyOverridingClassMembersProvider)) {
usedNames.put(name, Pair.<ElementType, Object>create(ElementType.BY_PROVIDER, element));
} else {
int i = 1;
}
}
}
final List<Object> ret = new ArrayList<Object>(getElementsFromUsedNames(usedNames));
namesAlready.addAll(usedNames.keySet());
ret.addAll(inheritedMembers);
if (!myClass.isNewStyleClass()) {
final PyBuiltinCache cache = PyBuiltinCache.getInstance(myClass);
final PyClassType classobjType = cache.getOldstyleClassobjType();
@@ -449,7 +482,11 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
return ret.toArray();
}
private void addOwnClassMembers(PsiElement expressionHook, Set<String> namesAlready, boolean suppressParentheses, List<Object> ret) {
private void addOwnClassMembers(PsiElement expressionHook,
Set<String> namesAlready,
boolean suppressParentheses,
@NotNull final Map<String, Pair<ElementType, Object>> usedNames) {
PyClass containingClass = PsiTreeUtil.getParentOfType(expressionHook, PyClass.class);
if (containingClass != null) {
containingClass = CompletionUtil.getOriginalElement(containingClass);
@@ -475,12 +512,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
if (namesAlready.contains(name)) continue;
if (!withinOurClass && isClassPrivate(name)) continue;
namesAlready.add(name);
ret.add(le);
usedNames.put(name, Pair.<ElementType, Object>create(ElementType.OWN, le));
}
if (slots != null) {
for (String name : slots) {
if (!namesAlready.contains(name)) {
ret.add(LookupElementBuilder.create(name));
usedNames.put(name, Pair.<ElementType, Object>create(ElementType.OWN, LookupElementBuilder.create(name)));
}
}
}
@@ -494,12 +531,14 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
return false;
}
private void addInheritedMembers(String name,
@NotNull
private List<Object> addInheritedMembers(String name,
PsiElement expressionHook,
Set<String> namesAlready,
ProcessingContext context,
List<Object> ret,
@NotNull final Map<String, Pair<ElementType, Object>> usedNames,
@NotNull TypeEvalContext typeEvalContext) {
final List<Object> ret = new ArrayList<Object>();
for (PyExpression expression : myClass.getSuperClassExpressions()) {
final PsiReference reference = expression.getReference();
PsiElement element = null;
@@ -521,13 +560,14 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
for (Object ob : ancestry) {
String inheritedName = ob.toString();
if (!namesAlready.contains(inheritedName) && !isClassPrivate(inheritedName)) {
ret.add(ob);
usedNames.put(inheritedName, Pair.create(ElementType.INHERITED, ob));
namesAlready.add(inheritedName);
}
}
ContainerUtil.addAll(ret, ancestry);
}
}
return ret;
}
private static boolean isClassPrivate(String lookup_string) {
@@ -607,4 +647,20 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
return new PyClassTypeImpl(pyClass, isDefinition);
}
// TOOD: Doc
private static List<Object> getElementsFromUsedNames(@NotNull final Map<String, Pair<ElementType, Object>> usedNames) {
final List<Object> ret = new ArrayList<Object>();
for (final Pair<ElementType, Object> objectPair : usedNames.values()) {
ret.add(objectPair.second);
}
return ret;
}
// TODO: Doc
private enum ElementType {
OWN,
INHERITED,
BY_PROVIDER
}
}
@@ -18,12 +18,12 @@ package com.intellij.xml.util;
import com.intellij.codeInsight.daemon.impl.analysis.encoding.XmlEncodingReferenceProvider;
import com.intellij.html.impl.providers.MicrodataReferenceProvider;
import com.intellij.html.impl.util.MicrodataUtil;
import com.intellij.openapi.paths.WebReference;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.*;
import com.intellij.psi.filters.*;
import com.intellij.psi.filters.position.NamespaceFilter;
import com.intellij.psi.filters.position.ParentElementFilter;
import com.intellij.psi.impl.UrlPsiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.*;
import com.intellij.psi.xml.*;
import com.intellij.util.ProcessingContext;
@@ -116,7 +116,7 @@ public class XmlReferenceContributor extends PsiReferenceContributor {
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext context) {
return new PsiReference[] { new UrlPsiReference(element) };
return new PsiReference[] { new WebReference(element) };
}
});
}