Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yann Cébron
2015-05-28 22:46:04 +02:00
77 changed files with 801 additions and 367 deletions
+2 -1
View File
@@ -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 {
@@ -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;
}
}
@@ -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);
}
}
}
}
}
}
}
}
@@ -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();
@@ -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());
}
@@ -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);
}
});
}
});
}
@@ -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);
@@ -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();
}
@@ -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();
}
@@ -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,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){}
}
@@ -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>;
}
}
@@ -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>;
}
}
@@ -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,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){}
}
@@ -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>;
}
}
@@ -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>;
}
}
@@ -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];
@@ -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);
@@ -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()
@@ -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
@@ -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;
}
}
@@ -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
@@ -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" : "");
@@ -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);
}
@@ -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;
}
}
@@ -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) {
@@ -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;
}
@@ -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 {
@@ -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> {
@@ -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);
}
@@ -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;
@@ -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);
@@ -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) {
@@ -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;
}
@@ -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>
@@ -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);
}