mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -862,10 +862,11 @@ binding.setVariable("buildCrossPlatformZip", { String zipPath, String sandbox, L
|
||||
}
|
||||
ant.copy(todir: "$zipDir/bin/mac") {
|
||||
fileset(dir: "$distMac/bin") {
|
||||
include(name: "idea*.vmoptions")
|
||||
include(name: "idea.vmoptions")
|
||||
include(name: "idea.properties")
|
||||
}
|
||||
}
|
||||
ant.copy(file: "$distMac/bin/idea.vmoptions", tofile: "$zipDir/bin/mac/idea64.vmoptions")
|
||||
|
||||
ant.zip(zipfile: zipPath, duplicate: "fail") {
|
||||
commonPaths.each {
|
||||
|
||||
+6
-3
@@ -920,9 +920,12 @@ public class GenericsHighlightUtil {
|
||||
}
|
||||
try {
|
||||
MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
|
||||
if (superMethod != null && method.getContainingClass().isInterface() && "clone".equals(superMethod.getName())) {
|
||||
final PsiClass containingClass = superMethod.getMethod().getContainingClass();
|
||||
if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) {
|
||||
if (superMethod != null && method.getContainingClass().isInterface()) {
|
||||
final PsiMethod psiMethod = superMethod.getMethod();
|
||||
final PsiClass containingClass = psiMethod.getContainingClass();
|
||||
if (containingClass != null &&
|
||||
CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
|
||||
psiMethod.hasModifierProperty(PsiModifier.PROTECTED)) {
|
||||
superMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
+62
-13
@@ -20,6 +20,8 @@ import com.intellij.codeInsight.generation.GenerateMembersUtil;
|
||||
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -27,28 +29,32 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
public class LambdaCompletionProvider extends CompletionProvider<CompletionParameters> {
|
||||
public class FunctionalExpressionCompletionProvider extends CompletionProvider<CompletionParameters> {
|
||||
@Override
|
||||
protected void addCompletions(@NotNull CompletionParameters parameters,
|
||||
ProcessingContext context,
|
||||
@NotNull CompletionResultSet result) {
|
||||
result.addAllElements(getLambdaVariants(parameters));
|
||||
result.addAllElements(getLambdaVariants(parameters, false));
|
||||
}
|
||||
|
||||
static List<LookupElement> getLambdaVariants(@NotNull CompletionParameters parameters) {
|
||||
static List<LookupElement> getLambdaVariants(@NotNull CompletionParameters parameters, boolean prioritize) {
|
||||
if (!PsiUtil.isLanguageLevel8OrHigher(parameters.getOriginalFile())) return Collections.emptyList();
|
||||
|
||||
List<LookupElement> result = ContainerUtil.newArrayList();
|
||||
@@ -56,15 +62,15 @@ public class LambdaCompletionProvider extends CompletionProvider<CompletionParam
|
||||
final PsiType defaultType = expectedType.getDefaultType();
|
||||
if (LambdaUtil.isFunctionalType(defaultType)) {
|
||||
final PsiType functionalInterfaceType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(defaultType);
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (method != null) {
|
||||
PsiParameter[] params = method.getParameterList().getParameters();
|
||||
final Project project = method.getProject();
|
||||
final PsiElement originalPosition = parameters.getOriginalPosition();
|
||||
final JVMElementFactory jvmElementFactory = originalPosition != null ? JVMElementFactories.getFactory(originalPosition.getLanguage(), project) : null;
|
||||
final PsiMethod functionalInterfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (functionalInterfaceMethod != null) {
|
||||
PsiParameter[] params = functionalInterfaceMethod.getParameterList().getParameters();
|
||||
final Project project = functionalInterfaceMethod.getProject();
|
||||
final PsiElement originalPosition = parameters.getPosition();
|
||||
final JVMElementFactory jvmElementFactory = JVMElementFactories.getFactory(originalPosition.getLanguage(), project);
|
||||
final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(functionalInterfaceMethod, PsiUtil.resolveGenericsClassInType(functionalInterfaceType));
|
||||
if (jvmElementFactory != null) {
|
||||
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(method, PsiUtil.resolveGenericsClassInType(functionalInterfaceType));
|
||||
params = GenerateMembersUtil.overriddenParameters(params, jvmElementFactory, javaCodeStyleManager, substitutor, originalPosition);
|
||||
}
|
||||
|
||||
@@ -82,14 +88,57 @@ public class LambdaCompletionProvider extends CompletionProvider<CompletionParam
|
||||
lambdaExpression = (PsiLambdaExpression)codeStyleManager.reformat(lambdaExpression);
|
||||
paramsString = lambdaExpression.getParameterList().getText();
|
||||
final LookupElementBuilder builder =
|
||||
LookupElementBuilder.create(paramsString).withPresentableText(paramsString + " -> {}").withInsertHandler(new InsertHandler<LookupElement>() {
|
||||
LookupElementBuilder.create(functionalInterfaceMethod, paramsString).withPresentableText(paramsString + " -> {}").withInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final Editor editor = context.getEditor();
|
||||
EditorModificationUtil.insertStringAtCaret(editor, " -> ");
|
||||
}
|
||||
});
|
||||
result.add(builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE));
|
||||
}).withIcon(AllIcons.Nodes.AnonymousClass);
|
||||
LookupElement lambdaElement = builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
if (prioritize) {
|
||||
lambdaElement = PrioritizedLookupElement.withPriority(lambdaElement, 1);
|
||||
}
|
||||
result.add(lambdaElement);
|
||||
|
||||
if (params.length == 1) {
|
||||
final PsiType expectedReturnType = substitutor.substitute(functionalInterfaceMethod.getReturnType());
|
||||
if (expectedReturnType != null) {
|
||||
final PsiClass paramClass = PsiUtil.resolveClassInClassTypeOnly(params[0].getType());
|
||||
if (paramClass != null && !paramClass.hasTypeParameters()) {
|
||||
final Set<String> visited = new HashSet<String>();
|
||||
for (PsiMethod psiMethod : paramClass.getAllMethods()) {
|
||||
final PsiType returnType = psiMethod.getReturnType();
|
||||
if (returnType != null &&
|
||||
psiMethod.getParameterList().getParametersCount() == 0 &&
|
||||
visited.add(psiMethod.getName()) &&
|
||||
!psiMethod.hasModifierProperty(PsiModifier.STATIC) &&
|
||||
JavaResolveUtil.isAccessible(psiMethod, null, psiMethod.getModifierList(), originalPosition, null, null) &&
|
||||
TypeConversionUtil.isAssignable(expectedReturnType, returnType)) {
|
||||
LookupElement methodRefLookupElement = LookupElementBuilder
|
||||
.create(psiMethod)
|
||||
.withPresentableText(paramClass.getName() + "::" + psiMethod.getName())
|
||||
.withInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final int startOffset = context.getStartOffset();
|
||||
final Document document = context.getDocument();
|
||||
final PsiFile file = context.getFile();
|
||||
document.insertString(startOffset, "::");
|
||||
JavaCompletionUtil.insertClassReference(paramClass, file, startOffset);
|
||||
}
|
||||
})
|
||||
.withIcon(AllIcons.Nodes.AnonymousClass)
|
||||
.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
if (prioritize && psiMethod.getContainingClass() == paramClass) {
|
||||
methodRefLookupElement = PrioritizedLookupElement.withPriority(methodRefLookupElement, 1);
|
||||
}
|
||||
result.add(methodRefLookupElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -225,9 +225,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
if (JavaSmartCompletionContributor.LAMBDA.accepts(parameters.getPosition())) {
|
||||
for (LookupElement element : LambdaCompletionProvider.getLambdaVariants(parameters)) {
|
||||
result.addElement(PrioritizedLookupElement.withPriority(element, 1));
|
||||
}
|
||||
result.addAllElements(FunctionalExpressionCompletionProvider.getLambdaVariants(parameters, true));
|
||||
}
|
||||
|
||||
PrefixMatcher matcher = result.getPrefixMatcher();
|
||||
|
||||
+1
-1
@@ -359,7 +359,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
});
|
||||
|
||||
extend(CompletionType.SMART, LAMBDA, new LambdaCompletionProvider());
|
||||
extend(CompletionType.SMART, LAMBDA, new FunctionalExpressionCompletionProvider());
|
||||
extend(CompletionType.SMART, METHOD_REFERENCE, new MethodReferenceCompletionProvider());
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -30,6 +30,7 @@ import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.PopupStep;
|
||||
@@ -196,7 +197,12 @@ public class AddImportAction implements QuestionAction {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
_addImport(ref, targetClass);
|
||||
DumbService.getInstance(myProject).withAlternativeResolveEnabled(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
_addImport(ref, targetClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+4
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateExpres
|
||||
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateExpressionSelectorBase;
|
||||
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplatePsiInfo;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.psi.*;
|
||||
@@ -33,6 +34,7 @@ import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.openapi.util.Conditions.and;
|
||||
@@ -80,6 +82,8 @@ public abstract class JavaPostfixTemplatesUtils {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PsiElement> getExpressions(@NotNull PsiElement context, @NotNull Document document, int offset) {
|
||||
if (DumbService.getInstance(context.getProject()).isDumb()) return Collections.emptyList();
|
||||
|
||||
List<PsiElement> expressions = super.getExpressions(context, document, offset);
|
||||
if (!expressions.isEmpty()) return expressions;
|
||||
|
||||
|
||||
@@ -509,7 +509,7 @@ public class GenericsUtil {
|
||||
final PsiType bound = ((PsiWildcardType)type).getBound();
|
||||
return eliminateWildcards(bound != null ? bound : ((PsiWildcardType)type).getExtendsBound(), false);//object
|
||||
} else if (type instanceof PsiCapturedWildcardType && !eliminateInTypeArguments) {
|
||||
return eliminateWildcards(((PsiCapturedWildcardType)type).getWildcard(), eliminateInTypeArguments);
|
||||
return ((PsiCapturedWildcardType)type).getUpperBound();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.RecursionGuard;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -49,8 +52,11 @@ public class PsiCapturedWildcardType extends PsiType.Stub {
|
||||
myExistential = existential;
|
||||
myContext = context;
|
||||
myParameter = parameter;
|
||||
myUpperBound = PsiType.getJavaLangObject(myContext.getManager(), getResolveScope());
|
||||
}
|
||||
|
||||
private static RecursionGuard guard = RecursionManager.createGuard("captureGuard");
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof PsiCapturedWildcardType)) {
|
||||
@@ -58,7 +64,7 @@ public class PsiCapturedWildcardType extends PsiType.Stub {
|
||||
}
|
||||
|
||||
final PsiCapturedWildcardType captured = (PsiCapturedWildcardType)o;
|
||||
if (!myContext.equals(captured.myContext) || !myExistential.equals(captured.myExistential)) {
|
||||
if (!myContext.equals(captured.myContext) || myExistential.isSuper() && !myExistential.equals(captured.myExistential)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -66,12 +72,24 @@ public class PsiCapturedWildcardType extends PsiType.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (myParameter != null) {
|
||||
final Boolean sameUpperBounds = guard.doPreventingRecursion(myContext, true, new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return Comparing.equal(myUpperBound, captured.myUpperBound);
|
||||
}
|
||||
});
|
||||
|
||||
if (sameUpperBounds != null && sameUpperBounds) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return myExistential.equals(captured.myExistential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myExistential.hashCode() + 31 * myContext.hashCode();
|
||||
return myUpperBound.hashCode() + 31 * myContext.hashCode();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -125,14 +143,14 @@ public class PsiCapturedWildcardType extends PsiType.Stub {
|
||||
|
||||
public PsiType getUpperBound () {
|
||||
final PsiType bound = myExistential.getBound();
|
||||
if (myExistential.isExtends()) {
|
||||
if (myExistential.isExtends() && myParameter == null) {
|
||||
return bound;
|
||||
}
|
||||
else if (bound instanceof PsiCapturedWildcardType) {
|
||||
return PsiWildcardType.createSuper(myContext.getManager(), ((PsiCapturedWildcardType)bound).getUpperBound());
|
||||
}
|
||||
else {
|
||||
return myUpperBound != null ? myUpperBound : PsiType.getJavaLangObject(myContext.getManager(), getResolveScope());
|
||||
return myUpperBound;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -763,10 +763,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
captureContext = captured.getContext();
|
||||
}
|
||||
PsiType glb = null;
|
||||
PsiType originalBound = PsiType.NULL;
|
||||
if (substituted instanceof PsiWildcardType) {
|
||||
final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
|
||||
PsiManager manager = typeParameter.getManager();
|
||||
PsiType originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null;
|
||||
originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null;
|
||||
glb = originalBound;
|
||||
for (PsiType boundType : boundTypes) {
|
||||
PsiType substitutedBoundType = captureSubstitutor.substitute(boundType);
|
||||
@@ -813,9 +814,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
|
||||
if (captureContext != null) {
|
||||
LOG.assertTrue(substituted instanceof PsiWildcardType, substituted);
|
||||
substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard())
|
||||
? oldSubstituted
|
||||
: PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter);
|
||||
substituted =
|
||||
oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard())
|
||||
? oldSubstituted
|
||||
: captureSubstitutor.substitute(typeParameter);
|
||||
LOG.assertTrue(substituted instanceof PsiCapturedWildcardType);
|
||||
if (glb != null) {
|
||||
((PsiCapturedWildcardType)substituted).setUpperBound(glb);
|
||||
}
|
||||
|
||||
@@ -257,8 +257,10 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
||||
} else {
|
||||
PsiType substituted = substituteInternal(original);
|
||||
if (original instanceof PsiWildcardType && substituted instanceof PsiCapturedWildcardType) {
|
||||
substituted = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(),
|
||||
((PsiCapturedWildcardType)substituted).getContext(), param);
|
||||
final PsiCapturedWildcardType capturedWildcardType = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(),
|
||||
((PsiCapturedWildcardType)substituted).getContext(), param);
|
||||
capturedWildcardType.setUpperBound(((PsiCapturedWildcardType)substituted).getUpperBound());
|
||||
substituted = capturedWildcardType;
|
||||
}
|
||||
//if (substituted == null) return false;
|
||||
substMap.put(param, substituted);
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import java.util.List;
|
||||
|
||||
class MyTest {
|
||||
|
||||
void m(List<Person> l) {
|
||||
l.stream().map(Person::getName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface Person {
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.List;
|
||||
|
||||
class MyTest {
|
||||
|
||||
void m(List<Person> l) {
|
||||
l.stream().map(<caret>)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface Person {
|
||||
String getName();
|
||||
}
|
||||
+5
@@ -16,4 +16,9 @@ class MyCloneable2 {
|
||||
public Object clone() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
interface MyFinalizable {
|
||||
<error descr="Method does not override method from its superclass">@Override</error> void finalize();
|
||||
@Override int hashCode();
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
|
||||
interface A<T extends String, K extends T> {
|
||||
K get();
|
||||
}
|
||||
|
||||
class Test {
|
||||
void f(A<?, ?> a) {
|
||||
String s = a.get();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class C<T extends C<? extends C<? extends T>>>{
|
||||
void foo(C<?> x){
|
||||
<error descr="Inferred type 'capture<? extends C<? extends C<capture<?>>>>' for type parameter 'T' is not within its bound; should extend 'C<capture<? extends C<? extends C<capture<?>>>>>'">bar(x)</error>;
|
||||
<error descr="Inferred type 'capture<?>' for type parameter 'T' is not within its bound; should extend 'C<capture<?>>'">bar(x)</error>;
|
||||
}
|
||||
<T extends C<? extends T>> void bar(C<T> x){}
|
||||
}
|
||||
+1
-1
@@ -6,6 +6,6 @@ interface B<T extends Cloneable> {
|
||||
|
||||
class D {
|
||||
void bar(B<?> x, List<?> y) {
|
||||
x.foo<error descr="'foo(java.util.List<? super capture<? extends java.lang.Cloneable>>)' in 'B' cannot be applied to '(java.util.List<capture<?>>)'">(y)</error>;
|
||||
x.foo<error descr="'foo(java.util.List<? super capture<?>>)' in 'B' cannot be applied to '(java.util.List<capture<?>>)'">(y)</error>;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -13,6 +13,6 @@ class Test2 {}
|
||||
|
||||
class Test {
|
||||
public void test(TestIF<?> testIF) {
|
||||
testIF.run<error descr="'run(capture<? extends TestIF2<? extends Test2>>)' in 'TestIF' cannot be applied to '()'">()</error>;
|
||||
testIF.run<error descr="'run(capture<?>)' in 'TestIF' cannot be applied to '()'">()</error>;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> {
|
||||
SortTest<?> t2 = new SortTest<Integer>(0);
|
||||
list.add(t2);
|
||||
<error descr="Inferred type 'SortTest<?>' for type parameter 'T' is not within its bound; should implement 'java.lang.Comparable<? super SortTest<?>>'">Collections.sort(list)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)'">(t2)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<?>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>;
|
||||
|
||||
//this should be OK
|
||||
SortTest<?>[] arr = new SortTest<?>[0];
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class C<T extends C<? extends C<? extends T>>>{
|
||||
void foo(C<?> x){
|
||||
<error descr="Inferred type 'capture<? extends C<? extends C<capture<?>>>>' for type parameter 'T' is not within its bound; should extend 'C<capture<? extends C<? extends C<capture<?>>>>>'">bar(x)</error>;
|
||||
<error descr="Inferred type 'capture<?>' for type parameter 'T' is not within its bound; should extend 'C<capture<?>>'">bar(x)</error>;
|
||||
}
|
||||
<T extends C<? extends T>> void bar(C<T> x){}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ interface B<T extends Cloneable> {
|
||||
|
||||
class D {
|
||||
void bar(B<?> x, List<?> y) {
|
||||
x.foo<error descr="'foo(java.util.List<? super capture<? extends java.lang.Cloneable>>)' in 'B' cannot be applied to '(java.util.List<capture<?>>)'">(y)</error>;
|
||||
x.foo<error descr="'foo(java.util.List<? super capture<?>>)' in 'B' cannot be applied to '(java.util.List<capture<?>>)'">(y)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,6 +13,6 @@ class Test2 {}
|
||||
|
||||
class Test {
|
||||
public void test(TestIF<?> testIF) {
|
||||
testIF.run<error descr="'run(capture<? extends TestIF2<? extends Test2>>)' in 'TestIF' cannot be applied to '()'">()</error>;
|
||||
testIF.run<error descr="'run(capture<?>)' in 'TestIF' cannot be applied to '()'">()</error>;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> {
|
||||
SortTest<?> t2 = new SortTest<Integer>(0);
|
||||
list.add(t2);
|
||||
Collections.sort<error descr="'sort(java.util.List<T>)' in 'java.util.Collections' cannot be applied to '(java.util.ArrayList<SortTest<?>>)'">(list)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)'">(t2)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<?>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>;
|
||||
|
||||
//this should be OK
|
||||
SortTest<?>[] arr = new SortTest<?>[0];
|
||||
|
||||
+4
@@ -123,6 +123,10 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
public void testSimpleMethodReference() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
@@ -508,6 +508,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
|
||||
}
|
||||
|
||||
public void testCapturedBoundOfCapture() throws Exception {
|
||||
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
|
||||
}
|
||||
|
||||
public void testJavaUtilCollections_NoVerify() throws Exception {
|
||||
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
|
||||
assertNotNull(collectionsClass);
|
||||
|
||||
@@ -78,6 +78,11 @@ public class MiscPsiTest extends LightCodeInsightFixtureTestCase {
|
||||
PsiFile fileCopy = (PsiFile)file.copy();
|
||||
fileCopy = (PsiFile) fileCopy.setName("NewTest.xxx");
|
||||
PsiFile newFile = (PsiFile)dir.add(fileCopy);
|
||||
if (!(newFile instanceof PsiBinaryFile)) {
|
||||
System.out.println(newFile.getVirtualFile().getFileType());
|
||||
System.out.println(newFile.getFileType());
|
||||
System.out.println(newFile.getText());
|
||||
}
|
||||
assertInstanceOf(newFile, PsiBinaryFile.class);
|
||||
|
||||
assertOrderedEquals(newFile.getVirtualFile().contentsToByteArray(), bytes);
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ package com.intellij.codeInsight.intention;
|
||||
* Marked actions are shown higher in the list of available quick fixes.
|
||||
*
|
||||
* @author Dmitry Avdeev
|
||||
* @see com.intellij.codeInsight.intention.IntentionAction
|
||||
* @see IntentionAction
|
||||
* @see com.intellij.codeInspection.LocalQuickFix
|
||||
*/
|
||||
public interface HighPriorityAction {
|
||||
|
||||
@@ -26,49 +26,49 @@ public class RestApiTest {
|
||||
Rule
|
||||
public fun getChain(): RuleChain = _chain
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "", status = 400)
|
||||
public fun fileEmptyRequest() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "foo.txt", relativeToProject = true, status = 200)
|
||||
public fun relativeToProject() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "foo.txt", relativeToProject = true, line = 1, status = 200)
|
||||
public fun relativeToProjectWithLine() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "foo.txt", relativeToProject = true, line = 1, column = 13, status = 200)
|
||||
public fun relativeToProjectWithLineAndColumn() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "fileInExcludedDir.txt", excluded = true, status = 200)
|
||||
public fun inExcludedDir() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "bar/42/foo.txt", doNotCreate = true, status = 404)
|
||||
public fun relativeNonExistent() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "_tmp_", doNotCreate = true, status = 404)
|
||||
public fun absoluteNonExistent() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
Test
|
||||
Test(timeout = 60000)
|
||||
TestDescriptor(filePath = "_tmp_", status = 200)
|
||||
public fun absolute() {
|
||||
doTest()
|
||||
|
||||
+21
-8
@@ -39,7 +39,7 @@ import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends SingleRootFileViewProvider {
|
||||
private final ConcurrentMap<Language, PsiFile> myRoots = ContainerUtil.newConcurrentMap(1, 0.75f, 1);
|
||||
private final ConcurrentMap<Language, PsiFileImpl> myRoots = ContainerUtil.newConcurrentMap(1, 0.75f, 1);
|
||||
private MultiplePsiFilesPerDocumentFileViewProvider myOriginal = null;
|
||||
|
||||
public MultiplePsiFilesPerDocumentFileViewProvider(PsiManager manager, VirtualFile virtualFile, boolean eventSystemEnabled) {
|
||||
@@ -67,12 +67,15 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single
|
||||
}
|
||||
|
||||
protected void removeFile(final Language language) {
|
||||
myRoots.remove(language);
|
||||
PsiFileImpl file = myRoots.remove(language);
|
||||
if (file != null) {
|
||||
file.markInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiFile getPsiInner(@NotNull final Language target) {
|
||||
PsiFile file = myRoots.get(target);
|
||||
PsiFileImpl file = myRoots.get(target);
|
||||
if (file == null) {
|
||||
if (isPhysical()) {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
@@ -85,12 +88,12 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single
|
||||
if (target != getBaseLanguage() && !getLanguages().contains(target)) {
|
||||
return null;
|
||||
}
|
||||
file = createFile(target);
|
||||
file = (PsiFileImpl)createFile(target);
|
||||
if (file == null) return null;
|
||||
if (myOriginal != null) {
|
||||
final PsiFile originalFile = myOriginal.getPsi(target);
|
||||
if (originalFile != null) {
|
||||
((PsiFileImpl)file).setOriginalFile(originalFile);
|
||||
file.setOriginalFile(originalFile);
|
||||
}
|
||||
}
|
||||
file = ConcurrencyUtil.cacheOrGet(myRoots, target, file);
|
||||
@@ -120,7 +123,7 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single
|
||||
|
||||
@TestOnly
|
||||
public void checkAllTreesEqual() {
|
||||
Collection<PsiFile> roots = myRoots.values();
|
||||
Collection<PsiFileImpl> roots = myRoots.values();
|
||||
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getManager().getProject());
|
||||
documentManager.commitAllDocuments();
|
||||
for (PsiFile root : roots) {
|
||||
@@ -187,11 +190,21 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single
|
||||
public void contentsSynchronized() {
|
||||
super.contentsSynchronized();
|
||||
Set<Language> languages = getLanguages();
|
||||
for (Iterator<Map.Entry<Language, PsiFile>> iterator = myRoots.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<Language, PsiFile> entry = iterator.next();
|
||||
for (Iterator<Map.Entry<Language, PsiFileImpl>> iterator = myRoots.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<Language, PsiFileImpl> entry = iterator.next();
|
||||
if (!languages.contains(entry.getKey())) {
|
||||
PsiFileImpl file = entry.getValue();
|
||||
iterator.remove();
|
||||
file.markInvalidated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markInvalidated() {
|
||||
for (PsiFileImpl file : myRoots.values()) {
|
||||
file.markInvalidated();
|
||||
}
|
||||
super.markInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,9 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
|
||||
psiFile = createFile();
|
||||
boolean set = myPsiFile.compareAndSet(null, psiFile);
|
||||
if (!set) {
|
||||
if (psiFile instanceof PsiFileImpl) {
|
||||
((PsiFileImpl)psiFile).markInvalidated();
|
||||
}
|
||||
psiFile = myPsiFile.get();
|
||||
}
|
||||
}
|
||||
@@ -304,6 +307,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
|
||||
return contentSize > PersistentFSConstants.getMaxIntellisenseFileSize();
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
public static boolean isTooLargeForContentLoading(@NotNull VirtualFile vFile, final long contentSize) {
|
||||
return contentSize > PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD;
|
||||
}
|
||||
@@ -446,7 +450,10 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
|
||||
}
|
||||
|
||||
public void forceCachedPsi(@NotNull PsiFile psiFile) {
|
||||
myPsiFile.set(psiFile);
|
||||
PsiFile prev = myPsiFile.getAndSet(psiFile);
|
||||
if (prev != psiFile && prev instanceof PsiFileImpl) {
|
||||
((PsiFileImpl)prev).markInvalidated();
|
||||
}
|
||||
((PsiManagerEx)myManager).getFileManager().setViewProvider(getVirtualFile(), this);
|
||||
}
|
||||
|
||||
@@ -476,6 +483,13 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
|
||||
return getClass().getSimpleName() + "{myVirtualFile=" + myVirtualFile + ", content=" + getContent() + '}';
|
||||
}
|
||||
|
||||
public void markInvalidated() {
|
||||
PsiFile psiFile = myPsiFile.get();
|
||||
if (psiFile instanceof PsiFileImpl) {
|
||||
((PsiFileImpl)psiFile).markInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
private interface Content {
|
||||
CharSequence getText();
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ public class FileManagerImpl implements FileManager {
|
||||
|
||||
private void checkLanguageChange() {
|
||||
Map<VirtualFile, FileViewProvider> fileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
|
||||
Map<VirtualFile, FileViewProvider> originalFileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
|
||||
myVFileToViewProviderMap.clear();
|
||||
for (Iterator<VirtualFile> iterator = fileToPsiFileMap.keySet().iterator(); iterator.hasNext();) {
|
||||
VirtualFile vFile = iterator.next();
|
||||
@@ -140,6 +141,7 @@ public class FileManagerImpl implements FileManager {
|
||||
}
|
||||
}
|
||||
myVFileToViewProviderMap.putAll(fileToPsiFileMap);
|
||||
markInvalidations(originalFileToPsiFileMap);
|
||||
}
|
||||
|
||||
public void forceReload(@NotNull VirtualFile vFile) {
|
||||
@@ -175,15 +177,25 @@ public class FileManagerImpl implements FileManager {
|
||||
myConnection.disconnect();
|
||||
}
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
clearViewProviders();
|
||||
|
||||
myDisposed = true;
|
||||
}
|
||||
|
||||
private void clearViewProviders() {
|
||||
for (final FileViewProvider provider : myVFileToViewProviderMap.values()) {
|
||||
if (provider instanceof SingleRootFileViewProvider) {
|
||||
((SingleRootFileViewProvider)provider).markInvalidated();
|
||||
}
|
||||
}
|
||||
myVFileToViewProviderMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@TestOnly
|
||||
public void cleanupForNextTest() {
|
||||
myVFileToViewProviderMap.clear();
|
||||
clearViewProviders();
|
||||
myVFileToPsiDirMap.clear();
|
||||
processQueue();
|
||||
((PsiModificationTrackerImpl)myManager.getModificationTracker()).incCounter();
|
||||
}
|
||||
|
||||
@@ -222,9 +234,11 @@ public class FileManagerImpl implements FileManager {
|
||||
@Override
|
||||
public void setViewProvider(@NotNull final VirtualFile virtualFile, @Nullable final FileViewProvider fileViewProvider) {
|
||||
FileViewProvider prev = findCachedViewProvider(virtualFile);
|
||||
if (prev == fileViewProvider) return;
|
||||
if (prev != null) {
|
||||
DebugUtil.startPsiModification(null);
|
||||
try {
|
||||
((SingleRootFileViewProvider)prev).markInvalidated();
|
||||
DebugUtil.onInvalidated(prev);
|
||||
}
|
||||
finally {
|
||||
@@ -450,7 +464,10 @@ public class FileManagerImpl implements FileManager {
|
||||
myVFileToPsiDirMap.remove(file);
|
||||
}
|
||||
else {
|
||||
myVFileToViewProviderMap.remove(file);
|
||||
FileViewProvider viewProvider = myVFileToViewProviderMap.remove(file);
|
||||
if (viewProvider instanceof SingleRootFileViewProvider) {
|
||||
((SingleRootFileViewProvider)viewProvider).markInvalidated();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -499,6 +516,7 @@ public class FileManagerImpl implements FileManager {
|
||||
|
||||
// note: important to update directories map first - findFile uses findDirectory!
|
||||
Map<VirtualFile, FileViewProvider> fileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
|
||||
Map<VirtualFile, FileViewProvider> originalFileToPsiFileMap = new THashMap<VirtualFile, FileViewProvider>(myVFileToViewProviderMap);
|
||||
if (useFind) {
|
||||
myVFileToViewProviderMap.clear();
|
||||
}
|
||||
@@ -535,6 +553,17 @@ public class FileManagerImpl implements FileManager {
|
||||
}
|
||||
myVFileToViewProviderMap.clear();
|
||||
myVFileToViewProviderMap.putAll(fileToPsiFileMap);
|
||||
|
||||
markInvalidations(originalFileToPsiFileMap);
|
||||
}
|
||||
|
||||
private void markInvalidations(Map<VirtualFile, FileViewProvider> originalFileToPsiFileMap) {
|
||||
for (Map.Entry<VirtualFile, FileViewProvider> entry : originalFileToPsiFileMap.entrySet()) {
|
||||
FileViewProvider viewProvider = entry.getValue();
|
||||
if (viewProvider instanceof SingleRootFileViewProvider && myVFileToViewProviderMap.get(entry.getKey()) != viewProvider) {
|
||||
((SingleRootFileViewProvider)viewProvider).markInvalidated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,6 +71,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
protected PsiFile myOriginalFile = null;
|
||||
private final FileViewProvider myViewProvider;
|
||||
private volatile Reference<StubTree> myStub;
|
||||
private boolean myInvalidated;
|
||||
protected final PsiManagerEx myManager;
|
||||
private volatile Getter<FileElement> myTreeElementPointer; // SoftReference/WeakReference to ASTNode or a strong reference to a tree if the file is a DummyHolder
|
||||
public static final Key<Boolean> BUILDING_STUB = new Key<Boolean>("Don't use stubs mark!");
|
||||
@@ -147,22 +148,21 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
FileViewProvider provider = getViewProvider();
|
||||
final VirtualFile vFile = provider.getVirtualFile();
|
||||
if (!vFile.isValid()) return false;
|
||||
if (!provider.isEventSystemEnabled()) return true; // "dummy" file
|
||||
if (myManager.getProject().isDisposed()) return false;
|
||||
return isPsiUpToDate(vFile);
|
||||
if (myManager.getProject().isDisposed()) {
|
||||
// normally FileManager.dispose would call markInvalidated
|
||||
// but there's temporary disposed project in tests, which doesn't actually dispose its components :(
|
||||
return false;
|
||||
}
|
||||
if (!myViewProvider.getVirtualFile().isValid()) {
|
||||
// PSI listeners receive VFS deletion events and do markInvalidated
|
||||
// but some VFS listeners receive the same events before that and ask PsiFile.isValid
|
||||
return false;
|
||||
}
|
||||
return !myInvalidated;
|
||||
}
|
||||
|
||||
protected boolean isPsiUpToDate(@NotNull VirtualFile vFile) {
|
||||
final FileViewProvider provider = myManager.findViewProvider(vFile);
|
||||
Language language = getLanguage();
|
||||
if (provider == null || provider.getPsi(language) == this) { // provider == null in tests
|
||||
return true;
|
||||
}
|
||||
Language baseLanguage = provider.getBaseLanguage();
|
||||
return baseLanguage != language && provider.getPsi(baseLanguage) == this;
|
||||
public void markInvalidated() {
|
||||
myInvalidated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -711,7 +711,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiManager getManager() {
|
||||
public final PsiManager getManager() {
|
||||
return myManager;
|
||||
}
|
||||
|
||||
@@ -929,11 +929,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Project getProject() {
|
||||
final PsiManager manager = getManager();
|
||||
if (manager == null) throw new PsiInvalidElementAccessException(this);
|
||||
|
||||
return manager.getProject();
|
||||
public final Project getProject() {
|
||||
return getManager().getProject();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+45
-41
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve.reference;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.patterns.*;
|
||||
@@ -24,43 +25,53 @@ import com.intellij.psi.PsiReferenceRegistrar;
|
||||
import com.intellij.psi.PsiReferenceService;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import gnu.trove.THashMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.resolve.reference.PsiReferenceRegistrarImpl");
|
||||
private final Map<Class, SimpleProviderBinding<PsiReferenceProvider>> myBindingsMap = new THashMap<Class, SimpleProviderBinding<PsiReferenceProvider>>();
|
||||
private final Map<Class, NamedObjectProviderBinding<PsiReferenceProvider>> myNamedBindingsMap = new THashMap<Class, NamedObjectProviderBinding<PsiReferenceProvider>>();
|
||||
private final FactoryMap<Class, Class[]> myKnownSupers = new ConcurrentFactoryMap<Class, Class[]>() {
|
||||
@Override
|
||||
protected Class[] create(Class key) {
|
||||
final Set<Class> result = new LinkedHashSet<Class>();
|
||||
for (Class candidate : myBindingsMap.keySet()) {
|
||||
if (candidate.isAssignableFrom(key)) {
|
||||
result.add(candidate);
|
||||
}
|
||||
}
|
||||
for (Class candidate : myNamedBindingsMap.keySet()) {
|
||||
if (candidate.isAssignableFrom(key)) {
|
||||
result.add(candidate);
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
return ArrayUtil.EMPTY_CLASS_ARRAY;
|
||||
}
|
||||
return result.toArray(new Class[result.size()]);
|
||||
}
|
||||
};
|
||||
private final Map<Class<?>, SimpleProviderBinding<PsiReferenceProvider>> myBindingsMap = ContainerUtil.newTroveMap();
|
||||
private final Map<Class<?>, NamedObjectProviderBinding<PsiReferenceProvider>> myNamedBindingsMap = ContainerUtil.newTroveMap();
|
||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
||||
private final ConcurrentFactoryMap<Class, ProviderBinding<PsiReferenceProvider>[]> myBindingCache;
|
||||
private boolean myInitialized;
|
||||
|
||||
public PsiReferenceRegistrarImpl(final Language language) {
|
||||
myBindingCache = new ConcurrentFactoryMap<Class, ProviderBinding<PsiReferenceProvider>[]>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected ProviderBinding<PsiReferenceProvider>[] create(Class key) {
|
||||
List<ProviderBinding<PsiReferenceProvider>> result = ContainerUtil.newSmartList();
|
||||
for (Class<?> bindingClass : myBindingsMap.keySet()) {
|
||||
if (bindingClass.isAssignableFrom(key)) {
|
||||
result.add(myBindingsMap.get(bindingClass));
|
||||
}
|
||||
}
|
||||
for (Class<?> bindingClass : myNamedBindingsMap.keySet()) {
|
||||
if (bindingClass.isAssignableFrom(key)) {
|
||||
result.add(myNamedBindingsMap.get(bindingClass));
|
||||
}
|
||||
}
|
||||
if (language != Language.ANY) {
|
||||
final PsiReferenceRegistrar anyRegistrar = ReferenceProvidersRegistry.getInstance().getRegistrar(Language.ANY);
|
||||
Collections.addAll(result, ((PsiReferenceRegistrarImpl)anyRegistrar).myBindingCache.get(key));
|
||||
}
|
||||
//noinspection unchecked
|
||||
return result.toArray(new ProviderBinding[result.size()]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void markInitialized() {
|
||||
myInitialized = true;
|
||||
}
|
||||
@@ -73,7 +84,6 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
LOG.error("Reference provider registration is only allowed from PsiReferenceContributor");
|
||||
}
|
||||
|
||||
myKnownSupers.clear(); // we should clear the cache
|
||||
final Class scope = pattern.getCondition().getInitialCondition().getAcceptedClass();
|
||||
final List<PatternCondition<? super T>> conditions = pattern.getCondition().getConditions();
|
||||
for (PatternCondition<? super T> _condition : conditions) {
|
||||
@@ -102,6 +112,8 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
myBindingsMap.put(scope, providerBinding = new SimpleProviderBinding<PsiReferenceProvider>());
|
||||
}
|
||||
providerBinding.registerProvider(provider, pattern, priority);
|
||||
|
||||
myBindingCache.clear();
|
||||
}
|
||||
|
||||
public void unregisterReferenceProvider(@NotNull Class scope, @NotNull PsiReferenceProvider provider) {
|
||||
@@ -141,22 +153,14 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar {
|
||||
@NotNull
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider,ProcessingContext>> getPairsByElement(@NotNull PsiElement element,
|
||||
@NotNull PsiReferenceService.Hints hints) {
|
||||
final Class<? extends PsiElement> clazz = element.getClass();
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>> ret = null;
|
||||
|
||||
for (Class aClass : myKnownSupers.get(clazz)) {
|
||||
SimpleProviderBinding<PsiReferenceProvider> simpleBinding = myBindingsMap.get(aClass);
|
||||
NamedObjectProviderBinding<PsiReferenceProvider> namedBinding = myNamedBindingsMap.get(aClass);
|
||||
if (simpleBinding == null && namedBinding == null) continue;
|
||||
final ProviderBinding<PsiReferenceProvider>[] bindings = myBindingCache.get(element.getClass());
|
||||
if (bindings.length == 0) return Collections.emptyList();
|
||||
|
||||
if (ret == null) ret = new SmartList<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>>();
|
||||
if (simpleBinding != null) {
|
||||
simpleBinding.addAcceptableReferenceProviders(element, ret, hints);
|
||||
}
|
||||
if (namedBinding != null) {
|
||||
namedBinding.addAcceptableReferenceProviders(element, ret, hints);
|
||||
}
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>> ret = ContainerUtil.newSmartList();
|
||||
for (ProviderBinding<PsiReferenceProvider> binding : bindings) {
|
||||
binding.addAcceptableReferenceProviders(element, ret, hints);
|
||||
}
|
||||
return ret == null ? Collections.<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>>emptyList() : ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-6
@@ -20,7 +20,6 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -48,7 +47,7 @@ public abstract class ReferenceProvidersRegistry {
|
||||
public abstract PsiReferenceRegistrar getRegistrar(@NotNull Language language);
|
||||
|
||||
/**
|
||||
* @see #getReferencesFromProviders(com.intellij.psi.PsiElement)
|
||||
* @see #getReferencesFromProviders(PsiElement)
|
||||
*/
|
||||
@Deprecated
|
||||
@NotNull
|
||||
@@ -64,10 +63,7 @@ public abstract class ReferenceProvidersRegistry {
|
||||
@NotNull
|
||||
public static PsiReference[] getReferencesFromProviders(@NotNull PsiElement context, @NotNull PsiReferenceService.Hints hints) {
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
PsiUtilCore.ensureValid(context);
|
||||
|
||||
ReferenceProvidersRegistry registry = getInstance();
|
||||
return registry.doGetReferencesFromProviders(context, hints);
|
||||
return getInstance().doGetReferencesFromProviders(context, hints);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+54
-58
@@ -23,7 +23,6 @@ import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@@ -41,82 +40,79 @@ public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry {
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
|
||||
private final Map<Language, PsiReferenceRegistrarImpl> myRegistrars = new FactoryMap<Language, PsiReferenceRegistrarImpl>() {
|
||||
@Override
|
||||
protected PsiReferenceRegistrarImpl create(Language language) {
|
||||
PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl();
|
||||
for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguage(language)) {
|
||||
contributor.registerReferenceProviders(registrar);
|
||||
}
|
||||
private final Map<Language, PsiReferenceRegistrarImpl> myRegistrars = ContainerUtil.newConcurrentMap();
|
||||
|
||||
List<PsiReferenceProviderBean> referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguage(language);
|
||||
for (final PsiReferenceProviderBean providerBean : referenceProviderBeans) {
|
||||
final ElementPattern<PsiElement> pattern = providerBean.createElementPattern();
|
||||
if (pattern != null) {
|
||||
registrar.registerReferenceProvider(pattern, new PsiReferenceProvider() {
|
||||
|
||||
PsiReferenceProvider myProvider;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
|
||||
if (myProvider == null) {
|
||||
|
||||
myProvider = providerBean.instantiate();
|
||||
if (myProvider == null) {
|
||||
myProvider = NULL_REFERENCE_PROVIDER;
|
||||
}
|
||||
}
|
||||
return myProvider.getReferencesByElement(element, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
registrar.markInitialized();
|
||||
|
||||
return registrar;
|
||||
@NotNull
|
||||
private static PsiReferenceRegistrarImpl createRegistrar(Language language) {
|
||||
PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl(language);
|
||||
for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguage(language)) {
|
||||
contributor.registerReferenceProviders(registrar);
|
||||
}
|
||||
};
|
||||
|
||||
List<PsiReferenceProviderBean> referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguage(language);
|
||||
for (final PsiReferenceProviderBean providerBean : referenceProviderBeans) {
|
||||
final ElementPattern<PsiElement> pattern = providerBean.createElementPattern();
|
||||
if (pattern != null) {
|
||||
registrar.registerReferenceProvider(pattern, new PsiReferenceProvider() {
|
||||
|
||||
PsiReferenceProvider myProvider;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
|
||||
if (myProvider == null) {
|
||||
|
||||
myProvider = providerBean.instantiate();
|
||||
if (myProvider == null) {
|
||||
myProvider = NULL_REFERENCE_PROVIDER;
|
||||
}
|
||||
}
|
||||
return myProvider.getReferencesByElement(element, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
registrar.markInitialized();
|
||||
|
||||
return registrar;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public synchronized PsiReferenceRegistrarImpl getRegistrar(@NotNull Language language) {
|
||||
return myRegistrars.get(language);
|
||||
public PsiReferenceRegistrarImpl getRegistrar(@NotNull Language language) {
|
||||
PsiReferenceRegistrarImpl registrar = myRegistrars.get(language);
|
||||
if (registrar == null) {
|
||||
//noinspection SynchronizeOnThis
|
||||
synchronized (this) {
|
||||
registrar = myRegistrars.get(language);
|
||||
if (registrar == null) {
|
||||
myRegistrars.put(language, registrar = createRegistrar(language));
|
||||
}
|
||||
}
|
||||
}
|
||||
return registrar;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiReference[] doGetReferencesFromProviders(@NotNull PsiElement context,
|
||||
@NotNull PsiReferenceService.Hints hints) {
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>> providersForContextLanguage =
|
||||
getRegistrar(context.getLanguage()).getPairsByElement(context, hints);
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>> providers = getRegistrar(context.getLanguage()).getPairsByElement(context, hints);
|
||||
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>> providersForAllLanguages =
|
||||
getRegistrar(Language.ANY).getPairsByElement(context, hints);
|
||||
|
||||
int providersCount = providersForContextLanguage.size() + providersForAllLanguages.size();
|
||||
|
||||
if (providersCount == 0) {
|
||||
if (providers.isEmpty()) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
if (providersCount == 1) {
|
||||
final ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext> firstProvider =
|
||||
(providersForAllLanguages.isEmpty() ? providersForContextLanguage : providersForAllLanguages).get(0);
|
||||
return firstProvider.provider.getReferencesByElement(context, firstProvider.processingContext);
|
||||
if (providers.size() == 1) {
|
||||
return providers.get(0).provider.getReferencesByElement(context, providers.get(0).processingContext);
|
||||
}
|
||||
|
||||
List<ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>> list =
|
||||
ContainerUtil.concat(providersForContextLanguage, providersForAllLanguages);
|
||||
@SuppressWarnings("unchecked")
|
||||
ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext>[] providers = list.toArray(new ProviderBinding.ProviderInfo[list.size()]);
|
||||
|
||||
Arrays.sort(providers, PRIORITY_COMPARATOR);
|
||||
ContainerUtil.sort(providers, PRIORITY_COMPARATOR);
|
||||
|
||||
List<PsiReference> result = new ArrayList<PsiReference>();
|
||||
final double maxPriority = providers[0].priority;
|
||||
final double maxPriority = providers.get(0).priority;
|
||||
next:
|
||||
for (ProviderBinding.ProviderInfo<PsiReferenceProvider, ProcessingContext> trinity : providers) {
|
||||
final PsiReference[] refs;
|
||||
|
||||
@@ -97,8 +97,8 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
|
||||
public boolean ACTIVATE_RIGHT_EDITOR_ON_CLOSE = false;
|
||||
@Deprecated
|
||||
public boolean ANTIALIASING_IN_EDITOR = true;
|
||||
public boolean ANTIALIASING_IN_IDE = !UIUtil.isRetina() && ANTIALIASING_IN_EDITOR;
|
||||
public LCDRenderingScope LCD_RENDERING_SCOPE = LCDRenderingScope.IDE;
|
||||
public boolean ANTIALIASING_IN_IDE = ANTIALIASING_IN_EDITOR;
|
||||
public LCDRenderingScope LCD_RENDERING_SCOPE = UIUtil.isRetina() ? LCDRenderingScope.OFF : LCDRenderingScope.IDE;
|
||||
public boolean USE_LCD_RENDERING_IN_EDITOR = true;
|
||||
public boolean MOVE_MOUSE_ON_DEFAULT_BUTTON = false;
|
||||
public boolean ENABLE_ALPHA_MODE = false;
|
||||
|
||||
@@ -302,4 +302,11 @@ public interface Caret extends UserDataHolderEx, Disposable {
|
||||
* to offset and logical column number in the vicinity of caret.
|
||||
*/
|
||||
boolean isAtRtlLocation();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if caret is located at a boundary between LTR and RTL text fragments. Caret can located at any side of the
|
||||
* boundary, exact location can be determined from directionality flags of caret's logical and visual position
|
||||
* ({@link LogicalPosition#leansForward} and {@link VisualPosition#leansRight}).
|
||||
*/
|
||||
boolean isAtDirectionBoundary();
|
||||
}
|
||||
|
||||
@@ -77,6 +77,13 @@ public class VisualPosition {
|
||||
return line > other.line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>VisualPosition</code> instance with a given value of {@link #leansRight} flag.
|
||||
*/
|
||||
public VisualPosition leanRight(boolean value) {
|
||||
return new VisualPosition(line, column, value);
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
return "VisualPosition: (" + line + ", " + column+")" + (leansRight ? " leans right" : "");
|
||||
|
||||
+16
-8
@@ -94,22 +94,30 @@ public class LiftShorterItemsClassifier extends Classifier<LookupElement> {
|
||||
}
|
||||
|
||||
private void internListToLift(LookupElement longer) {
|
||||
myToLift.put(longer, myListInterner.intern(myToLift.get(longer)));
|
||||
final Collection<LookupElement> elements = myToLift.get(longer);
|
||||
if (elements.size() > 10) return;
|
||||
|
||||
myToLift.put(longer, myListInterner.intern(elements));
|
||||
}
|
||||
|
||||
private void calculateToLift(LookupElement element) {
|
||||
boolean hasChanges = false;
|
||||
for (String string : element.getAllLookupStrings()) {
|
||||
for (int len = 1; len < string.length(); len++) {
|
||||
String prefix = string.substring(0, len);
|
||||
for (LookupElement shorterElement : myElements.get(prefix)) {
|
||||
if (myCondition.shouldLift(shorterElement, element)) {
|
||||
hasChanges = true;
|
||||
myToLift.putValue(element, shorterElement);
|
||||
try {
|
||||
for (String string : element.getAllLookupStrings()) {
|
||||
for (int len = 1; len < string.length(); len++) {
|
||||
String prefix = string.substring(0, len);
|
||||
for (LookupElement shorterElement : myElements.get(prefix)) {
|
||||
if (myCondition.shouldLift(shorterElement, element)) {
|
||||
hasChanges = true;
|
||||
myToLift.putValue(element, shorterElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
||||
throw new RuntimeException("Error while traversing lookup strings of " + element + " of " + element.getClass(), e);
|
||||
}
|
||||
if (hasChanges) {
|
||||
internListToLift(element);
|
||||
}
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.codeInsight.daemon.impl;
|
||||
|
||||
import com.intellij.codeInsight.intention.AbstractIntentionAction;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
class GutterIntentionAction extends AbstractIntentionAction implements Comparable<IntentionAction> {
|
||||
private final AnAction myAction;
|
||||
private final EditorEx myEditor;
|
||||
private final String myText;
|
||||
|
||||
public GutterIntentionAction(AnAction action, String text, EditorEx editor) {
|
||||
myAction = action;
|
||||
myEditor = editor;
|
||||
myText = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final RelativePoint relativePoint = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
|
||||
myAction.actionPerformed(
|
||||
new AnActionEvent(relativePoint.toMouseEvent(), myEditor.getDataContext(), myText, new Presentation(),
|
||||
ActionManager.getInstance(), 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
static void addActions(RangeHighlighterEx info,
|
||||
EditorEx editor,
|
||||
List<HighlightInfo.IntentionActionDescriptor> descriptors) {
|
||||
final GutterIconRenderer renderer = info.getGutterIconRenderer();
|
||||
if (renderer == null) {
|
||||
return;
|
||||
}
|
||||
addActions(renderer.getClickAction(), editor, descriptors, renderer);
|
||||
addActions(renderer.getMiddleButtonClickAction(), editor, descriptors, renderer);
|
||||
addActions(renderer.getRightButtonClickAction(), editor, descriptors, renderer);
|
||||
addActions(renderer.getPopupMenuActions(), editor, descriptors, renderer);
|
||||
}
|
||||
|
||||
private static void addActions(AnAction action,
|
||||
EditorEx editor,
|
||||
List<HighlightInfo.IntentionActionDescriptor> descriptors,
|
||||
GutterIconRenderer renderer) {
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
if (action instanceof ActionGroup) {
|
||||
AnAction[] children = ((ActionGroup)action).getChildren(null);
|
||||
for (AnAction child : children) {
|
||||
addActions(child, editor, descriptors, renderer);
|
||||
}
|
||||
}
|
||||
AnActionEvent event = AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, editor.getDataContext());
|
||||
action.update(event);
|
||||
String text = event.getPresentation().getText();
|
||||
if (text == null) text = action.getTemplatePresentation().getText();
|
||||
if (text == null) {
|
||||
return;
|
||||
}
|
||||
final IntentionAction actionAdapter = new GutterIntentionAction(action, text, editor);
|
||||
Icon icon = action.getTemplatePresentation().getIcon();
|
||||
if (icon == null) icon = renderer.getIcon();
|
||||
HighlightInfo.IntentionActionDescriptor descriptor =
|
||||
new HighlightInfo.IntentionActionDescriptor(actionAdapter, Collections.<IntentionAction>emptyList(), text, icon);
|
||||
descriptors.add(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(IntentionAction o) {
|
||||
if (o instanceof GutterIntentionAction) {
|
||||
AnAction other = ((GutterIntentionAction)o).myAction;
|
||||
if (myAction instanceof Comparable) {
|
||||
return ((Comparable)myAction).compareTo(other);
|
||||
}
|
||||
else if (other instanceof Comparable) {
|
||||
return -((Comparable)other).compareTo(myAction);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+10
-46
@@ -19,7 +19,6 @@ package com.intellij.codeInsight.daemon.impl;
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.codeInsight.intention.AbstractIntentionAction;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.IntentionManager;
|
||||
import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
|
||||
@@ -28,12 +27,7 @@ import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateState;
|
||||
import com.intellij.codeInspection.actions.CleanupAllIntention;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -41,11 +35,12 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.editor.ex.MarkupModelEx;
|
||||
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
|
||||
import com.intellij.openapi.editor.impl.DocumentMarkupModel;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.IntentionFilterOwner;
|
||||
@@ -53,8 +48,6 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -63,7 +56,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -315,43 +307,15 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
|
||||
}
|
||||
|
||||
final int line = hostDocument.getLineNumber(offset);
|
||||
DaemonCodeAnalyzerEx.processHighlights(hostDocument, project, null,
|
||||
hostDocument.getLineStartOffset(line),
|
||||
hostDocument.getLineEndOffset(line), new Processor<HighlightInfo>() {
|
||||
@Override
|
||||
public boolean process(HighlightInfo info) {
|
||||
final GutterIconRenderer renderer = (GutterIconRenderer)info.getGutterIconRenderer();
|
||||
if (renderer == null) {
|
||||
MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(hostDocument, project, true);
|
||||
model.processRangeHighlightersOverlappingWith(hostDocument.getLineStartOffset(line),
|
||||
hostDocument.getLineEndOffset(line), new Processor<RangeHighlighterEx>() {
|
||||
@Override
|
||||
public boolean process(RangeHighlighterEx highlighter) {
|
||||
GutterIntentionAction.addActions(highlighter, (EditorEx)hostEditor, intentions.guttersToShow);
|
||||
return true;
|
||||
}
|
||||
final AnAction action = renderer.getClickAction();
|
||||
if (action == null) {
|
||||
return true;
|
||||
}
|
||||
final String text = renderer.getTooltipText();
|
||||
if (text == null) {
|
||||
return true;
|
||||
}
|
||||
final IntentionAction actionAdapter = new AbstractIntentionAction() {
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final RelativePoint relativePoint = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
|
||||
action.actionPerformed(
|
||||
new AnActionEvent(relativePoint.toMouseEvent(), DataManager.getInstance().getDataContext(), text, new Presentation(),
|
||||
ActionManager.getInstance(), 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
intentions.guttersToShow.add(
|
||||
new HighlightInfo.IntentionActionDescriptor(actionAdapter, Collections.<IntentionAction>emptyList(), text, renderer.getIcon()));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
boolean cleanup = appendCleanupCode(intentions.inspectionFixesToShow, hostFile);
|
||||
if (!cleanup) {
|
||||
|
||||
+4
-2
@@ -36,7 +36,6 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.*;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
@@ -310,7 +309,7 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
|
||||
if (weight1 != weight2) {
|
||||
return weight2 - weight1;
|
||||
}
|
||||
return Comparing.compare(o1.getText(), o2.getText());
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
@@ -355,6 +354,9 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
|
||||
if (myCachedInspectionFixes.contains(action)) {
|
||||
return 10;
|
||||
}
|
||||
if (myCachedGutters.contains(action)) {
|
||||
return 5;
|
||||
}
|
||||
if (action.getAction() instanceof EmptyIntentionAction) {
|
||||
return -10;
|
||||
}
|
||||
|
||||
@@ -19,24 +19,16 @@ import com.intellij.codeHighlighting.Pass;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.ExecutorRegistry;
|
||||
import com.intellij.execution.Location;
|
||||
import com.intellij.execution.PsiLocation;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.impl.ActionPopupMenuImpl;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -60,67 +52,35 @@ public class RunLineMarkerInfo extends LineMarkerInfo<PsiElement> {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ActionGroup getPopupMenuActions() {
|
||||
List<AnAction> actions = new ArrayList<AnAction>();
|
||||
Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors();
|
||||
actions.addAll(ContainerUtil.mapNotNull(executors,
|
||||
new Function<Executor, AnAction>() {
|
||||
@Override
|
||||
public AnAction fun(Executor executor) {
|
||||
return ActionManager.getInstance().getAction(executor.getContextActionId());
|
||||
}
|
||||
}));
|
||||
actions.add(Separator.getInstance());
|
||||
actions.addAll(ContainerUtil.mapNotNull(RunLineMarkerContributor.EXTENSION.allForLanguage(myElement.getLanguage()),
|
||||
new NullableFunction<RunLineMarkerContributor, AnAction>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public AnAction fun(RunLineMarkerContributor contributor) {
|
||||
return contributor.getAdditionalAction(myElement);
|
||||
}
|
||||
}));
|
||||
|
||||
return new DefaultActionGroup(actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnAction getClickAction() {
|
||||
return new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
List<AnAction> actions = new ArrayList<AnAction>();
|
||||
Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors();
|
||||
actions.addAll(ContainerUtil.mapNotNull(executors,
|
||||
new Function<Executor, AnAction>() {
|
||||
@Override
|
||||
public AnAction fun(Executor executor) {
|
||||
return ActionManager.getInstance().getAction(executor.getContextActionId());
|
||||
}
|
||||
}));
|
||||
actions.add(Separator.getInstance());
|
||||
actions.addAll(ContainerUtil.mapNotNull(RunLineMarkerContributor.EXTENSION.allForLanguage(myElement.getLanguage()),
|
||||
new NullableFunction<RunLineMarkerContributor, AnAction>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public AnAction fun(RunLineMarkerContributor contributor) {
|
||||
return contributor.getAdditionalAction(myElement);
|
||||
}
|
||||
}));
|
||||
|
||||
ActionPopupMenuImpl
|
||||
popupMenu = (ActionPopupMenuImpl)ActionManager.getInstance().createActionPopupMenu(ActionPlaces.EDITOR_POPUP,
|
||||
new DefaultActionGroup(actions));
|
||||
final MouseEvent me = (MouseEvent)e.getInputEvent();
|
||||
final Component c = me.getComponent();
|
||||
if (c != null && c.isShowing()) {
|
||||
final DataContext delegate = DataManager.getInstance().getDataContext(c, me.getX(), me.getY());
|
||||
final DataContext dataContext = new MyDataContext(myElement, delegate);
|
||||
popupMenu.setDataContextProvider(new Getter<DataContext>() {
|
||||
@Override
|
||||
public DataContext get() {
|
||||
return dataContext;
|
||||
}
|
||||
});
|
||||
popupMenu.getComponent().show(c, me.getX(), me.getY());
|
||||
}
|
||||
}
|
||||
};
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class MyDataContext extends UserDataHolderBase implements DataContext {
|
||||
private final PsiElement myElement;
|
||||
private final DataContext myDelegate;
|
||||
|
||||
public MyDataContext(PsiElement element, DataContext delegate) {
|
||||
myElement = element;
|
||||
myDelegate = delegate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NonNls String dataId) {
|
||||
if (Location.DATA_KEY.is(dataId)) return new PsiLocation<PsiElement>(myElement);
|
||||
return myDelegate.getData(dataId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1761,6 +1761,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
classes.add(o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
-6
@@ -18,7 +18,6 @@ package com.intellij.ide.projectView.impl.nodes;
|
||||
|
||||
import com.intellij.ide.projectView.ViewSettings;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleFileIndex;
|
||||
@@ -35,16 +34,11 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ProjectViewModuleNode extends AbstractModuleNode {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.projectView.impl.nodes.ProjectViewModuleNode");
|
||||
|
||||
public ProjectViewModuleNode(Project project, Module value, ViewSettings viewSettings) {
|
||||
super(project, value, viewSettings);
|
||||
}
|
||||
|
||||
public ProjectViewModuleNode(Project project, Object value, ViewSettings viewSettings) {
|
||||
this(project, (Module)value, viewSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Collection<AbstractTreeNode> getChildren() {
|
||||
|
||||
@@ -275,9 +275,14 @@ public abstract class ChooseByNameBase {
|
||||
|
||||
@Override
|
||||
public Object getData(String dataId) {
|
||||
if (PlatformDataKeys.SEARCH_INPUT_TEXT.is(dataId)) {
|
||||
return myTextField == null ? null : myTextField.getText();
|
||||
}
|
||||
|
||||
if (PlatformDataKeys.HELP_ID.is(dataId)) {
|
||||
return myModel.getHelpId();
|
||||
}
|
||||
|
||||
if (myCalcElementsThread != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -242,4 +242,9 @@ public class InjectedCaret implements Caret {
|
||||
public boolean isAtRtlLocation() {
|
||||
return myDelegate.isAtRtlLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAtDirectionBoundary() {
|
||||
return myDelegate.isAtDirectionBoundary();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +566,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
|
||||
if (oldElement.getClass().equals(newElement.getClass())) {
|
||||
treeEvent.setOldParent(oldParentDir);
|
||||
treeEvent.setNewParent(newParentDir);
|
||||
treeEvent.setChild(newElement);
|
||||
treeEvent.setChild(oldElement);
|
||||
myManager.childMoved(treeEvent);
|
||||
}
|
||||
else {
|
||||
|
||||
+2
-6
@@ -197,19 +197,15 @@ public abstract class ChangeSignatureDialogBase<ParamInfo extends ParameterInfo,
|
||||
}
|
||||
return table;
|
||||
}
|
||||
if (isFocusable(myNameField)) {
|
||||
if (UIUtil.isFocusable(myNameField)) {
|
||||
return myNameField;
|
||||
}
|
||||
if (isFocusable(myReturnTypeField)) {
|
||||
if (UIUtil.isFocusable(myReturnTypeField)) {
|
||||
return myReturnTypeField;
|
||||
}
|
||||
return super.getPreferredFocusedComponent();
|
||||
}
|
||||
|
||||
private static boolean isFocusable(JComponent component) {
|
||||
return component != null && component.isFocusable() && component.isEnabled() && component.isShowing();
|
||||
}
|
||||
|
||||
protected int getSelectedIdx() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.util.List;
|
||||
* Interface for a custom step in a list popup.
|
||||
*
|
||||
* @see ListPopup
|
||||
* @see com.intellij.openapi.ui.popup.JBPopupFactory#createListPopup(ListPopupStep)
|
||||
* @see JBPopupFactory#createListPopup(ListPopupStep)
|
||||
* @since 6.0
|
||||
*/
|
||||
public interface ListPopupStep<T> extends PopupStep<T> {
|
||||
|
||||
+10
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -69,8 +69,14 @@ class MoveCaretLeftOrRightHandler extends EditorActionHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
final boolean scrollToCaret = (!(editor instanceof EditorImpl) || ((EditorImpl)editor).isScrollToCaret())
|
||||
&& caret == editor.getCaretModel().getPrimaryCaret();
|
||||
caretModel.moveCaretRelatively(myDirection == Direction.RIGHT ? 1 : -1, 0, false, false, scrollToCaret);
|
||||
VisualPosition currentPosition = caret.getVisualPosition();
|
||||
if (caret.isAtDirectionBoundary() && (myDirection == Direction.RIGHT ^ currentPosition.leansRight)) {
|
||||
caret.moveToVisualPosition(currentPosition.leanRight(!currentPosition.leansRight));
|
||||
}
|
||||
else {
|
||||
final boolean scrollToCaret = (!(editor instanceof EditorImpl) || ((EditorImpl)editor).isScrollToCaret())
|
||||
&& caret == editor.getCaretModel().getPrimaryCaret();
|
||||
caretModel.moveCaretRelatively(myDirection == Direction.RIGHT ? 1 : -1, 0, false, false, scrollToCaret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,6 +267,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
|
||||
|
||||
int newLineNumber = visualCaret.line + lineShift;
|
||||
int newColumnNumber = visualCaret.column + columnShift;
|
||||
boolean newLeansRight = lineShift == 0 && columnShift != 0 ? columnShift < 0 : visualCaret.leansRight;
|
||||
|
||||
if (desiredX >= 0) {
|
||||
newColumnNumber = myEditor.xyToVisualPosition(new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight())).column;
|
||||
}
|
||||
@@ -305,13 +307,14 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
|
||||
|
||||
VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber);
|
||||
if (!myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
|
||||
LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber));
|
||||
LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber, newLeansRight));
|
||||
int offset = myEditor.logicalPositionToOffset(log);
|
||||
if (offset >= document.getTextLength()) {
|
||||
int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength()).column;
|
||||
int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength(), true).column;
|
||||
// We want to move caret to the last column if if it's located at the last line and 'Down' is pressed.
|
||||
if (lastOffsetColumn > newColumnNumber) {
|
||||
newColumnNumber = lastOffsetColumn;
|
||||
newLeansRight = true;
|
||||
desiredX = -1;
|
||||
lastColumnNumber = -1;
|
||||
}
|
||||
@@ -321,7 +324,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
|
||||
if (offset >= 0 && offset < document.getTextLength()) {
|
||||
if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) {
|
||||
if (columnShift <= 0) {
|
||||
newColumnNumber = myEditor.offsetToVisualPosition(offset).column;
|
||||
newColumnNumber = myEditor.offsetToVisualPosition(offset, true).column;
|
||||
}
|
||||
else {
|
||||
SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1);
|
||||
@@ -339,7 +342,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
|
||||
}
|
||||
}
|
||||
|
||||
pos = new VisualPosition(newLineNumber, newColumnNumber);
|
||||
pos = new VisualPosition(newLineNumber, newColumnNumber, newLeansRight);
|
||||
if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) {
|
||||
LogicalPosition logical = myEditor.visualToLogicalPosition(pos);
|
||||
int softWrapOffset = myEditor.logicalPositionToOffset(logical);
|
||||
@@ -1466,6 +1469,11 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
|
||||
return myEditor.myUseNewRendering && myEditor.myView.isRtlLocation(myOffset, myLogicalCaret.leansForward);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAtDirectionBoundary() {
|
||||
return myEditor.myUseNewRendering && myEditor.myView.isDirectionBoundary(myOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates information about target vertical range info - its <code>'y'</code> coordinate and height in pixels.
|
||||
*/
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ContextMenuImpl extends JPanel implements Disposable {
|
||||
final Rectangle r = viewport.getBounds();
|
||||
final Point viewPosition = viewport.getViewPosition();
|
||||
|
||||
final Rectangle activationArea = new Rectangle(0, 0, r.width, 150);
|
||||
final Rectangle activationArea = new Rectangle(0, 0, r.width, r.height);
|
||||
return activationArea.contains(p.x, p.y - viewPosition.y);
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -1354,13 +1354,18 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.isPopupTrigger()) {
|
||||
if (e.isPopupTrigger() || isPopupAction(e)) {
|
||||
invokePopup(e);
|
||||
} else if (UIUtil.isCloseClick(e)) {
|
||||
processClose(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPopupAction(MouseEvent e) {
|
||||
GutterIconRenderer renderer = getGutterRenderer(e);
|
||||
return renderer != null && renderer.getClickAction() == null && renderer.getPopupMenuActions() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(final MouseEvent e) {
|
||||
if (e.isPopupTrigger()) {
|
||||
|
||||
@@ -304,7 +304,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
|
||||
private CaretImpl myPrimaryCaret;
|
||||
|
||||
private final boolean myDisableRtl = Registry.is("editor.disable.rtl");
|
||||
public final boolean myDisableRtl = Registry.is("editor.disable.rtl");
|
||||
public final boolean myUseNewRendering = Registry.is("editor.new.rendering");
|
||||
final EditorView myView;
|
||||
|
||||
|
||||
@@ -656,9 +656,9 @@ class EditorPainter {
|
||||
g.fillRect(x, y, lineWidth, lineHeight);
|
||||
if (myDocument.getTextLength() > 0 && caret != null && !myView.getLineLayout(caret.getLogicalPosition().line).isLtr()) {
|
||||
g.fillPolygon(new int[]{
|
||||
isRtl ? x + lineWidth - 1 : x,
|
||||
isRtl ? x + lineWidth - 1 - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE,
|
||||
isRtl ? x + lineWidth - 1 : x
|
||||
isRtl ? x + lineWidth : x,
|
||||
isRtl ? x + lineWidth - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE,
|
||||
isRtl ? x + lineWidth : x
|
||||
},
|
||||
new int[]{y, y, y + CARET_DIRECTION_MARK_SIZE}, 3);
|
||||
}
|
||||
|
||||
@@ -268,6 +268,14 @@ public class EditorView implements Disposable {
|
||||
return layout.isRtlLocation(offset - myDocument.getLineStartOffset(line), leanForward);
|
||||
}
|
||||
|
||||
public boolean isDirectionBoundary(int offset) {
|
||||
assertIsDispatchThread();
|
||||
if (myDocument.getTextLength() == 0) return false;
|
||||
int line = myDocument.getLineNumber(offset);
|
||||
LineLayout layout = getLineLayout(line);
|
||||
return layout.isDirectionBoundary(offset - myDocument.getLineStartOffset(line));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
LineLayout getLineLayout(int line) {
|
||||
return myTextLayoutCache.getLineLayout(line);
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.intellij.openapi.editor.impl.view;
|
||||
import com.intellij.openapi.editor.colors.FontPreferences;
|
||||
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.intellij.lang.annotations.JdkConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -81,7 +80,7 @@ class LineLayout {
|
||||
EditorImpl editor = view.getEditor();
|
||||
FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences();
|
||||
char[] chars = CharArrayUtil.fromSequence(editor.getDocument().getImmutableCharSequence(), lineStartOffset, lineEndOffset);
|
||||
List<BidiRun> runs = createRuns(chars);
|
||||
List<BidiRun> runs = createRuns(editor, chars);
|
||||
for (BidiRun run : runs) {
|
||||
IterationState it = new IterationState(editor, lineStartOffset + run.startOffset, lineStartOffset + run.endOffset,
|
||||
false, false, false, false);
|
||||
@@ -101,7 +100,7 @@ class LineLayout {
|
||||
EditorImpl editor = view.getEditor();
|
||||
FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences();
|
||||
char[] chars = CharArrayUtil.fromSequence(text);
|
||||
List<BidiRun> runs = createRuns(chars);
|
||||
List<BidiRun> runs = createRuns(editor, chars);
|
||||
for (BidiRun run : runs) {
|
||||
addFragments(run, chars, run.startOffset, run.endOffset, fontStyle, fontPreferences, fontRenderContext, null);
|
||||
assert !run.fragments.isEmpty();
|
||||
@@ -109,8 +108,8 @@ class LineLayout {
|
||||
return runs;
|
||||
}
|
||||
|
||||
private static List<BidiRun> createRuns(char[] text) {
|
||||
if (Registry.is("editor.disable.rtl")) return Collections.singletonList(new BidiRun((byte)0, 0, text.length));
|
||||
private static List<BidiRun> createRuns(EditorImpl editor, char[] text) {
|
||||
if (editor.myDisableRtl) return Collections.singletonList(new BidiRun((byte)0, 0, text.length));
|
||||
Bidi bidi = new Bidi(text, 0, null, 0, text.length, Bidi.DIRECTION_LEFT_TO_RIGHT);
|
||||
int runCount = bidi.getRunCount();
|
||||
List<BidiRun> runs = new ArrayList<BidiRun>(runCount);
|
||||
@@ -212,6 +211,17 @@ class LineLayout {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isDirectionBoundary(int offset) {
|
||||
boolean prevIsRtl = false;
|
||||
for (BidiRun run : myBidiRunsInLogicalOrder) {
|
||||
boolean curIsRtl = run.isRtl();
|
||||
if (offset == run.startOffset && curIsRtl != prevIsRtl) return true;
|
||||
if (offset < run.endOffset) return false;
|
||||
prevIsRtl = curIsRtl;
|
||||
}
|
||||
return prevIsRtl;
|
||||
}
|
||||
|
||||
private static class BidiRun {
|
||||
private final byte level;
|
||||
private final int startOffset;
|
||||
|
||||
+5
@@ -203,6 +203,11 @@ public class TextComponentCaret extends UserDataHolderBase implements Caret {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAtDirectionBoundary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private SelectionModel getSelectionModel() {
|
||||
return myEditor.getSelectionModel();
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ public class VfsImplUtil {
|
||||
public void run() {
|
||||
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
|
||||
}
|
||||
}, ModalityState.defaultModalityState());
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") T t = (T)handler;
|
||||
|
||||
@@ -120,7 +120,8 @@ public class VfsData {
|
||||
if (o == ourDeadMarker) {
|
||||
throw reportDeadFileAccess(new VirtualFileImpl(id, segment, parent));
|
||||
}
|
||||
assert segment.getNameId(id) > 0;
|
||||
final int nameId = segment.getNameId(id);
|
||||
assert nameId > 0 : "nameId=" + nameId + "; data=" + o + "; parent=" + parent;
|
||||
|
||||
return o instanceof DirectoryData ? new VirtualDirectoryImpl(id, segment, (DirectoryData)o, parent, parent.getFileSystem())
|
||||
: new VirtualFileImpl(id, segment, parent);
|
||||
|
||||
+3
-1
@@ -99,7 +99,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
|
||||
if (result == null) {
|
||||
synchronized (myData) {
|
||||
addToAdoptedChildren(ignoreCase, name);
|
||||
if (!allChildrenLoaded()) {
|
||||
myData.addAdoptedName(name, getFileSystem().isCaseSensitive());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +235,29 @@ public class EditorRtlTest extends AbstractEditorTest {
|
||||
assertLogicalPositionsEqual("Wrong logical position", lF(1), myEditor.getCaretModel().getLogicalPosition());
|
||||
}
|
||||
|
||||
public void testNavigationWithArrowKeys() throws Exception {
|
||||
init("llrrll\nllrrll");
|
||||
assertCaretPosition(vL(0));
|
||||
right();
|
||||
assertCaretPosition(vL(1));
|
||||
right();
|
||||
assertCaretPosition(vL(2));
|
||||
right();
|
||||
assertCaretPosition(vR(2));
|
||||
right();
|
||||
assertCaretPosition(vL(3));
|
||||
right();
|
||||
assertCaretPosition(vL(4));
|
||||
down();
|
||||
assertCaretPosition(v(1, 4, false));
|
||||
left();
|
||||
assertCaretPosition(v(1, 3, true));
|
||||
left();
|
||||
assertCaretPosition(v(1, 2, true));
|
||||
up();
|
||||
assertCaretPosition(vR(2));
|
||||
}
|
||||
|
||||
private void init(String text) throws IOException {
|
||||
initText(text.replace(RTL_CHAR_REPRESENTATION, RTL_CHAR));
|
||||
}
|
||||
@@ -299,6 +322,10 @@ public class EditorRtlTest extends AbstractEditorTest {
|
||||
assertEquals(message, expectedPosition, actualPosition);
|
||||
assertEquals(message + " (direction flag)", expectedPosition.leansRight, actualPosition.leansRight);
|
||||
}
|
||||
|
||||
private static void assertCaretPosition(VisualPosition visualPosition) {
|
||||
assertVisualPositionsEqual("Wrong caret position", visualPosition, myEditor.getCaretModel().getVisualPosition());
|
||||
}
|
||||
|
||||
// logical position leaning backward
|
||||
private static LogicalPosition lB(int column) {
|
||||
|
||||
+16
@@ -574,6 +574,22 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
|
||||
executeAction("EditorSelectLine");
|
||||
}
|
||||
|
||||
protected static void left() {
|
||||
executeAction("EditorLeft");
|
||||
}
|
||||
|
||||
protected static void right() {
|
||||
executeAction("EditorRight");
|
||||
}
|
||||
|
||||
protected static void up() {
|
||||
executeAction("EditorUp");
|
||||
}
|
||||
|
||||
protected static void down() {
|
||||
executeAction("EditorDown");
|
||||
}
|
||||
|
||||
protected static void lineComment() {
|
||||
new CommentByLineCommentAction().actionPerformedImpl(getProject(), getEditor());
|
||||
}
|
||||
|
||||
@@ -2085,6 +2085,15 @@ public class UIUtil {
|
||||
return new Color(actual.getRed(), actual.getGreen(), actual.getBlue(), alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param component to check whether it can be focused or not
|
||||
* @return {@code true} if component is not {@code null} and can be focused
|
||||
* @see Component#isRequestFocusAccepted(boolean, boolean, sun.awt.CausedFocusEvent.Cause)
|
||||
*/
|
||||
public static boolean isFocusable(JComponent component) {
|
||||
return component != null && component.isFocusable() && component.isEnabled() && component.isShowing();
|
||||
}
|
||||
|
||||
public static void requestFocus(@NotNull final JComponent c) {
|
||||
if (c.isShowing()) {
|
||||
c.requestFocus();
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.vcsUtil;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.vcs.actions.VcsContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -35,10 +36,13 @@ public class VcsSelectionUtil {
|
||||
if (selectionFromEditor != null) {
|
||||
return selectionFromEditor;
|
||||
}
|
||||
final VcsSelectionProvider[] providers = Extensions.getExtensions(VcsSelectionProvider.EP_NAME);
|
||||
for(VcsSelectionProvider provider: providers) {
|
||||
final VcsSelection vcsSelection = provider.getSelection(context);
|
||||
if (vcsSelection != null) return vcsSelection;
|
||||
for(VcsSelectionProvider provider: Extensions.getExtensions(VcsSelectionProvider.EP_NAME)) {
|
||||
try {
|
||||
final VcsSelection vcsSelection = provider.getSelection(context);
|
||||
if (vcsSelection != null) return vcsSelection;
|
||||
}
|
||||
catch (IndexNotReadyException ignored) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+5
@@ -27,6 +27,7 @@ import com.intellij.ui.ColoredTextContainer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.frame.*;
|
||||
@@ -124,6 +125,10 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
|
||||
|
||||
@Override
|
||||
public void applyPresentation(@Nullable Icon icon, @NotNull XValuePresentation valuePresentation, boolean hasChildren) {
|
||||
// extra check for obsolete nodes - tree root was changed
|
||||
// too dangerous to put this into isObsolete - it is called from anywhere, not only EDT
|
||||
if (isObsolete() || !TreeUtil.isAncestor(getTree().getRoot(), this)) return;
|
||||
|
||||
setIcon(icon);
|
||||
myValuePresentation = valuePresentation;
|
||||
myRawValue = XValuePresentationUtil.computeValueText(valuePresentation);
|
||||
|
||||
@@ -18,18 +18,21 @@ package org.jetbrains.idea.devkit.testAssistant;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.FilePathSplittingPolicy;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
class GotoTestDataAction extends AnAction {
|
||||
class GotoTestDataAction extends AnAction implements Comparable {
|
||||
private final String myBasePath;
|
||||
private final Project myProject;
|
||||
|
||||
public GotoTestDataAction(String basePath, Project project) {
|
||||
super(basePath);
|
||||
super("Go to " + FilePathSplittingPolicy.SPLIT_BY_SEPARATOR.getPresentableName(new File(basePath), 50), null,
|
||||
FileTypeManager.getInstance().getFileTypeByFileName(basePath).getIcon());
|
||||
myBasePath = basePath;
|
||||
myProject = project;
|
||||
}
|
||||
@@ -41,4 +44,9 @@ class GotoTestDataAction extends AnAction {
|
||||
new OpenFileDescriptor(myProject, baseDir).navigate(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
return o instanceof GotoTestDataAction ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.execution.lineMarker.RunLineMarkerInfo;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -32,13 +33,21 @@ import java.util.List;
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
public class JUnitRunLineMarkerProvider implements LineMarkerProvider {
|
||||
|
||||
private static final Function<PsiElement, String> TOOLTIP_PROVIDER = new Function<PsiElement, String>() {
|
||||
@Override
|
||||
public String fun(PsiElement element) {
|
||||
return "Run Test";
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiClass && JUnitUtil.isTestClass((PsiClass)element, false, true))
|
||||
return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), null);
|
||||
return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), TOOLTIP_PROVIDER);
|
||||
if (element instanceof PsiMethod && JUnitUtil.isTestMethod(new PsiLocation<PsiMethod>((PsiMethod)element)))
|
||||
return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), null);
|
||||
return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), TOOLTIP_PROVIDER);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@@ -127,11 +127,8 @@ public class IDEATestNGRemoteListener implements ISuiteListener, IResultListener
|
||||
for (int i = idx; i < parentsHierarchy.size(); i++) {
|
||||
String fqName = parentsHierarchy.get(parentsHierarchy.size() - 1 - i);
|
||||
String currentClassName = getShortName(fqName);
|
||||
myPrintStream.print("\n##teamcity[testSuiteStarted name =\'" + escapeName(currentClassName));
|
||||
if (provideLocation) {
|
||||
myPrintStream.print("\' locationHint = \'java:suite://" + escapeName(fqName));
|
||||
}
|
||||
myPrintStream.println("\']");
|
||||
myPrintStream.println("\n##teamcity[testSuiteStarted name =\'" + escapeName(currentClassName) +
|
||||
(provideLocation ? "\' locationHint = \'java:suite://" + escapeName(fqName) : "") + "\']");
|
||||
myCurrentSuites.add(currentClassName);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Add quotes for attribute value on typing '='"/>
|
||||
<text value="Add quotes for attribute value on typing '=' and attribute completion"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="76e81" class="com.intellij.ui.components.JBCheckBox" binding="myAutoCloseTagCheckBox">
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.application.options.editor.WebEditorOptions;
|
||||
import com.intellij.codeInsight.AutoPopupController;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -65,14 +66,18 @@ public class XmlAttributeInsertHandler implements InsertHandler<LookupElement> {
|
||||
final PsiFile file = context.getFile();
|
||||
|
||||
final CharSequence chars = document.getCharsSequence();
|
||||
if (!CharArrayUtil.regionMatches(chars, caretOffset, "=\"") && !CharArrayUtil.regionMatches(chars, caretOffset, "='")) {
|
||||
final boolean insertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue();
|
||||
final boolean hasQuotes = CharArrayUtil.regionMatches(chars, caretOffset, "=\"");
|
||||
if (!hasQuotes && !CharArrayUtil.regionMatches(chars, caretOffset, "='")) {
|
||||
PsiElement fileContext = file.getContext();
|
||||
String toInsert= "=\"\"";
|
||||
|
||||
if(fileContext != null) {
|
||||
if (fileContext.getText().startsWith("\"")) toInsert = "=''";
|
||||
}
|
||||
|
||||
|
||||
if (!insertQuotes) toInsert = "=";
|
||||
|
||||
if (caretOffset >= document.getTextLength() || "/> \n\t\r".indexOf(document.getCharsSequence().charAt(caretOffset)) < 0) {
|
||||
document.insertString(caretOffset, toInsert + " ");
|
||||
}
|
||||
@@ -85,7 +90,7 @@ public class XmlAttributeInsertHandler implements InsertHandler<LookupElement> {
|
||||
}
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(caretOffset + 2);
|
||||
editor.getCaretModel().moveToOffset(caretOffset + (insertQuotes || hasQuotes ? 2 : 1));
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
editor.getSelectionModel().removeSelection();
|
||||
AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor);
|
||||
|
||||
@@ -50,7 +50,13 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate {
|
||||
public Result charTyped(char c, Project project, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (needToInsertQuotes) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
editor.getDocument().insertString(offset, "\"\"");
|
||||
PsiElement fileContext = file.getContext();
|
||||
String toInsert= "\"\"";
|
||||
|
||||
if(fileContext != null) {
|
||||
if (fileContext.getText().startsWith("\"")) toInsert = "''";
|
||||
}
|
||||
editor.getDocument().insertString(offset, toInsert);
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
AutoPopupController.getInstance(project).scheduleAutoPopup(editor);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.application.options.editor.WebEditorOptions;
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
@@ -348,6 +349,18 @@ public class XmlCompletionTest extends LightCodeInsightFixtureTestCase {
|
||||
checkResultByFile(getTestName(true) + ".xml");
|
||||
}
|
||||
|
||||
public void testAttributeNoQuotes() throws Throwable {
|
||||
boolean oldInsertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue();
|
||||
WebEditorOptions.getInstance().setInsertQuotesForAttributeValue(false);
|
||||
try {
|
||||
configureByFile(getTestName(false) + ".xml");
|
||||
selectItem(myFixture.getLookupElements()[0], '\t');
|
||||
checkResultByFile(getTestName(false) + "_after.xml");
|
||||
} finally {
|
||||
WebEditorOptions.getInstance().setInsertQuotesForAttributeValue(oldInsertQuotes);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBeforeAttributeNameWithPrefix() throws Exception {
|
||||
configureByFile(getTestName(true) + ".xml");
|
||||
selectItem(myFixture.getLookupElements()[0], '\t');
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<a>
|
||||
<include file="" value=""/>
|
||||
<include <caret>/>
|
||||
|
||||
</a>
|
||||
@@ -0,0 +1,5 @@
|
||||
<a>
|
||||
<include file="" value=""/>
|
||||
<include file=/>
|
||||
|
||||
</a>
|
||||
+25
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.html.dtd;
|
||||
|
||||
import com.intellij.html.impl.RelaxedHtmlFromSchemaElementDescriptor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.xml.XmlAttributeDescriptor;
|
||||
import com.intellij.xml.XmlElementDescriptor;
|
||||
@@ -70,6 +71,30 @@ public class HtmlElementDescriptorImpl extends BaseXmlElementDescriptorImpl {
|
||||
if (!myCaseSensitive) name = name.toLowerCase();
|
||||
|
||||
XmlElementDescriptor xmlElementDescriptor = getElementDescriptor(name, element);
|
||||
if (xmlElementDescriptor == null && "html".equals(getName())) {
|
||||
XmlTag head = null;
|
||||
XmlTag body = null;
|
||||
|
||||
for (XmlTag child : PsiTreeUtil.getChildrenOfTypeAsList(contextTag, XmlTag.class)) {
|
||||
if ("head".equals(child.getName())) head = child;
|
||||
if ("body".equals(child.getName())) body = child;
|
||||
}
|
||||
if (head == null) {
|
||||
if (body == null || element.getTextOffset() < body.getTextOffset()) {
|
||||
XmlElementDescriptor headDescriptor = getElementDescriptor("head", contextTag);
|
||||
if (headDescriptor != null) {
|
||||
xmlElementDescriptor = headDescriptor.getElementDescriptor(element, contextTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xmlElementDescriptor == null && body == null) {
|
||||
XmlElementDescriptor bodyDescriptor = getElementDescriptor("body", contextTag);
|
||||
if (bodyDescriptor != null) {
|
||||
xmlElementDescriptor = bodyDescriptor.getElementDescriptor(element, contextTag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (xmlElementDescriptor == null && myRelaxed) {
|
||||
xmlElementDescriptor = RelaxedHtmlFromSchemaElementDescriptor.getRelaxedDescriptor(this, element);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user