diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/view/InternalCompilerRefServiceView.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/view/InternalCompilerRefServiceView.java index 3de46ac2d961..2f19aa845425 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/view/InternalCompilerRefServiceView.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/view/InternalCompilerRefServiceView.java @@ -31,6 +31,7 @@ import com.intellij.psi.presentation.java.ClassPresentationUtil; import com.intellij.psi.presentation.java.SymbolPresentationUtil; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.content.impl.ContentImpl; import com.intellij.ui.treeStructure.Tree; import org.jetbrains.annotations.NotNull; @@ -79,7 +80,7 @@ public class InternalCompilerRefServiceView extends JPanel implements DataProvid } }); setLayout(new BorderLayout()); - add(myTree); + add(new JBScrollPane(myTree)); } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 021668ee1225..6579e63f1521 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -445,55 +445,6 @@ public class AnnotationsHighlightUtil { return ref; } - static HighlightInfo checkForeignInnerClassesUsed(final PsiAnnotation annotation) { - final HighlightInfo[] infos = new HighlightInfo[1]; - final PsiAnnotationOwner owner = annotation.getOwner(); - if (owner instanceof PsiModifierList) { - final PsiElement parent = ((PsiModifierList)owner).getParent(); - if (parent instanceof PsiClass) { - annotation.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitElement(PsiElement element) { - if (infos[0] != null) return; - super.visitElement(element); - } - - @Override - public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { - super.visitClassObjectAccessExpression(expression); - final PsiTypeElement operand = expression.getOperand(); - final PsiClass classType = PsiUtil.resolveClassInType(operand.getType()); - if (classType != null) { - checkAccessibility(operand.getInnermostComponentReferenceElement(), classType, HighlightUtil.formatClass(classType)); - } - } - - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - final PsiElement resolve = expression.resolve(); - if (resolve instanceof PsiField) { - checkAccessibility(expression, (PsiMember)resolve, HighlightUtil.formatField((PsiField)resolve)); - } - } - - private void checkAccessibility(PsiJavaCodeReferenceElement expression, PsiMember resolve, String memberString) { - if (resolve.hasModifierProperty(PsiModifier.PRIVATE) && - PsiTreeUtil.isAncestor(parent, resolve, true)) { - String description = JavaErrorMessages.message("private.symbol", - memberString, - HighlightUtil.formatClass((PsiClass)parent)); - infos[0] = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description).create(); - HighlightUtil.registerAccessQuickFixAction(resolve, expression, infos[0], null); - } - } - }); - } - } - return infos[0]; - } - @Nullable static HighlightInfo checkAnnotationType(PsiAnnotation annotation) { PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index e50bc4c3b5a7..8ad8847cf391 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -635,7 +635,7 @@ public class GenericsHighlightUtil { } if (superMethod.hasModifierProperty(PsiModifier.STATIC) && superContainingClass != null && - superContainingClass.isInterface() && PsiUtil.isLanguageLevel8OrHigher(superContainingClass)) { + superContainingClass.isInterface() && !checkEqualsSuper && PsiUtil.isLanguageLevel8OrHigher(superContainingClass)) { return null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 294505c27770..72dfedbbf09e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -241,7 +241,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation, myLanguageLevel)); - if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation, myLanguageLevel)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation)); if (CommonClassNames.JAVA_LANG_OVERRIDE.equals(annotation.getQualifiedName())) { diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamer.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamer.java index cd16aad88e91..8a3607275be0 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamer.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -22,17 +22,15 @@ package com.intellij.refactoring.rename.naming; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; +import org.jetbrains.annotations.NotNull; public class AutomaticOverloadsRenamer extends AutomaticRenamer { - public AutomaticOverloadsRenamer(PsiMethod method, String newName) { - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null) { - final PsiMethod[] overloads = containingClass.findMethodsByName(method.getName(), false); - for (PsiMethod overload : overloads) { - if (overload != method && overload.findDeepestSuperMethods().length == 0) { - myElements.add(overload); - suggestAllNames(overload.getName(), newName); - } + + public AutomaticOverloadsRenamer(@NotNull PsiMethod method, String newName) { + for (PsiMethod overload : getOverloads(method)) { + if (overload != method && overload.findDeepestSuperMethods().length == 0) { + myElements.add(overload); + suggestAllNames(overload.getName(), newName); } } } @@ -54,4 +52,11 @@ public class AutomaticOverloadsRenamer extends AutomaticRenamer { public boolean isSelectedByDefault() { return true; } + + @NotNull + protected PsiMethod[] getOverloads(@NotNull PsiMethod method) { + PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) return PsiMethod.EMPTY_ARRAY; + return containingClass.findMethodsByName(method.getName(), false); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamerFactory.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamerFactory.java index fab97ba6c15f..9283fb31d3cb 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamerFactory.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticOverloadsRenamerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,16 +20,21 @@ */ package com.intellij.refactoring.rename.naming; -import com.intellij.psi.*; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; import com.intellij.usageView.UsageInfo; +import org.jetbrains.annotations.NotNull; import java.util.Collection; -public class AutomaticOverloadsRenamerFactory implements AutomaticRenamerFactory{ - public boolean isApplicable(PsiElement element) { - if (element instanceof PsiMethod && !((PsiMethod)element).isConstructor()) { +public class AutomaticOverloadsRenamerFactory implements AutomaticRenamerFactory { + + public boolean isApplicable(@NotNull PsiElement element) { + if (element.getLanguage() == JavaLanguage.INSTANCE && element instanceof PsiMethod && !((PsiMethod)element).isConstructor()) { final PsiClass containingClass = ((PsiMethod)element).getContainingClass(); return containingClass != null && containingClass.findMethodsByName(((PsiMethod)element).getName(), false).length > 1; } @@ -48,6 +53,7 @@ public class AutomaticOverloadsRenamerFactory implements AutomaticRenamerFactory JavaRefactoringSettings.getInstance().setRenameOverloads(enabled); } + @NotNull public AutomaticRenamer createRenamer(PsiElement element, String newName, Collection usages) { return new AutomaticOverloadsRenamer((PsiMethod)element, newName); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java index e97b5d6312a4..f9c4db15693e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java @@ -122,9 +122,15 @@ public class JavaResolveUtil { if (memberClass == null) { return false; } - // if resolving supertype reference, skip its containing class with getContextClass - PsiClass contextClass = member instanceof PsiClass ? getContextClass(place) - : PsiTreeUtil.getContextOfType(place, PsiClass.class, false); + PsiClass contextClass; + if (member instanceof PsiClass) { + // if resolving supertype reference, skip its containing class with getContextClass + contextClass = getContextClass(place); + } + else { + contextClass = PsiTreeUtil.getContextOfType(place, PsiClass.class, false); + if (isInClassAnnotationParameterList(place, contextClass)) return false; + } while (contextClass != null) { if (InheritanceUtil.isInheritorOrSelf(contextClass, memberClass, true)) { if (member instanceof PsiClass || @@ -156,7 +162,8 @@ public class JavaResolveUtil { if (fileResolveScope == null) { PsiClass placeTopLevelClass = getTopLevelClass(place, null); PsiClass memberTopLevelClass = getTopLevelClass(memberClass, null); - return manager.areElementsEquivalent(placeTopLevelClass, memberTopLevelClass); + return manager.areElementsEquivalent(placeTopLevelClass, memberTopLevelClass) && + !isInClassAnnotationParameterList(place, PsiTreeUtil.getContextOfType(place, PsiClass.class, false)); } else { return fileResolveScope instanceof PsiClass && @@ -186,6 +193,16 @@ public class JavaResolveUtil { return true; } + private static boolean isInClassAnnotationParameterList(@NotNull PsiElement place, @Nullable PsiClass contextClass) { + if (contextClass != null) { + PsiAnnotation annotation = PsiTreeUtil.getContextOfType(place, PsiAnnotation.class, true); + if (annotation != null && contextClass.getModifierList() == annotation.getOwner()) { + return true; + } + } + return false; + } + private static boolean ignoreReferencedElementAccessibility(PsiFile placeFile) { return placeFile instanceof FileResolveScopeProvider && ((FileResolveScopeProvider) placeFile).ignoreReferencedElementAccessibility() && diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/ProtectedFieldUsedInAnnotationParameterOfInheritor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/ProtectedFieldUsedInAnnotationParameterOfInheritor.java new file mode 100644 index 000000000000..f39e09c76e0f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/ProtectedFieldUsedInAnnotationParameterOfInheritor.java @@ -0,0 +1,4 @@ +import a.A; + +@SuppressWarnings(A.A_FOO) +class B extends A {} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/ClassObjectAccessibility.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/ClassObjectAccessibility.java index 929b107d53f6..5dda31b8b426 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/ClassObjectAccessibility.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/ClassObjectAccessibility.java @@ -1,4 +1,4 @@ -@SomeAnnotation(Foo.Bar.class) +@SomeAnnotation(Foo.Bar.class) public class Foo{ private static class Bar { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java index e02db8fb902f..974d6ee9c6e6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java @@ -1,4 +1,4 @@ -@SuppressWarnings(ThisClass.FOO) +@SuppressWarnings(ThisClass.FOO) public class ThisClass { private static final String FOO = "foo"; } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/privateInaccessibleConstant.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/privateInaccessibleConstant.java index 435810d00b44..ef49b407ae26 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/privateInaccessibleConstant.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/privateInaccessibleConstant.java @@ -1,4 +1,4 @@ -@FooAnnotation(Foo.BAR) +@FooAnnotation(Foo.BAR) class Foo { private static final String BAR = "bar"; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasureForStaticMethodsInInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasureForStaticMethodsInInterfaces.java new file mode 100644 index 000000000000..db4acfc6f0c0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasureForStaticMethodsInInterfaces.java @@ -0,0 +1,5 @@ + +interface Test { + static void foo(A a) {} + static void foo(B b) {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java index 5b3ecddbe758..07d0cd173feb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java @@ -99,6 +99,12 @@ public class LightAdvHighlightingFixtureTest extends LightCodeInsightFixtureTest myFixture.checkHighlighting(); } + public void testProtectedFieldUsedInAnnotationParameterOfInheritor() throws Exception { + myFixture.addClass("package a; public class A {protected final static String A_FOO = \"A\";}"); + myFixture.configureByFile(getTestName(false) + ".java"); + myFixture.checkHighlighting(); + } + @Override protected String getBasePath() { return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/advFixture"; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index c74c36172b7a..904a6be6f9f4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -1012,4 +1012,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { public void testBoundsPromotionForDerivedType() throws Exception { doTest(); } + + public void testSameErasureForStaticMethodsInInterfaces() throws Exception { + doTest(); + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/intention/FlipCommaIntentionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/intention/FlipCommaIntentionTest.java index b079d8c7c903..194f8928837e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/intention/FlipCommaIntentionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/intention/FlipCommaIntentionTest.java @@ -31,4 +31,11 @@ public class FlipCommaIntentionTest extends IPPTestCase { " int b, a;\n" + "}"); } + + public void testUnavailableForDangling() throws Exception { + myFixture.configureByText("a.java", "class C {\n" + + " int a[] = new int[]{1,2,};" + + "}"); + assertEmpty(myFixture.filterAvailableIntentions("Flip")); + } } diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java index 280359731f1e..666df9849f63 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavaCompilerToolExtension.java @@ -16,24 +16,18 @@ package org.jetbrains.jps.javac; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.ExtensionsSupport; import org.jetbrains.jps.builders.java.JavaCompilingTool; -import javax.tools.JavaCompiler; +import javax.tools.*; import java.util.Collection; -import java.util.Collections; -import java.util.List; /** * @author Eugene Zhuravlev * Date: 09-Nov-16 */ public abstract class JavaCompilerToolExtension { - @NotNull - public abstract String getId(); - - /** + /** * This method is called before compiler task execution. * The extension can install all necessary compiler listeners here. * @@ -45,31 +39,9 @@ public abstract class JavaCompilerToolExtension { public void beforeCompileTaskExecution(@NotNull JavaCompilingTool compilingTool, @NotNull JavaCompiler.CompilationTask task, @NotNull Collection options, @NotNull DiagnosticOutputConsumer diagnosticConsumer) { } - /** - * Custom data passed through DiagnosticOutputConsumer object with pluginId == thisExtensionId will be passed to this method - * @param dataName - * @param content - */ - public void processData(String dataName, byte[] content) { - } - - public List getExternalBuildProcessOptions(@NotNull JavaCompilingTool compilingTool) { - return Collections.emptyList(); - } - private static final ExtensionsSupport ourExtSupport = new ExtensionsSupport(JavaCompilerToolExtension.class); @NotNull public static Collection getExtensions() { return ourExtSupport.getExtensions(); } - - @Nullable - public static JavaCompilerToolExtension getExtension(@NotNull String id) { - for (JavaCompilerToolExtension extension : getExtensions()) { - if (id.equals(extension.getId())) { - return extension; - } - } - return null; - } } diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java index 0de00ccf2c19..03f9cf336bdf 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java @@ -171,7 +171,7 @@ public class JavacMain { extension.beforeCompileTaskExecution(compilingTool, task, _options, diagnosticConsumer); } catch (Throwable e) { - fileManager.getContext().reportMessage(Diagnostic.Kind.MANDATORY_WARNING, extension.getId() + ": " + e.getMessage()); + fileManager.getContext().reportMessage(Diagnostic.Kind.MANDATORY_WARNING, extension.getClass() + " : " + e.getMessage()); e.printStackTrace(System.err); } } diff --git a/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.java.CustomOutputDataListener b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.java.CustomOutputDataListener new file mode 100644 index 000000000000..b32c2ace989f --- /dev/null +++ b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.java.CustomOutputDataListener @@ -0,0 +1 @@ +org.jetbrains.jps.javac.ast.JavacAstCustomDataListener \ No newline at end of file diff --git a/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.java.ExternalJavacOptionsProvider b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.java.ExternalJavacOptionsProvider new file mode 100644 index 000000000000..f91f84c5da68 --- /dev/null +++ b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.incremental.java.ExternalJavacOptionsProvider @@ -0,0 +1 @@ +org.jetbrains.jps.javac.ast.ReferenceCollectorExternalJavacOptionsProvider \ No newline at end of file diff --git a/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.javac.JavaCompilerToolExtension b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.javac.JavaCompilerToolExtension index aba1ef7e1011..dc163c7ab132 100644 --- a/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.javac.JavaCompilerToolExtension +++ b/jps/jps-builders/src/META-INF/services/org.jetbrains.jps.javac.JavaCompilerToolExtension @@ -1,16 +1,2 @@ -# -# Copyright 2000-2016 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. -# -org.jetbrains.jps.javac.ast.RefCollectorCompilerToolExtension \ No newline at end of file +org.jetbrains.jps.javac.ast.ExternalRefCollectorCompilerToolExtension +org.jetbrains.jps.javac.ast.InProcessRefCollectorCompilerToolExtension \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/CustomOutputDataListener.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/CustomOutputDataListener.java new file mode 100644 index 000000000000..a1d73deaf7a1 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/CustomOutputDataListener.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.incremental.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * An extension for processing custom messages that had been sent by {@link org.jetbrains.jps.javac.DiagnosticOutputConsumer#customOutputData} + */ +public interface CustomOutputDataListener { + + @NotNull + String getId(); + + /** + * Custom data passed through DiagnosticOutputConsumer object with pluginId == thisExtension.getId() will be passed to this method + * @param dataName + * @param content + */ + void processData(@Nullable String dataName, @NotNull byte[] content); +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacOptionsProvider.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacOptionsProvider.java new file mode 100644 index 000000000000..c69ce8d20cf1 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacOptionsProvider.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.incremental.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.java.JavaCompilingTool; + +import java.util.Collection; + +/** + * An extension for setting up additional options for external java compiler. + * See {@link JavaBuilder#loadCommonJavacOptions(org.jetbrains.jps.incremental.CompileContext, JavaCompilingTool)} + */ +public interface ExternalJavacOptionsProvider { + @NotNull + Collection getOptions(@NotNull JavaCompilingTool tool); +} + diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index ad98b48b8a7f..5c1eb83170ee 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -1047,8 +1047,8 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - for (JavaCompilerToolExtension extension : JavaCompilerToolExtension.getExtensions()) { - vmOptions.addAll(extension.getExternalBuildProcessOptions(compilingTool)); + for (ExternalJavacOptionsProvider extension : JpsServiceManager.getInstance().getExtensions(ExternalJavacOptionsProvider.class)) { + vmOptions.addAll(extension.getOptions(compilingTool)); } if (JavaCompilers.ECLIPSE_ID.equals(compilingTool.getId())) { @@ -1119,9 +1119,11 @@ public class JavaBuilder extends ModuleLevelBuilder { @Override public void customOutputData(String pluginId, String dataName, byte[] data) { - final JavaCompilerToolExtension handler = JavaCompilerToolExtension.getExtension(pluginId); - if (handler != null) { - handler.processData(dataName, data); + for (CustomOutputDataListener listener : JpsServiceManager.getInstance().getExtensions(CustomOutputDataListener.class)) { + if (pluginId.equals(listener.getId())) { + listener.processData(dataName, data); + return; + } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/AbstractRefCollectorCompilerToolExtension.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/AbstractRefCollectorCompilerToolExtension.java new file mode 100644 index 000000000000..68e2134c0301 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/AbstractRefCollectorCompilerToolExtension.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.javac.ast; + +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.java.JavaCompilingTool; +import org.jetbrains.jps.javac.DiagnosticOutputConsumer; +import org.jetbrains.jps.javac.JavaCompilerToolExtension; +import org.jetbrains.jps.javac.ast.api.JavacFileData; + +import javax.tools.*; +import java.util.Collection; + +public abstract class AbstractRefCollectorCompilerToolExtension extends JavaCompilerToolExtension { + @Override + public final void beforeCompileTaskExecution(@NotNull JavaCompilingTool compilingTool, + @NotNull JavaCompiler.CompilationTask task, + @NotNull Collection options, + @NotNull DiagnosticOutputConsumer diagnosticConsumer) { + if (isEnabled()) { + JavacReferenceCollector.installOn(task, divideImportsRefs(), getFileDataConsumer(diagnosticConsumer)); + } + } + + protected abstract boolean isEnabled(); + + protected abstract boolean divideImportsRefs(); + + @NotNull + protected abstract Consumer getFileDataConsumer(@NotNull DiagnosticOutputConsumer diagnosticConsumer); +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/ExternalRefCollectorCompilerToolExtension.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/ExternalRefCollectorCompilerToolExtension.java new file mode 100644 index 000000000000..29d87cd4885a --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/ExternalRefCollectorCompilerToolExtension.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.javac.ast; + +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.javac.DiagnosticOutputConsumer; +import org.jetbrains.jps.javac.ast.api.JavacFileData; + +public class ExternalRefCollectorCompilerToolExtension extends AbstractRefCollectorCompilerToolExtension { + public static final String ID = "external.ast.reference.collector"; + + public static final String ENABLED_PARAM = "external.java.process.ref.collector.enabled"; + public static final String DIVIDE_IMPORTS_PARAM = "external.java.process.divide.imports"; + + @Override + protected boolean isEnabled() { + return "true".equals(System.getProperty(ENABLED_PARAM)); + } + + @Override + protected boolean divideImportsRefs() { + return "true".equals(System.getProperty(DIVIDE_IMPORTS_PARAM)); + } + + @NotNull + @Override + protected Consumer getFileDataConsumer(@NotNull final DiagnosticOutputConsumer diagnosticConsumer) { + return new Consumer() { + @Override + public void consume(JavacFileData data) { + diagnosticConsumer.customOutputData(ID, "javac-refs", data.asBytes()); + } + }; + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/InProcessRefCollectorCompilerToolExtension.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/InProcessRefCollectorCompilerToolExtension.java new file mode 100644 index 000000000000..8350ed124b1d --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/InProcessRefCollectorCompilerToolExtension.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.javac.ast; + +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.javac.DiagnosticOutputConsumer; +import org.jetbrains.jps.javac.ast.api.JavacFileData; +import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; +import org.jetbrains.jps.service.JpsServiceManager; + +import java.util.ArrayList; +import java.util.List; + +public class InProcessRefCollectorCompilerToolExtension extends AbstractRefCollectorCompilerToolExtension { + @Override + protected boolean isEnabled() { + try { + @SuppressWarnings("unused") + final Class jpsServiceManager = JpsServiceManager.class; + } + catch (NoClassDefFoundError ignored) { + return false; + } + + for (JavacFileReferencesRegistrar registrar : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { + if (registrar.isEnabled()) { + return true; + } + } + return false; + } + + @Override + protected boolean divideImportsRefs() { + return false; + } + + @NotNull + @Override + protected Consumer getFileDataConsumer(@NotNull DiagnosticOutputConsumer diagnosticConsumer) { + return createFileDataConsumer(); + } + + @NotNull + static Consumer createFileDataConsumer() { + return new JavacFileDataConsumer(); + } + + private static class JavacFileDataConsumer implements Consumer { + final JavacFileReferencesRegistrar[] myRegistrars; + + private JavacFileDataConsumer() { + List registrars = new ArrayList(); + for (JavacFileReferencesRegistrar registrar : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { + if (registrar.isEnabled()) { + registrar.initialize(); + registrars.add(registrar); + } + } + myRegistrars = registrars.toArray(new JavacFileReferencesRegistrar[registrars.size()]); + } + + @Override + public void consume(JavacFileData data) { + for (JavacFileReferencesRegistrar registrar : myRegistrars) { + if (registrar.isEnabled()) { + registrar.registerFile(data.getFilePath(), registrar.onlyImports() ? data.getImportRefs() : data.getRefs(), data.getDefs()); + } + } + } + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacAstCustomDataListener.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacAstCustomDataListener.java new file mode 100644 index 000000000000..6b914c423589 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacAstCustomDataListener.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.javac.ast; + +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.incremental.java.CustomOutputDataListener; +import org.jetbrains.jps.javac.ast.api.JavacFileData; + +public class JavacAstCustomDataListener implements CustomOutputDataListener { + private final Consumer myConsumer; + + public JavacAstCustomDataListener() { + myConsumer = InProcessRefCollectorCompilerToolExtension.createFileDataConsumer(); + } + + @NotNull + @Override + public String getId() { + return ExternalRefCollectorCompilerToolExtension.ID; + } + + @Override + public void processData(@Nullable String dataName, @NotNull byte[] content) { + myConsumer.consume(JavacFileData.fromBytes(content)); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java index c4e98dbe91c1..23f59d9f2922 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/JavacReferenceCollectorListener.java @@ -15,20 +15,17 @@ */ package org.jetbrains.jps.javac.ast; -import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.util.Consumer; -import com.intellij.util.ReflectionUtil; import com.sun.source.tree.*; import com.sun.source.util.*; import com.sun.tools.javac.util.ClientCodeException; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; -import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.javac.ast.api.JavacDef; import org.jetbrains.jps.javac.ast.api.JavacFileData; -import org.jetbrains.jps.javac.ast.api.JavacRef; import org.jetbrains.jps.javac.ast.api.JavacNameTable; +import org.jetbrains.jps.javac.ast.api.JavacRef; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -51,21 +48,19 @@ final class JavacReferenceCollectorListener implements TaskListener { private final Trees myTreeUtility; private final JavacNameTable myNameTableCache; - private NotNullLazyValue myAsterisk = new NotNullLazyValue() { - @NotNull - @Override - protected Name compute() { - return myElementUtility.getName("*"); - } - }; - private final Map myIncompletelyProcessedFiles = new THashMap(10); static void installOn(JavaCompiler.CompilationTask task, boolean divideImportRefs, Consumer dataConsumer) { JavacTask javacTask = (JavacTask)task; - Method addTaskMethod = ReflectionUtil.getMethod(JavacTask.class, "addTaskListener", TaskListener.class); // jdk >= 8 + Method addTaskMethod; // jdk >= 8 + try { + addTaskMethod = JavacTask.class.getMethod("addTaskListener", TaskListener.class); + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } final JavacReferenceCollectorListener taskListener = new JavacReferenceCollectorListener(divideImportRefs, dataConsumer, javacTask.getElements(), @@ -73,6 +68,7 @@ final class JavacReferenceCollectorListener implements TaskListener { Trees.instance(javacTask)); if (addTaskMethod != null) { try { + addTaskMethod.setAccessible(true); addTaskMethod.invoke(task, taskListener); } catch (IllegalAccessException e) { @@ -178,7 +174,7 @@ final class JavacReferenceCollectorListener implements TaskListener { final MemberSelectTree classImport = (MemberSelectTree)qExpr; final Element ownerElement = incompletelyProcessedFile.getReferencedElement(classImport); final Name name = id.getIdentifier(); - if (name != myAsterisk.getValue()) { + if (name != myNameTableCache.getAsterisk()) { // member import for (Element memberElement : myElementUtility.getAllMembers((TypeElement)ownerElement)) { if (memberElement.getSimpleName() == name) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java deleted file mode 100644 index 3daddeec537c..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/RefCollectorCompilerToolExtension.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2000-2016 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 org.jetbrains.jps.javac.ast; - -import com.intellij.openapi.util.AtomicClearableLazyValue; -import com.intellij.util.Consumer; -import com.intellij.util.SystemProperties; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.TestOnly; -import org.jetbrains.jps.builders.java.JavaCompilingTool; -import org.jetbrains.jps.javac.DiagnosticOutputConsumer; -import org.jetbrains.jps.javac.JavaCompilerToolExtension; -import org.jetbrains.jps.javac.ast.api.JavacFileData; -import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; -import org.jetbrains.jps.model.java.compiler.JavaCompilers; -import org.jetbrains.jps.service.JpsServiceManager; - -import javax.tools.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * @author Eugene Zhuravlev - * Date: 09-Nov-16 - */ -public class RefCollectorCompilerToolExtension extends JavaCompilerToolExtension{ - public static final String ID = "ASTReferenceCollector"; - - private static final String ENABLED_PARAM = "jps.ref.collector.enabled"; - private static final String DIVIDE_IMPORTS_PARAM = "jps.divide.imports"; - - private final AtomicClearableLazyValue> myRegistrars = new AtomicClearableLazyValue>() { - @NotNull - @Override - protected List compute() { - List result = new ArrayList(); - for (JavacFileReferencesRegistrar registrar : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { - if (registrar.isEnabled()) { - registrar.initialize(); - result.add(registrar); - } - } - return result; - } - }; - - @NotNull - @Override - public String getId() { - return ID; - } - - @Override - public void beforeCompileTaskExecution(@NotNull JavaCompilingTool compilingTool, - @NotNull JavaCompiler.CompilationTask task, - @NotNull Collection options, - @NotNull final DiagnosticOutputConsumer diagnosticConsumer) { - if (isJavac(compilingTool)) { - final String isEnabledProperty = System.getProperty(ENABLED_PARAM); - - Consumer fileDataConsumer; - boolean divideImportsRefs; - if (isEnabledProperty == null) { - //in-process - final RefCollectorOptions refCollectorOptions = new RefCollectorOptions(); - fileDataConsumer = refCollectorOptions.enabled ? new Consumer() { - @Override - public void consume(JavacFileData data) { - submitFileData(data); - } - } : null; - divideImportsRefs = refCollectorOptions.divideImportRefs; - } else if (isEnabledProperty.equals("true")) { - //external - fileDataConsumer = new Consumer() { - @Override - public void consume(JavacFileData data) { - diagnosticConsumer.customOutputData(ID, "javac-refs", data.asBytes()); - } - }; - divideImportsRefs = SystemProperties.getBooleanProperty(DIVIDE_IMPORTS_PARAM, false); - } else { - return; - } - - if (fileDataConsumer != null) { - JavacReferenceCollector.installOn(task, divideImportsRefs, fileDataConsumer); - } - } - } - - @Override - public List getExternalBuildProcessOptions(@NotNull JavaCompilingTool compilingTool) { - List options = new ArrayList(2); - if (isJavac(compilingTool)) { - final RefCollectorOptions refCollectorOptions = new RefCollectorOptions(); - options.add("-D" + ENABLED_PARAM + "=" + refCollectorOptions.enabled); - if (refCollectorOptions.enabled && refCollectorOptions.divideImportRefs) { - options.add("-D" + DIVIDE_IMPORTS_PARAM + "=true"); - } - } else { - options.add("-D" + ENABLED_PARAM + "=false"); - } - return options; - } - - @Override - public void processData(String dataName, byte[] content) { - submitFileData(JavacFileData.fromBytes(content)); - } - - private void submitFileData(@NotNull JavacFileData data) { - for (JavacFileReferencesRegistrar registrar : myRegistrars.getValue()) { - registrar.registerFile(data.getFilePath(), registrar.onlyImports() ? data.getImportRefs() : data.getRefs(), data.getDefs()); - } - } - - private static boolean isJavac(@NotNull JavaCompilingTool compilingTool) { - return JavaCompilers.JAVAC_ID.equals(compilingTool.getId()); - } - - private static class RefCollectorOptions { - private final boolean enabled; - private final boolean divideImportRefs; - - private RefCollectorOptions() { - boolean enabled = false; - boolean divideImportRefs = false; - for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { - if (listener.isEnabled()) { - enabled = true; - if (listener.onlyImports()) { - divideImportRefs = true; - } - } - } - - this.enabled = enabled; - this.divideImportRefs = divideImportRefs; - } - } - - @TestOnly - public void clearRegistrars() { - myRegistrars.drop(); - } -} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/ReferenceCollectorExternalJavacOptionsProvider.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/ReferenceCollectorExternalJavacOptionsProvider.java new file mode 100644 index 000000000000..b86bfdbf24d5 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/ReferenceCollectorExternalJavacOptionsProvider.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.jps.javac.ast; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.java.JavaCompilingTool; +import org.jetbrains.jps.incremental.java.ExternalJavacOptionsProvider; +import org.jetbrains.jps.javac.ast.api.JavacFileReferencesRegistrar; +import org.jetbrains.jps.model.java.compiler.JavaCompilers; +import org.jetbrains.jps.service.JpsServiceManager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ReferenceCollectorExternalJavacOptionsProvider implements ExternalJavacOptionsProvider { + @NotNull + @Override + public Collection getOptions(@NotNull JavaCompilingTool tool) { + List options = new ArrayList(2); + if (tool.getId().equals(JavaCompilers.JAVAC_ID)) { + final JavacReferenceCollectorOptions + javacReferenceCollectorOptions = new JavacReferenceCollectorOptions(); + options.add("-D" + ExternalRefCollectorCompilerToolExtension.ENABLED_PARAM + "=" + javacReferenceCollectorOptions.isEnabled()); + if (javacReferenceCollectorOptions.isEnabled() && javacReferenceCollectorOptions.isImportRefsDivided()) { + options.add("-D" + ExternalRefCollectorCompilerToolExtension.DIVIDE_IMPORTS_PARAM + "=true"); + } + } + return options; + } + + private static class JavacReferenceCollectorOptions { + private final boolean myEnabled; + private final boolean myDivideImportRefs; + + private JavacReferenceCollectorOptions() { + boolean enabled = false; + boolean divideImportRefs = false; + for (JavacFileReferencesRegistrar listener : JpsServiceManager.getInstance().getExtensions(JavacFileReferencesRegistrar.class)) { + if (listener.isEnabled()) { + enabled = true; + if (listener.onlyImports()) { + divideImportRefs = true; + } + } + } + + myEnabled = enabled; + myDivideImportRefs = divideImportRefs; + } + + public boolean isEnabled() { + return myEnabled; + } + + public boolean isImportRefsDivided() { + return myDivideImportRefs; + } + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java index 4528e5c43c66..3811505c0bdb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacFileData.java @@ -16,19 +16,20 @@ package org.jetbrains.jps.javac.ast.api; import com.intellij.openapi.util.ThrowableComputable; -import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.util.ThrowableConsumer; -import com.intellij.util.io.*; +import com.intellij.util.io.DataInputOutputUtil; import org.jetbrains.annotations.NotNull; import javax.lang.model.element.Modifier; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.DataOutput; -import java.io.IOException; +import java.io.*; import java.util.*; public class JavacFileData { + private static final byte CLASS_MARKER = 0; + private static final byte METHOD_MARKER = 1; + private static final byte FIELD_MARKER = 2; + private static final byte FUN_EXPR_MARKER = 3; + private final String myFilePath; private final Collection myRefs; private final Collection myImportRefs; @@ -66,10 +67,13 @@ public class JavacFileData { @NotNull public byte[] asBytes() { - final BufferExposingByteArrayOutputStream os = new BufferExposingByteArrayOutputStream(); + final ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream stream = new DataOutputStream(os); try { - EXTERNALIZER.save(stream, this); + stream.writeUTF(getFilePath()); + saveRefs(stream, getRefs()); + saveRefs(stream, getImportRefs()); + saveDefs(stream, getDefs()); } catch (IOException e) { throw new RuntimeException(e); @@ -79,177 +83,140 @@ public class JavacFileData { @NotNull public static JavacFileData fromBytes(byte[] bytes) { - final UnsyncByteArrayInputStream is = new UnsyncByteArrayInputStream(bytes); + final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes)); try { - return EXTERNALIZER.read(new DataInputStream(is)); + return new JavacFileData(in.readUTF(), + readRefs(in), + readRefs(in), + readDefs(in)); } catch (IOException e) { throw new RuntimeException(e); } } - private static final DataExternalizer EXTERNALIZER = new DataExternalizer() { - DataExternalizer myRefSeqExternalizer = createRefExternalizer(); - DataExternalizer myDefSeqExternalizer = createDefExternalizer(); - - @Override - public void save(@NotNull DataOutput out, JavacFileData data) throws IOException { - EnumeratorStringDescriptor.INSTANCE.save(out, data.getFilePath()); - saveRefs(out, data.getRefs()); - saveRefs(out, data.getImportRefs()); - saveDefs(out, data.getDefs()); - } - - @Override - public JavacFileData read(@NotNull DataInput in) throws IOException { - return new JavacFileData(EnumeratorStringDescriptor.INSTANCE.read(in), - readRefs(in), - readRefs(in), - readDefs(in)); - } - - - private void saveRefs(final DataOutput out, Collection refs) throws IOException { - DataInputOutputUtil.writeSeq(out, refs, new ThrowableConsumer() { - @Override - public void consume(JavacRef ref) throws IOException { - myRefSeqExternalizer.save(out, ref); - } - }); - } - - private Collection readRefs(final DataInput in) throws IOException { - return DataInputOutputUtil.readSeq(in, new ThrowableComputable() { - @Override - public JavacRef compute() throws IOException { - return myRefSeqExternalizer.read(in); - } - }); - } - - private void saveDefs(final DataOutput out, List defs) throws IOException { - DataInputOutputUtil.writeSeq(out, defs, new ThrowableConsumer() { - @Override - public void consume(JavacDef def) throws IOException { - myDefSeqExternalizer.save(out, def); - } - }); - } - - private List readDefs(final DataInput in) throws IOException { - return DataInputOutputUtil.readSeq(in, new ThrowableComputable() { - @Override - public JavacDef compute() throws IOException { - return myDefSeqExternalizer.read(in); - } - }); - } - - }; - - private static DataExternalizer createDefExternalizer() { - return new DataExternalizer() { - private static final byte CLASS_MARKER = 0; - private static final byte FUN_EXPR_MARKER = 1; - - DataExternalizer refExternalizer = createRefExternalizer(); - + private static void saveRefs(final DataOutput out, Collection refs) throws IOException { + DataInputOutputUtil.writeSeq(out, refs, new ThrowableConsumer() { @Override - public void save(@NotNull DataOutput out, JavacDef def) throws IOException { - if (def instanceof JavacDef.JavacClassDef) { - out.writeByte(CLASS_MARKER); - final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses(); - out.writeInt(superClasses.length); - for (JavacRef aClass : superClasses) { - refExternalizer.save(out, aClass); - } - } - else if (def instanceof JavacDef.JavacFunExprDef) { - out.writeByte(FUN_EXPR_MARKER); - } else { - throw new IllegalStateException("unknown type: " + def.getClass()); - } - refExternalizer.save(out, def.getDefinedElement()); + public void consume(JavacRef ref) throws IOException { + writeJavacRef(out, ref); } - - @Override - public JavacDef read(@NotNull DataInput in) throws IOException { - final byte marker = in.readByte(); - switch (marker) { - case CLASS_MARKER: - final int supersSize = in.readInt(); - JavacRef[] superClasses = new JavacRef[supersSize]; - for (int i = 0; i < supersSize; i++) { - superClasses[i] = refExternalizer.read(in); - } - return new JavacDef.JavacClassDef(refExternalizer.read(in), superClasses); - case FUN_EXPR_MARKER: - return new JavacDef.JavacFunExprDef(refExternalizer.read(in)); - default: throw new IllegalStateException("unknown marker " + marker); - } - } - }; + }); } - private static DataExternalizer createRefExternalizer() { - return new DataExternalizer() { - private static final byte CLASS_MARKER = 0; - private static final byte METHOD_MARKER = 1; - private static final byte FIELD_MARKER = 2; - + private static Collection readRefs(final DataInput in) throws IOException { + return DataInputOutputUtil.readSeq(in, new ThrowableComputable() { @Override - public void save(@NotNull DataOutput out, JavacRef ref) throws IOException { - if (ref instanceof JavacRef.JavacClass) { - out.writeByte(CLASS_MARKER); - out.writeBoolean(((JavacRef.JavacClass)ref).isAnonymous()); - } - else if (ref instanceof JavacRef.JavacField) { - out.writeByte(FIELD_MARKER); - IOUtil.writeUTF(out, ref.getOwnerName()); - } - else if (ref instanceof JavacRef.JavacMethod) { - out.writeByte(METHOD_MARKER); - IOUtil.writeUTF(out, ref.getOwnerName()); - out.write(((JavacRef.JavacMethod)ref).getParamCount()); - } else { - throw new IllegalStateException("unknown type: " + ref.getClass()); - } - writeModifiers(out, ref.getModifiers()); - IOUtil.writeUTF(out, ref.getName()); + public JavacRef compute() throws IOException { + return readJavacRef(in); } + }); + } + private static void saveDefs(final DataOutput out, List defs) throws IOException { + DataInputOutputUtil.writeSeq(out, defs, new ThrowableConsumer() { @Override - public JavacRef read(@NotNull DataInput in) throws IOException { - final byte marker = in.readByte(); - switch (marker) { - case CLASS_MARKER: - return new JavacRef.JavacClassImpl(in.readBoolean(), readModifiers(in), IOUtil.readUTF(in)); - case METHOD_MARKER: - return new JavacRef.JavacMethodImpl(IOUtil.readUTF(in), in.readByte(), readModifiers(in), IOUtil.readUTF(in)); - case FIELD_MARKER: - return new JavacRef.JavacFieldImpl(IOUtil.readUTF(in), readModifiers(in), IOUtil.readUTF(in)); - default: - throw new IllegalStateException("unknown marker " + marker); + public void consume(JavacDef def) throws IOException { + writeJavacDef(out, def); + } + }); + } + + private static List readDefs(final DataInput in) throws IOException { + return DataInputOutputUtil.readSeq(in, new ThrowableComputable() { + @Override + public JavacDef compute() throws IOException { + return readJavacDef(in); + } + }); + } + + private static JavacDef readJavacDef(@NotNull DataInput in) throws IOException { + final byte marker = in.readByte(); + switch (marker) { + case CLASS_MARKER: + final int supersSize = in.readInt(); + JavacRef[] superClasses = new JavacRef[supersSize]; + for (int i = 0; i < supersSize; i++) { + superClasses[i] = readJavacRef(in); } - } + return new JavacDef.JavacClassDef(readJavacRef(in), superClasses); + case FUN_EXPR_MARKER: + return new JavacDef.JavacFunExprDef(readJavacRef(in)); + default: + throw new IllegalStateException("unknown marker " + marker); + } + } - private void writeModifiers(final DataOutput output, Set modifiers) throws IOException { - DataInputOutputUtil.writeSeq(output, modifiers, new ThrowableConsumer() { - @Override - public void consume(Modifier modifier) throws IOException { - IOUtil.writeUTF(output, modifier.name()); - } - }); + private static void writeJavacDef(@NotNull DataOutput out, JavacDef def) throws IOException { + if (def instanceof JavacDef.JavacClassDef) { + out.writeByte(CLASS_MARKER); + final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses(); + out.writeInt(superClasses.length); + for (JavacRef aClass : superClasses) { + writeJavacRef(out, aClass); } + } + else if (def instanceof JavacDef.JavacFunExprDef) { + out.writeByte(FUN_EXPR_MARKER); + } + else { + throw new IllegalStateException("unknown type: " + def.getClass()); + } + writeJavacRef(out, def.getDefinedElement()); + } - private Set readModifiers(final DataInput input) throws IOException { - return EnumSet.copyOf(DataInputOutputUtil.readSeq(input, new ThrowableComputable() { - @Override - public Modifier compute() throws IOException { - return Modifier.valueOf(IOUtil.readUTF(input)); - } - })); + private static void writeJavacRef(@NotNull DataOutput out, JavacRef ref) throws IOException { + if (ref instanceof JavacRef.JavacClass) { + out.writeByte(CLASS_MARKER); + out.writeBoolean(((JavacRef.JavacClass)ref).isAnonymous()); + } + else if (ref instanceof JavacRef.JavacField) { + out.writeByte(FIELD_MARKER); + out.writeUTF(ref.getOwnerName()); + } + else if (ref instanceof JavacRef.JavacMethod) { + out.writeByte(METHOD_MARKER); + out.writeUTF(ref.getOwnerName()); + out.write(((JavacRef.JavacMethod)ref).getParamCount()); + } + else { + throw new IllegalStateException("unknown type: " + ref.getClass()); + } + writeModifiers(out, ref.getModifiers()); + out.writeUTF(ref.getName()); + } + + private static JavacRef readJavacRef(@NotNull DataInput in) throws IOException { + final byte marker = in.readByte(); + switch (marker) { + case CLASS_MARKER: + return new JavacRef.JavacClassImpl(in.readBoolean(), readModifiers(in), in.readUTF()); + case METHOD_MARKER: + return new JavacRef.JavacMethodImpl(in.readUTF(), in.readByte(), readModifiers(in), in.readUTF()); + case FIELD_MARKER: + return new JavacRef.JavacFieldImpl(in.readUTF(), readModifiers(in), in.readUTF()); + default: + throw new IllegalStateException("unknown marker " + marker); + } + } + + private static void writeModifiers(final DataOutput output, Set modifiers) throws IOException { + DataInputOutputUtil.writeSeq(output, modifiers, new ThrowableConsumer() { + @Override + public void consume(Modifier modifier) throws IOException { + output.writeUTF(modifier.name()); } - }; + }); + } + + private static Set readModifiers(final DataInput input) throws IOException { + final List modifierList = DataInputOutputUtil.readSeq(input, new ThrowableComputable() { + @Override + public Modifier compute() throws IOException { + return Modifier.valueOf(input.readUTF()); + } + }); + return modifierList.isEmpty() ? Collections.emptySet() : EnumSet.copyOf(modifierList); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java index 84082ef5e18d..6656e770ed05 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ast/api/JavacNameTable.java @@ -26,6 +26,7 @@ import javax.lang.model.util.Elements; public class JavacNameTable { private final SLRUCache myParsedNameCache; private final Elements myElements; + private Name myAsterisk; public JavacNameTable(Elements elements) { myParsedNameCache = new SLRUCache(1000, 1000) { @@ -47,4 +48,12 @@ public class JavacNameTable { public String parseBinaryName(Element element) { return parseName(myElements.getBinaryName((TypeElement)element)); } + + @NotNull + public Name getAsterisk() { + if (myAsterisk == null) { + myAsterisk = myElements.getName("*"); + } + return myAsterisk; + } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt index 5dc1bb86ad66..da3e7d8ee0aa 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/references/ReferenceIndexTestBase.kt @@ -23,17 +23,14 @@ import com.intellij.util.indexing.impl.MapIndexStorage import com.intellij.util.indexing.impl.MapReduceIndex import com.intellij.util.io.PersistentStringEnumerator import org.jetbrains.jps.backwardRefs.BackwardReferenceIndexWriter -import org.jetbrains.jps.backwardRefs.NameEnumerator import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex import org.jetbrains.jps.backwardRefs.LightRef +import org.jetbrains.jps.backwardRefs.NameEnumerator import org.jetbrains.jps.backwardRefs.index.CompiledFileData import org.jetbrains.jps.backwardRefs.index.CompilerIndices -import org.jetbrains.jps.builders.BuildResult import org.jetbrains.jps.builders.JpsBuildTestCase import org.jetbrains.jps.builders.TestProjectBuilderLogger import org.jetbrains.jps.builders.logging.BuildLoggingManager -import org.jetbrains.jps.javac.JavaCompilerToolExtension -import org.jetbrains.jps.javac.ast.RefCollectorCompilerToolExtension import java.io.File abstract class ReferenceIndexTestBase : JpsBuildTestCase() { @@ -60,22 +57,6 @@ abstract class ReferenceIndexTestBase : JpsBuildTestCase() { assertIndexEquals("initialIndex.txt") } - override fun rebuildAllModules() { - try { - super.rebuildAllModules() - } finally { - (JavaCompilerToolExtension.getExtension(RefCollectorCompilerToolExtension.ID) as RefCollectorCompilerToolExtension).clearRegistrars() - } - } - - override fun buildAllModules(): BuildResult { - try { - return super.buildAllModules() - } finally { - (JavaCompilerToolExtension.getExtension(RefCollectorCompilerToolExtension.ID) as RefCollectorCompilerToolExtension).clearRegistrars() - } - } - protected fun renameFile(fileToRename: String, newName: String) { rename(orCreateProjectDir.path + "/m/" + fileToRename, newName) } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonBySchemaObjectCompletionContributor.java b/json/src/com/jetbrains/jsonSchema/impl/JsonBySchemaObjectCompletionContributor.java index 50ba6d58bd86..e3642c64390a 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonBySchemaObjectCompletionContributor.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonBySchemaObjectCompletionContributor.java @@ -243,7 +243,7 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor { // inserting longer string for proper formatting final String stringToInsert = ": 1"; EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 2); - formatInsertedString(context, project, stringToInsert.length()); + formatInsertedString(context, stringToInsert.length()); final int offset = editor.getCaretModel().getOffset(); context.getDocument().deleteString(offset, offset + 1); PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); @@ -277,7 +277,7 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor { EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 2); PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); - formatInsertedString(context, project, stringToInsert.length()); + formatInsertedString(context, stringToInsert.length()); EditorActionHandler handler = EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ENTER); handler.execute(editor, editor.getCaretModel().getCurrentCaret(), DataManager.getInstance().getDataContext(editor.getContentComponent())); @@ -288,7 +288,7 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor { SelectionModel model = editor.getSelectionModel(); EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, stringToInsert.length()); - formatInsertedString(context, context.getProject(), stringToInsert.length()); + formatInsertedString(context, stringToInsert.length()); int start = editor.getSelectionModel().getSelectionStart(); model.setSelection(start - value.length(), start); AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null); @@ -297,7 +297,7 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor { stringToInsert = ":[]"; EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 2); - formatInsertedString(context, project, stringToInsert.length()); + formatInsertedString(context, stringToInsert.length()); break; case _string: case _integer: @@ -366,14 +366,15 @@ class JsonBySchemaObjectCompletionContributor extends CompletionContributor { editor.getCaretModel().moveToOffset(newOffset); } - formatInsertedString(context, context.getProject(), stringToInsert.length()); + formatInsertedString(context, stringToInsert.length()); if (hasValues) { AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null); } } - public static void formatInsertedString(InsertionContext context, Project project, int offset) { + public static void formatInsertedString(@NotNull InsertionContext context, int offset) { + Project project = context.getProject(); PsiDocumentManager.getInstance(project).commitDocument(context.getDocument()); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); codeStyleManager.reformatText(context.getFile(), context.getStartOffset(), context.getTailOffset() + offset); diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index c93dd0de68de..05d0bd328cda 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -278,16 +278,15 @@ class SchemeManagerImpl(val fileSpec: String, val oldSchemes = schemes val schemes = oldSchemes.toMutableList() val newSchemesOffset = schemes.size - if (provider != null && provider.isApplicable(fileSpec, roamingType)) { - provider.processChildren(fileSpec, roamingType, { canRead(it) }) { name, input, readOnly -> - catchAndLog(name) { - val scheme = loadScheme(name, input, schemes, filesToDelete) - if (readOnly && scheme != null) { - readOnlyExternalizableSchemes.put(scheme.name, scheme) - } + if (provider != null && provider.processChildren(fileSpec, roamingType, { canRead(it) }) { name, input, readOnly -> + catchAndLog(name) { + val scheme = loadScheme(name, input, schemes, filesToDelete) + if (readOnly && scheme != null) { + readOnlyExternalizableSchemes.put(scheme.name, scheme) } - true } + true + }) { } else { ioDirectory.directoryStreamIfExists({ canRead(it.fileName.toString()) }) { @@ -335,7 +334,7 @@ class SchemeManagerImpl(val fileSpec: String, loadSchemes() - (processor as? LazySchemeProcessor)?.reloaded() + (processor as? LazySchemeProcessor)?.reloaded(this) } private fun removeExternalizableSchemes() { @@ -717,14 +716,13 @@ class SchemeManagerImpl(val fileSpec: String, } private fun deleteFiles(errors: MutableList, filesToDelete: MutableSet) { - if (provider != null && provider.enabled) { + if (provider != null) { val iterator = filesToDelete.iterator() for (name in iterator) { errors.catch { val spec = "$fileSpec/$name" - if (provider.isApplicable(spec, roamingType)) { + if (provider.delete(spec, roamingType)) { iterator.remove() - provider.delete(spec, roamingType) } } } diff --git a/platform/configuration-store-impl/src/StreamProviderWrapper.kt b/platform/configuration-store-impl/src/StreamProviderWrapper.kt index d3751393c286..6bf219ab3a10 100644 --- a/platform/configuration-store-impl/src/StreamProviderWrapper.kt +++ b/platform/configuration-store-impl/src/StreamProviderWrapper.kt @@ -10,28 +10,25 @@ class StreamProviderWrapper : StreamProvider { override val enabled: Boolean get() = streamProvider.let { it != null && it.enabled } - override fun isApplicable(fileSpec: String, roamingType: RoamingType): Boolean { - return enabled && streamProvider!!.isApplicable(fileSpec, roamingType) - } + override fun isApplicable(fileSpec: String, roamingType: RoamingType) = streamProvider?.isApplicable(fileSpec, roamingType) ?: false - override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> R): R { - return streamProvider!!.read(fileSpec, roamingType, consumer) - } + override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> Unit) = streamProvider?.read(fileSpec, roamingType, consumer) ?: false override fun processChildren(path: String, roamingType: RoamingType, filter: Function1, - processor: Function3) { - streamProvider!!.processChildren(path, roamingType, filter, processor) + processor: Function3): Boolean { + return streamProvider?.let { + it.processChildren(path, roamingType, filter, processor) + true + } ?: false } override fun write(fileSpec: String, content: ByteArray, size: Int, roamingType: RoamingType) { streamProvider!!.write(fileSpec, content, size, roamingType) } - override fun delete(fileSpec: String, roamingType: RoamingType) { - streamProvider!!.delete(fileSpec, roamingType) - } + override fun delete(fileSpec: String, roamingType: RoamingType) = streamProvider?.delete(fileSpec, roamingType) ?: false } fun StreamProvider?.getOriginalProvider() = if (this is StreamProviderWrapper) streamProvider else null \ No newline at end of file diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index 626c1dcb5c3f..ed308b9c4a98 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -47,25 +47,25 @@ abstract class XmlElementStorage protected constructor(val fileSpec: String, override fun hasState(storageData: StateMap, componentName: String) = storageData.hasState(componentName) - override fun loadData(): StateMap { - val element: Element? - // we don't use local data if has stream provider - if (provider != null && provider.isApplicable(fileSpec, roamingType)) { - element = LOG.catchAndLog { - loadDataFromProvider().apply { dataLoadedFromProvider(this) } + override fun loadData() = loadElement()?.let { loadState(it) } ?: StateMap.EMPTY + + private fun loadElement(useStreamProvider: Boolean = true): Element? { + var element: Element? = null + LOG.catchAndLog { + if (!useStreamProvider || !(provider?.read(fileSpec, roamingType) { + it?.let { + element = loadElement(it) + } + } ?: false)) { + element = loadLocalData() } } - else { - element = loadLocalData() - } - return element?.let { loadState(element) } ?: StateMap.EMPTY + return element } protected open fun dataLoadedFromProvider(element: Element?) { } - private fun loadDataFromProvider(): Element? = provider!!.read(fileSpec, roamingType) { it?.let(::loadElement) } - private fun loadState(element: Element): StateMap { beforeElementLoaded(element) return StateMap.fromMap(FileStorageCoreUtil.load(element, pathMacroSubstitutor, true)) @@ -127,15 +127,15 @@ abstract class XmlElementStorage protected constructor(val fileSpec: String, } val provider = storage.provider - if (provider != null && provider.isApplicable(storage.fileSpec, storage.roamingType)) { - if (element == null) { - provider.delete(storage.fileSpec, storage.roamingType) - } - else { - // we should use standard line-separator (\n) - stream provider can share file content on any OS - provider.write(storage.fileSpec, element.toBufferExposingByteArray(), storage.roamingType) + if (element == null) { + if (provider == null || !provider.delete(storage.fileSpec, storage.roamingType)) { + saveLocally(null) } } + else if (provider != null && provider.isApplicable(storage.fileSpec, storage.roamingType)) { + // we should use standard line-separator (\n) - stream provider can share file content on any OS + provider.write(storage.fileSpec, element.toBufferExposingByteArray(), storage.roamingType) + } else { saveLocally(element) } @@ -163,14 +163,14 @@ abstract class XmlElementStorage protected constructor(val fileSpec: String, updatedFrom(changedComponentNames, deleted, true) } - fun updatedFrom(changedComponentNames: MutableSet, deleted: Boolean, streamProvider: Boolean) { + fun updatedFrom(changedComponentNames: MutableSet, deleted: Boolean, useStreamProvider: Boolean) { if (roamingType == RoamingType.DISABLED) { // storage roaming was changed to DISABLED, but settings repository has old state return } LOG.catchAndLog { - val newElement = if (deleted) null else if (streamProvider) loadDataFromProvider() else loadLocalData() + val newElement = if (deleted) null else loadElement(useStreamProvider) val states = storageDataRef.get() if (newElement == null) { // if data was loaded, mark as changed all loaded components diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index d53084807b2a..3d96c2904891 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -323,7 +323,8 @@ internal class ApplicationStoreTest { private fun writeConfig(fileName: String, @Language("XML") data: String) = testAppConfig.writeChild(fileName, data) private class MyStreamProvider : StreamProvider { - override fun processChildren(path: String, roamingType: RoamingType, filter: (String) -> Boolean, processor: (String, InputStream, Boolean) -> Boolean) { + override fun processChildren(path: String, roamingType: RoamingType, filter: (String) -> Boolean, processor: (String, InputStream, Boolean) -> Boolean): Boolean { + return true } val data: MutableMap> = THashMap() @@ -341,13 +342,15 @@ internal class ApplicationStoreTest { return map } - override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> R): R { + override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> Unit): Boolean { val data = getMap(roamingType).get(fileSpec) - return data?.let { ByteArrayInputStream(it.toByteArray()) }.let(consumer) + data?.let { ByteArrayInputStream(it.toByteArray()) }.let(consumer) + return true } - override fun delete(fileSpec: String, roamingType: RoamingType) { - data[roamingType]?.remove(fileSpec) + override fun delete(fileSpec: String, roamingType: RoamingType): Boolean { + data.get(roamingType)?.remove(fileSpec) + return true } } diff --git a/platform/configuration-store-impl/testSrc/DoNotSaveDefaults.kt b/platform/configuration-store-impl/testSrc/DoNotSaveDefaults.kt new file mode 100644 index 000000000000..a12c4e3c1b5a --- /dev/null +++ b/platform/configuration-store-impl/testSrc/DoNotSaveDefaults.kt @@ -0,0 +1,44 @@ +package com.intellij.configurationStore + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.impl.ApplicationImpl +import com.intellij.openapi.components.stateStore +import com.intellij.testFramework.ProjectRule +import com.intellij.testFramework.runInEdtAndWait +import com.intellij.util.io.delete +import org.junit.ClassRule +import org.junit.Test +import java.nio.file.Paths + +class DoNotSaveDefaultsTest { + companion object { + @JvmField + @ClassRule + val projectRule = ProjectRule() + + init { + Paths.get(PathManager.getConfigPath()).delete() + } + } + + @Test + fun test() { + val app = ApplicationManager.getApplication() as ApplicationImpl + val directory = app.stateStore.stateStorageManager.expandMacros(APP_CONFIG) + val dirPath = Paths.get(directory) + try { + app.doNotSave(false) + runInEdtAndWait { + app.saveAll() + } + } + finally { + app.doNotSave(true) + } + + println(directory) + println(printDirectoryTree(dirPath.toFile())) + } +} + diff --git a/platform/configuration-store-impl/testSrc/FileTreePrinter.kt b/platform/configuration-store-impl/testSrc/FileTreePrinter.kt new file mode 100644 index 000000000000..5919805a9eeb --- /dev/null +++ b/platform/configuration-store-impl/testSrc/FileTreePrinter.kt @@ -0,0 +1,45 @@ +package com.intellij.configurationStore + +import java.io.File + +fun printDirectoryTree(folder: File): String { + if (!folder.isDirectory) { + throw IllegalArgumentException("folder is not a Directory") + } + val indent = 0 + val sb = StringBuilder() + printDirectoryTree(folder, indent, sb) + return sb.toString() +} + +private fun printDirectoryTree(folder: File, indent: Int, sb: StringBuilder) { + if (!folder.isDirectory) { + throw IllegalArgumentException("folder is not a Directory") + } + getIndentString(indent, sb) + sb.append("\u251c\u2500\u2500") + sb.append(folder.name) + sb.append("/") + sb.append("\n") + for (file in folder.listFiles()!!) { + if (file.isDirectory) { + printDirectoryTree(file, indent + 1, sb) + } + else { + printFile(file, indent + 1, sb) + } + } +} + +private fun printFile(file: File, indent: Int, sb: StringBuilder) { + getIndentString(indent, sb) + sb.append("\u251c\u2500\u2500") + sb.append(file.name) + sb.append("\n") +} + +private fun getIndentString(indent: Int, sb: StringBuilder) { + for (i in 0..indent - 1) { + sb.append(" ") + } +} \ No newline at end of file diff --git a/platform/configuration-store-impl/testSrc/MockStreamProvider.kt b/platform/configuration-store-impl/testSrc/MockStreamProvider.kt index fe4c80e4c815..c7593602ff4d 100644 --- a/platform/configuration-store-impl/testSrc/MockStreamProvider.kt +++ b/platform/configuration-store-impl/testSrc/MockStreamProvider.kt @@ -11,17 +11,18 @@ class MockStreamProvider(private val dir: Path) : StreamProvider { dir.resolve(fileSpec).write(content, 0, size) } - override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> R): R { + override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> Unit): Boolean { val file = dir.resolve(fileSpec) try { - return file.inputStream().use(consumer) + file.inputStream().use(consumer) } catch (e: NoSuchFileException) { - return consumer(null) + consumer(null) } + return true } - override fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean) { + override fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean): Boolean { dir.resolve(path).directoryStreamIfExists({ filter(it.fileName.toString()) }) { for (file in it) { val attributes = file.basicAttributesIfExists() @@ -40,9 +41,12 @@ class MockStreamProvider(private val dir: Path) : StreamProvider { } } } + + return true } - override fun delete(fileSpec: String, roamingType: RoamingType) { + override fun delete(fileSpec: String, roamingType: RoamingType): Boolean { dir.resolve(fileSpec).delete() + return true } } diff --git a/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java b/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java index dd5c7aaff068..9cae5d6aa56e 100644 --- a/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java +++ b/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java @@ -143,6 +143,7 @@ public class SearchReplaceComponent extends EditorHeaderComponent implements Dat }; myLeftPanel = new NonOpaquePanel(new BorderLayout()); + myLeftPanel.setBorder(JBUI.Borders.emptyLeft(6)); myLeftPanel.add(mySearchFieldWrapper, BorderLayout.NORTH); myLeftPanel.add(myReplaceFieldWrapper, BorderLayout.SOUTH); diff --git a/platform/lang-impl/src/com/intellij/find/SearchTextArea.java b/platform/lang-impl/src/com/intellij/find/SearchTextArea.java index 90a602360b44..0c36cbdb401b 100644 --- a/platform/lang-impl/src/com/intellij/find/SearchTextArea.java +++ b/platform/lang-impl/src/com/intellij/find/SearchTextArea.java @@ -20,6 +20,7 @@ import com.intellij.find.editorHeaderActions.Utils; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; +import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI; import com.intellij.ide.ui.laf.intellij.MacIntelliJIconCache; import com.intellij.ide.ui.laf.intellij.MacIntelliJTextFieldUI; import com.intellij.openapi.actionSystem.*; @@ -27,6 +28,7 @@ import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.actionSystem.impl.InplaceActionButtonLook; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -37,6 +39,7 @@ import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.panels.NonOpaquePanel; +import com.intellij.ui.paint.RectanglePainter; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.JBDimension; import com.intellij.util.ui.JBInsets; @@ -52,7 +55,6 @@ import javax.swing.event.DocumentEvent; import javax.swing.text.DefaultEditorKit; import java.awt.*; import java.awt.event.*; -import java.awt.geom.RoundRectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -64,7 +66,8 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList private ActionButton myNewLineButton; private ActionButton myClearButton; private JBScrollPane myScrollPane; - private ActionButton myHistoryPopupButton; + private final ActionButton myHistoryPopupButton; + private final LafHelper myHelper; public SearchTextArea(boolean search) { this(new JTextArea(), search, false); @@ -103,8 +106,8 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList public Insets getBorderInsets(Component c) { int bottom = (StringUtil.getLineBreakCount(myTextArea.getText()) > 0) ? 2 : UIUtil.isUnderDarcula() ? 1 : 0; int top = myTextArea.getFontMetrics(myTextArea.getFont()).getHeight() <= 16 ? 2 : 1; - if (JBUI.isHiDPI()) bottom = 2; - if (JBUI.isHiDPI()) top = 2; + if (JBUI.isHiDPI(c)) bottom = 2; + if (JBUI.isHiDPI(c)) top = 2; return new JBInsets(top, 0, bottom, 0); } @@ -122,6 +125,8 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList myInfoLabel = new JBLabel(UIUtil.ComponentStyle.SMALL); myInfoLabel.setForeground(JBColor.GRAY); + myHelper = createHelper(); + myHistoryPopupButton = createButton(new ShowHistoryAction(search)); myClearButton = createButton(new ClearAction()); myNewLineButton = createButton(new NewLineAction()); @@ -131,20 +136,17 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList } protected void updateLayout() { - int height = UIUtil.getLineHeight(myTextArea); - Insets insets = myTextArea.getInsets(); - int extraGap = Math.max(JBUI.isHiDPI() ? 0 : 1, (height + insets.top + insets.bottom - JBUI.scale(16)) / 2); - setBorder(new EmptyBorder(3 + Math.max(0, JBUI.scale(16) - height) / 2, 6, 3, 4));//In case of small fonts we shouldn't align to top - setLayout(new MigLayout("flowx, ins 0, gapx " + JBUI.scale(4))); + setBorder(myHelper.getBorder()); + setLayout(new MigLayout(myHelper.getLayoutConstraints())); removeAll(); - add(myHistoryPopupButton, "ay top, gaptop " + extraGap +", gapleft" + (JBUI.isHiDPI() ? 4 : 0)); + add(myHistoryPopupButton, myHelper.getHistoryButtonConstraints()); add(myScrollPane, "ay top, growx, pushx"); //TODO combine icons/info modes if (myInfoMode) { add(myInfoLabel); } else { - add(myIconsPanel, "gaptop " + extraGap + ",ay top, gapright " + extraGap/2); + add(myIconsPanel, myHelper.getIconsPanelConstraints()); updateIconsLayout(); } } @@ -181,7 +183,7 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList if (multiline && showNewLine) { myIconsPanel.add(myNewLineButton); } - myIconsPanel.setBorder(JBUI.Borders.emptyBottom(rows == 2 ? 3 : 0)); + myIconsPanel.setBorder(myHelper.getIconsPanelBorder(rows)); myScrollPane.revalidate(); doLayout(); } @@ -228,38 +230,10 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList @Override public void paint(Graphics graphics) { Graphics2D g = (Graphics2D)graphics.create(); - boolean hasFocus = myTextArea.hasFocus(); try { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - Rectangle r = new Rectangle(getSize()); - r.height = Math.max(r.height, myScrollPane.getHeight() + getInsets().top + getInsets().bottom); - if (myIconsPanel.getParent() != null) { - r.height = Math.max(r.height, myIconsPanel.getHeight() + getInsets().top + getInsets().bottom); - } - if (r.height % 2 == 1) r.height--; - int arcSize = Math.min(Math.max(25, myTextArea.getFontMetrics(myTextArea.getFont()).getHeight() * 3 / 2), r.height - 1); - if (JBUI.isHiDPI()) arcSize = JBUI.scale(21); - Color borderColor = myTextArea.isEnabled() ? enabledBorderColor : disabledBorderColor; - if (SystemInfo.isMac && (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderAquaLookAndFeel())) { - g.setColor(borderColor); - MacIntelliJTextFieldUI.paintAquaSearchFocusRing(g, r, myTextArea); - } - else { - JBInsets.removeFrom(r, new JBInsets(3, 3, 3, 3)); - if (hasFocus && (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula())) { - DarculaUIUtil.paintSearchFocusRing(g, r, myTextArea, arcSize); - } - else { - Shape shape = UIUtil.isUnderWindowsLookAndFeel() - ? new Rectangle(r.x, r.y, r.width, r.height) - : new RoundRectangle2D.Double(r.x, r.y, r.width, r.height, arcSize - JBUI.scale(5), arcSize - JBUI.scale(5)); - g.setColor(myTextArea.getBackground()); - g.fill(shape); - g.setColor(borderColor); - g.draw(shape); - } - } + myHelper.paint(g); } finally { g.dispose(); @@ -284,7 +258,7 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList public ShowHistoryAction(boolean search) { super((search ? "Search" : "Replace") + " History", (search ? "Search" : "Replace") + " history", - MacIntelliJIconCache.getIcon("searchFieldWithHistory")); + myHelper.getShowHistoryIcon()); myShowSearchHistory = search; @@ -321,7 +295,7 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList private class ClearAction extends DumbAwareAction { public ClearAction() { - super(null, null, AllIcons.Actions.Clear); + super(null, null, myHelper.getClearIcon()); } @Override @@ -332,7 +306,8 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList private class NewLineAction extends DumbAwareAction { public NewLineAction() { - super(null, "New line (" + KeymapUtil.getKeystrokeText(SearchReplaceComponent.NEW_LINE_KEYSTROKE) + ")", AllIcons.Actions.SearchNewLine); + super(null, "New line (" + KeymapUtil.getKeystrokeText(SearchReplaceComponent.NEW_LINE_KEYSTROKE) + ")", + AllIcons.Actions.SearchNewLine); } @Override @@ -340,4 +315,152 @@ public class SearchTextArea extends NonOpaquePanel implements PropertyChangeList new DefaultEditorKit.InsertBreakAction().actionPerformed(new ActionEvent(myTextArea, 0, "action")); } } + + @NotNull + private LafHelper createHelper() { + return SystemInfo.isMac ? new MacLafHelper() : new DefaultLafHelper(); + } + + private static abstract class LafHelper { + abstract Border getBorder(); + + abstract String getLayoutConstraints(); + + abstract String getHistoryButtonConstraints(); + + abstract String getIconsPanelConstraints(); + + abstract Border getIconsPanelBorder(int rows); + + abstract Icon getShowHistoryIcon(); + + abstract Icon getClearIcon(); + + abstract void paint(Graphics2D g); + } + + private class MacLafHelper extends LafHelper { + @Override + Border getBorder() { + return new EmptyBorder(3 + Math.max(0, JBUI.scale(16) - UIUtil.getLineHeight(myTextArea)) / 2, 6, 3, 4); + } + + @Override + String getLayoutConstraints() { + return "flowx, ins 0, gapx " + JBUI.scale(4); + } + + @Override + String getHistoryButtonConstraints() { + int extraGap = getExtraGap(); + return "ay top, gaptop " + extraGap + ", gapleft" + (JBUI.isHiDPI(myTextArea) ? 4 : 0); + } + + private int getExtraGap() { + int height = UIUtil.getLineHeight(myTextArea); + Insets insets = myTextArea.getInsets(); + return Math.max(JBUI.isHiDPI(myTextArea) ? 0 : 1, (height + insets.top + insets.bottom - JBUI.scale(16)) / 2); + } + + + @Override + String getIconsPanelConstraints() { + int extraGap = getExtraGap(); + return "gaptop " + extraGap + ",ay top, gapright " + extraGap / 2; + } + + @Override + Border getIconsPanelBorder(int rows) { + return JBUI.Borders.emptyBottom(rows == 2 ? 3 : 0); + } + + @Override + Icon getShowHistoryIcon() { + return MacIntelliJIconCache.getIcon("searchFieldWithHistory"); + } + + @Override + Icon getClearIcon() { + return AllIcons.Actions.Clear; + } + + @Override + void paint(Graphics2D g) { + Rectangle r = new Rectangle(getSize()); + int h = myIconsPanel.getParent() != null ? Math.max(myIconsPanel.getHeight(), myScrollPane.getHeight()) : myScrollPane.getHeight(); + r.height = Math.max(r.height, h + getInsets().top + getInsets().bottom); + if (r.height % 2 == 1) r.height--; + g.setColor(myTextArea.isEnabled() ? enabledBorderColor : disabledBorderColor); + MacIntelliJTextFieldUI.paintAquaSearchFocusRing(g, r, myTextArea); + } + } + + private class DefaultLafHelper extends LafHelper { + @Override + Border getBorder() { + return JBUI.Borders.empty(2); + } + + @Override + String getLayoutConstraints() { + return "flowx, ins 2 " + JBUI.scale(4) + " 2 " + (3 + JBUI.scale(1)) + ", gapx " + JBUI.scale(4); + } + + @Override + String getHistoryButtonConstraints() { + return "ay top, gaptop " + JBUI.scale(getIconTopGap());//Double scaling inside but it looks not bad + } + + private int getIconTopGap() { + return Math.max(2, (UIUtil.getLineHeight(myTextArea) + myTextArea.getInsets().top + myTextArea.getInsets().bottom - JBUI.scale(16)) / 2); + } + + @Override + String getIconsPanelConstraints() { + return "gaptop " + getIconTopGap() + ",ay top"; + } + + @Override + Border getIconsPanelBorder(int rows) { + return JBUI.Borders.empty(); + } + + @Override + Icon getShowHistoryIcon() { + Icon searchIcon = UIManager.getIcon("TextField.darcula.searchWithHistory.icon"); + if (searchIcon == null) { + searchIcon = IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/searchWithHistory.png", DarculaTextFieldUI.class, true); + } + return searchIcon; + } + + @Override + Icon getClearIcon() { + Icon clearIcon = UIManager.getIcon("TextField.darcula.clear.icon"); + if (clearIcon == null) { + clearIcon = IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/clear.png", DarculaTextFieldUI.class, true); + } + return clearIcon; + } + + @Override + void paint(Graphics2D g) { + Rectangle r = new Rectangle(getSize()); + JBInsets.removeFrom(r, getInsets()); + if (r.height % 2 == 1) r.height++; + int arcSize = JBUI.scale(26); + + JBInsets.removeFrom(r, new JBInsets(1, 1, 1, 1)); + if (myTextArea.hasFocus()) { + g.setColor(myTextArea.getBackground()); + RectanglePainter.FILL.paint(g, r.x, r.y, r.width, r.height, arcSize); + DarculaUIUtil.paintSearchFocusRing(g, r, myTextArea, arcSize); + } + else { + arcSize -= JBUI.scale(5); + RectanglePainter + .paint(g, r.x, r.y, r.width, r.height, arcSize, myTextArea.getBackground(), myTextArea.isEnabled() ? Gray._100 : Gray._83); + } + } + } } diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java index 1bbeed75c071..0618531dd089 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/FlipCommaIntention.java @@ -16,13 +16,13 @@ package com.intellij.openapi.editor.actions; import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.lang.Language; -import com.intellij.lang.LanguageExtension; +import com.intellij.lang.*; import com.intellij.lang.parser.GeneratedParserUtilBase; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -130,6 +130,24 @@ public class FlipCommaIntention implements IntentionAction { @Nullable private static PsiElement smartAdvance(PsiElement element, boolean fwd) { - return getSiblings(element, fwd).filter(e -> isFlippable(e)).first(); + final PsiElement candidate = getSiblings(element, fwd).filter(e -> isFlippable(e)).first(); + if (candidate != null && isBrace(candidate)) return null; + return candidate; + } + + private static boolean isBrace(@NotNull PsiElement candidate) { + final ASTNode node = candidate.getNode(); + if (node != null && node.getFirstChildNode() == null) { + final PairedBraceMatcher braceMatcher = LanguageBraceMatching.INSTANCE.forLanguage(candidate.getLanguage()); + if (braceMatcher != null) { + final IElementType elementType = node.getElementType(); + for (BracePair pair : braceMatcher.getPairs()) { + if (elementType == pair.getLeftBraceType() || elementType == pair.getRightBraceType()) { + return true; + } + } + } + } + return false; } } diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java index 2a6ada8617d7..0abeebb03cb3 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java @@ -36,6 +36,7 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -233,8 +234,7 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple public boolean beforeOkAction() { try { PluginManager.saveDisabledPlugins(myPluginGroups.getDisabledPluginIds(), false); - IdeInitialConfigButtonUsages.setPredefinedDisabledPlugins(new com.intellij.util.containers.HashSet<>(myPluginGroups.getDisabledPluginIds())/* - myPluginGroups.getTree().values().stream().flatMap(pair -> pair.getSecond().stream()).collect(Collectors.toSet())*/); + IdeInitialConfigButtonUsages.setPredefinedDisabledPlugins(new HashSet<>(myPluginGroups.getDisabledPluginIds())); } catch (IOException ignored) { } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java index 8a2aeea48bc4..e7d09f75ada1 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJTextFieldUI.java @@ -223,7 +223,7 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI { if (c.hasFocus()) { Color graphiteColor = new Color(0x6f6f72); Color blueColor = ColorUtil.brighter(new Color(0x006de2), 3); - g.setColor(ColorUtil.withAlpha(IntelliJLaf.isGraphite() ? graphiteColor : blueColor, .3)); + g.setColor(ColorUtil.withAlpha(IntelliJLaf.isGraphite() ? graphiteColor : blueColor, .35)); Area area = new Area(getShape(r, 7, false)); area.subtract(new Area(getShape(r, 3.5, true))); g.fill(area); @@ -232,7 +232,7 @@ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI { } private static RoundRectangle2D.Double getShape(Rectangle r, double radius, boolean inner) { - double max_radius = 7; + double max_radius = 6; radius = Math.min(max_radius, Math.max(0, radius)); double inset = max_radius - radius; double indent = inner ? 0.5 : 0; diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeInitialConfigButtonUsages.java b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeInitialConfigButtonUsages.java index cb261e398c76..5f1ee44918bd 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeInitialConfigButtonUsages.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeInitialConfigButtonUsages.java @@ -31,19 +31,27 @@ public final class IdeInitialConfigButtonUsages { private static volatile Set ourPredefinedDisabledPlugins = ALL_PLUGINS_SELECTED; - private static volatile Set ourDownloadedPlugins = Collections.emptySet(); + private static Set ourDownloadedPlugins = Collections.emptySet(); public static ConfigImport getConfigImport() { return ourConfigImport; } - public static void setConfigImport(JRadioButton ...buttons) { - if (buttons.length < ConfigImport.values().length) { - for (int i = 0; i < buttons.length; i++) { - if (buttons[i] != null && buttons[i].isSelected()) { - ourConfigImport = ConfigImport.values()[i]; - } - } + public static void setConfigImport(JRadioButton myRbDoNotImport, + JRadioButton myRbImport, + JRadioButton myRbImportAuto, + JRadioButton myCustomButton) { + if (myRbDoNotImport != null && myRbDoNotImport.isSelected()) { + ourConfigImport = ConfigImport.DO_NOT_IMPORT; + } + else if (myRbImport != null && myRbImport.isSelected()) { + ourConfigImport = ConfigImport.IMPORT_PATH; + } + else if (myRbImportAuto != null && myRbImportAuto.isSelected()) { + ourConfigImport = ConfigImport.IMPORT_AUTO; + } + else if (myCustomButton != null && myCustomButton.isSelected()) { + ourConfigImport = ConfigImport.IMPORT_CUSTOM; } } @@ -66,11 +74,11 @@ public final class IdeInitialConfigButtonUsages { ourPredefinedDisabledPlugins = predefinedDisabledPlugins; } - public static Set getDownloadedPlugins() { + public synchronized static Set getDownloadedPlugins() { return ourDownloadedPlugins; } - public static void addDownloadedPlugin(String pluginId) { + public synchronized static void addDownloadedPlugin(String pluginId) { if (ourDownloadedPlugins.isEmpty()) { ourDownloadedPlugins = new HashSet<>(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java index 7faba683c61c..15cce3b24847 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java @@ -40,6 +40,7 @@ import com.intellij.openapi.options.SchemeState; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.AppUIUtil; import com.intellij.util.ComponentTreeEventDispatcher; import com.intellij.util.JdomKt; import com.intellij.util.io.URLUtil; @@ -130,9 +131,12 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Pers } @Override - public void reloaded() { - initEditableDefaultSchemesCopies(); - initEditableBundledSchemesCopies(); + public void reloaded(@NotNull SchemeManager schemeManager) { + // todo is EDT really required (develar: for now it will be better just to use invokeOnEdt) + AppUIUtil.invokeOnEdt(() -> { + initEditableDefaultSchemesCopies(); + initEditableBundledSchemesCopies(); + }); } } mySchemeManager = schemeManagerFactory.create(FILE_SPEC, new EditorColorSchemeProcessor()); diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.kt index 5a98a1f290ac..5f2e28212a95 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.kt @@ -31,6 +31,7 @@ import com.intellij.openapi.options.SchemeManagerFactory import com.intellij.openapi.util.Condition import com.intellij.openapi.util.Conditions import com.intellij.openapi.util.Disposer +import com.intellij.ui.AppUIUtil import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.SmartHashSet import gnu.trove.THashMap @@ -59,6 +60,15 @@ class KeymapManagerImpl(defaultKeymap: DefaultKeymap, factory: SchemeManagerFact listener.activeKeymapChanged(newScheme) } } + + override fun reloaded(schemeManager: SchemeManager) { + if (schemeManager.currentScheme == null) { + // listeners expect that event will be fired in EDT + AppUIUtil.invokeOnEdt { + schemeManager.setCurrentSchemeName(defaultKeymap.defaultKeymapName, true) + } + } + } }) val systemDefaultKeymap = if (WelcomeWizardUtil.getWizardMacKeymap() == null) defaultKeymap.defaultKeymapName else WelcomeWizardUtil.getWizardMacKeymap() diff --git a/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt b/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt index 3b62939d7f90..c86517fbd917 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/LayoutBuilder.kt @@ -26,9 +26,7 @@ import javax.swing.ButtonGroup import javax.swing.JLabel class LayoutBuilder(val `$`: LayoutBuilderImpl, val buttonGroup: ButtonGroup? = null) { - inline fun row(label: String, init: Row.() -> Unit) { - row(label = Label(label), init = init) - } + inline fun row(label: String, init: Row.() -> Unit) = row(label = Label(label), init = init) inline fun row(label: JLabel? = null, separated: Boolean = false, init: Row.() -> Unit): Row { val row = `$`.newRow(label, buttonGroup, separated) diff --git a/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt b/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt index 2a8ba406fcea..692cfee2a0fc 100644 --- a/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt +++ b/platform/platform-impl/src/com/intellij/ui/layout/MigLayoutBuilder.kt @@ -81,6 +81,7 @@ internal class MigLayoutBuilder : LayoutBuilderImpl { } lc.noVisualPadding() + lc.hideMode = 3 container.layout = MigLayout(lc) @@ -209,6 +210,19 @@ private class MigLayoutRow(private val componentConstraints: MutableMap protected abstract val builder: LayoutBuilderImpl diff --git a/platform/projectModel-api/src/com/intellij/configurationStore/StreamProvider.kt b/platform/projectModel-api/src/com/intellij/configurationStore/StreamProvider.kt index eda9fd779588..e49ed1040431 100644 --- a/platform/projectModel-api/src/com/intellij/configurationStore/StreamProvider.kt +++ b/platform/projectModel-api/src/com/intellij/configurationStore/StreamProvider.kt @@ -24,6 +24,9 @@ interface StreamProvider { val enabled: Boolean get() = true + /** + * Called only on `write` + */ fun isApplicable(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT) = true /** @@ -33,14 +36,22 @@ interface StreamProvider { */ fun write(fileSpec: String, content: ByteArray, size: Int = content.size, roamingType: RoamingType = RoamingType.DEFAULT) - fun read(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT, consumer: (InputStream?) -> R): R + /** + * `true` if provider is applicable for file. + */ + fun read(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT, consumer: (InputStream?) -> Unit): Boolean - fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean) + /** + * `true` if provider is fully responsible and local sources must be not used. + */ + fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean): Boolean /** * Delete file or directory + * + * `true` if provider is fully responsible and local sources must be not used. */ - fun delete(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT) + fun delete(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT): Boolean } @TestOnly diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/SchemeManagerIprProvider.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/SchemeManagerIprProvider.kt index ce4929252d00..f40bb9d9caee 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/SchemeManagerIprProvider.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/SchemeManagerIprProvider.kt @@ -27,24 +27,26 @@ import java.io.InputStream class SchemeManagerIprProvider(private val subStateTagName: String) : StreamProvider { private val nameToData = ContainerUtil.newConcurrentMap() - override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> R): R { - val name = PathUtilRt.getFileName(fileSpec) - return nameToData.get(name)?.let(ByteArray::inputStream).let { consumer(it) } + override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> Unit): Boolean { + nameToData.get(PathUtilRt.getFileName(fileSpec))?.let(ByteArray::inputStream).let { consumer(it) } + return true } - override fun delete(fileSpec: String, roamingType: RoamingType) { + override fun delete(fileSpec: String, roamingType: RoamingType): Boolean { nameToData.remove(PathUtilRt.getFileName(fileSpec)) + return true } override fun processChildren(path: String, roamingType: RoamingType, filter: (String) -> Boolean, - processor: (String, InputStream, Boolean) -> Boolean) { + processor: (String, InputStream, Boolean) -> Boolean): Boolean { for ((name, data) in nameToData) { if (filter(name) && !data.inputStream().use { processor(name, it, false) }) { break } } + return true } override fun write(fileSpec: String, content: ByteArray, size: Int, roamingType: RoamingType) { diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt index 0215c7731626..bcaccc8bb05d 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt @@ -66,7 +66,10 @@ abstract class LazySchemeProcessor(pri open fun isSchemeEqualToBundled(scheme: MUTABLE_SCHEME) = false - open fun reloaded() { + /** + * May be called from any thread - EDT is not guaranteed. + */ + open fun reloaded(schemeManager: SchemeManager) { } } diff --git a/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt b/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt index 9e2be48a4ab1..3ce521a69634 100644 --- a/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt +++ b/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt @@ -64,7 +64,7 @@ open class ApplicationRule : ExternalResource() { /** * Project created on request, so, could be used as a bare (only application). */ -class ProjectRule() : ApplicationRule() { +class ProjectRule : ApplicationRule() { companion object { private var sharedProject: ProjectEx? = null private val projectOpened = AtomicBoolean() @@ -242,7 +242,7 @@ fun Project.use(task: (Project) -> Unit) { } } -class DisposeNonLightProjectsRule() : ExternalResource() { +class DisposeNonLightProjectsRule : ExternalResource() { override fun after() { val projectManager = if (ApplicationManager.getApplication().isDisposed) null else ProjectManager.getInstance() as ProjectManagerImpl projectManager?.openProjects?.forEachGuaranteed { diff --git a/platform/util/src/com/intellij/util/ui/JBUI.java b/platform/util/src/com/intellij/util/ui/JBUI.java index d964fd882fcc..df42683a8714 100644 --- a/platform/util/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/src/com/intellij/util/ui/JBUI.java @@ -36,8 +36,6 @@ import java.awt.*; import java.awt.image.ImageObserver; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.util.HashMap; -import java.util.Map; /** * @author Konstantin Bulenkov @@ -458,6 +456,21 @@ public class JBUI { return isHiDPI((GraphicsDevice)null, type); } + /** + * Equivalent of {@link #isHiDPI(Graphics2D, ScaleType)} called for the graphics of specified component. + * + * @see #isHiDPI(Graphics2D, ScaleType) + * @param component if it's null the graphics of the default screen device will be used + */ + public static boolean isHiDPI(@Nullable Component component) { + Graphics graphics = component != null? component.getGraphics() : null; + try { + return isHiDPI((Graphics2D)graphics, ScaleType.USR); + } finally { + if (graphics != null) graphics.dispose(); + } + } + public static class Fonts { public static JBFont label() { return JBFont.create(UIManager.getFont("Label.font"), false); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java index d158ac923315..3d2d0604fbc9 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java @@ -73,6 +73,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import org.jetbrains.plugins.groovy.lang.resolve.processors.GrScopeProcessorWithHints; +import org.jetbrains.plugins.groovy.transformations.impl.GroovyObjectTransformationSupport; import org.jetbrains.plugins.groovy.util.LightCacheKey; import java.util.ArrayList; @@ -336,6 +337,7 @@ public class GrUnresolvedAccessChecker { } private static boolean isNotFromGroovyObject(@NotNull PsiMethod found) { + if (GroovyObjectTransformationSupport.isGroovyObjectSupportMethod(found)) return false; PsiClass aClass = found.getContainingClass(); if (aClass == null) return false; String qname = aClass.getQualifiedName(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index e629466b8242..f4c490fae1cc 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -882,7 +882,7 @@ public class TypesUtil { if (type instanceof PsiClassType) { PsiClass resolved = ((PsiClassType)type).resolve(); if (resolved instanceof PsiAnonymousClass) { - return getQualifiedName(((PsiAnonymousClass)resolved).getBaseClassType()); + return "anonymous " + getQualifiedName(((PsiAnonymousClass)resolved).getBaseClassType()); } if (resolved != null) { return resolved.getQualifiedName(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrAnonymousClassDefinitionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrAnonymousClassDefinitionImpl.java index 274abaab774f..9f32c474e8ae 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrAnonymousClassDefinitionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrAnonymousClassDefinitionImpl.java @@ -29,14 +29,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClassReferenceType; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrTypeDefinitionStub; import org.jetbrains.plugins.groovy.lang.psi.stubs.elements.GrStubElementType; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; /** * @author Maxim.Medvedev @@ -144,11 +140,7 @@ public class GrAnonymousClassDefinitionImpl extends GrTypeDefinitionImpl impleme public PsiClass getSuperClass() { final PsiClass psiClass = getBaseClass(); if (psiClass != null && !psiClass.isInterface()) return psiClass; - return GroovyPsiManager.getInstance(getProject()).findClassWithCache(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT, getResolveScope()); - } - - private PsiClassType createTypeByName(String className) { - return TypesUtil.createTypeByFQClassName(className, this); + return JavaPsiFacade.getInstance(getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, getResolveScope()); } @Override @@ -159,22 +151,7 @@ public class GrAnonymousClassDefinitionImpl extends GrTypeDefinitionImpl impleme @NotNull @Override public PsiClassType[] getExtendsListTypes(boolean includeSynthetic) { - final PsiClass baseClass = getBaseClass(); - - if (baseClass != null) { - if (baseClass.isInterface()) { - return new PsiClassType[]{createTypeByName(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT)}; - } - else { - if (baseClass instanceof GrTypeDefinition) { - return new PsiClassType[]{getBaseClassType()}; - } - else { - return new PsiClassType[]{getBaseClassType(), createTypeByName(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT)}; - } - } - } - return super.getExtendsListTypes(includeSynthetic); + return PsiClassType.EMPTY_ARRAY; } @Override @@ -190,11 +167,21 @@ public class GrAnonymousClassDefinitionImpl extends GrTypeDefinitionImpl impleme @NotNull @Override public PsiClassType[] getImplementsListTypes(boolean includeSynthetic) { - final PsiClass baseClass = getBaseClass(); - if (baseClass != null && baseClass.isInterface()) { - return new PsiClassType[]{getBaseClassType(), createTypeByName(GroovyCommonClassNames.GROOVY_OBJECT)}; + return PsiClassType.EMPTY_ARRAY; + } + + @NotNull + @Override + public PsiClassType[] getSuperTypes(boolean includeSynthetic) { + PsiClassType baseClassType = getBaseClassType(); + PsiClass baseClass = baseClassType.resolve(); + if (baseClass == null || !baseClass.isInterface()) { + return new PsiClassType[]{baseClassType}; + } + else { + PsiClassType objectType = PsiType.getJavaLangObject(getManager(), getResolveScope()); + return new PsiClassType[]{objectType, baseClassType}; } - return new PsiClassType[]{createTypeByName(GroovyCommonClassNames.GROOVY_OBJECT)}; } @Override diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrEnumTypeDefinitionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrEnumTypeDefinitionImpl.java index a26b56261805..13d5f86b9a5a 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrEnumTypeDefinitionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrEnumTypeDefinitionImpl.java @@ -38,7 +38,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEn import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstantList; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrTypeDefinitionStub; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import static com.intellij.psi.CommonClassNames.JAVA_LANG_ENUM; @@ -74,7 +73,7 @@ public class GrEnumTypeDefinitionImpl extends GrTypeDefinitionImpl implements Gr @Override @NotNull public PsiClassType[] getExtendsListTypes(boolean includeSynthetic) { - return new PsiClassType[]{createEnumType(), createGroovyObjectSupportType()}; + return new PsiClassType[]{createEnumType()}; } private PsiClassType createEnumType() { @@ -93,10 +92,6 @@ public class GrEnumTypeDefinitionImpl extends GrTypeDefinitionImpl implements Gr return TypesUtil.createTypeByFQClassName(JAVA_LANG_ENUM, this); } - private PsiClassType createGroovyObjectSupportType() { - return TypesUtil.createTypeByFQClassName(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT, this); - } - @Override @NotNull public GrField[] getFields() { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java index 9e7ad1051074..ee95eaed926a 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java @@ -98,12 +98,10 @@ public class GrTypeDefinitionMembersCache { if (includeSynthetic && TransformationUtilKt.isUnderTransformation(myDefinition)) includeSynthetic = false; return CachedValuesManager.getCachedValue(myDefinition, includeSynthetic ? () -> { PsiClassType[] extendsTypes = getTransformationResult().getExtendsTypes(); - PsiClassType[] result = GrClassImplUtil.getExtendsListTypes(myDefinition, extendsTypes); - return CachedValueProvider.Result.create(result, myDependencies); + return CachedValueProvider.Result.create(extendsTypes, myDependencies); } : () -> { PsiClassType[] extendsTypes = GrClassImplUtil.getReferenceListTypes(myDefinition.getExtendsClause()); - PsiClassType[] result = GrClassImplUtil.getExtendsListTypes(myDefinition, extendsTypes); - return CachedValueProvider.Result.create(result, myDependencies); + return CachedValueProvider.Result.create(extendsTypes, myDependencies); }).clone(); } @@ -112,18 +110,17 @@ public class GrTypeDefinitionMembersCache { if (includeSynthetic && TransformationUtilKt.isUnderTransformation(myDefinition)) includeSynthetic = false; return CachedValuesManager.getCachedValue(myDefinition, includeSynthetic ? () -> { PsiClassType[] implementsTypes = getTransformationResult().getImplementsTypes(); - PsiClassType[] result = GrClassImplUtil.getImplementsListTypes(myDefinition, implementsTypes); - return CachedValueProvider.Result.create(result, myDependencies); + return CachedValueProvider.Result.create(implementsTypes, myDependencies); } : () -> { PsiClassType[] implementsTypes = GrClassImplUtil.getReferenceListTypes(myDefinition.getImplementsClause()); - PsiClassType[] result = GrClassImplUtil.getImplementsListTypes(myDefinition, implementsTypes); - return CachedValueProvider.Result.create(result, myDependencies); + return CachedValueProvider.Result.create(implementsTypes, myDependencies); }).clone(); } @NotNull private TransformationResult getTransformationResult() { - assert !TransformationUtilKt.isUnderTransformation(myDefinition); + boolean underTransformation = TransformationUtilKt.isUnderTransformation(myDefinition); + assert !underTransformation; return CachedValuesManager.getCachedValue(myDefinition, () -> CachedValueProvider.Result.create( TransformationUtilKt.transformDefinition(myDefinition), myDependencies )); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrMethodWrapper.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrMethodWrapper.java index 0fad8509857e..acb931b06b61 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrMethodWrapper.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrMethodWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightTypeParameter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.GrPsiTypeStub; @@ -33,6 +34,7 @@ public class GrMethodWrapper extends GrLightMethodBuilder implements PsiMirrorEl }; private final PsiMethod myWrappedMethod; + private PsiElement myContext; private volatile boolean myNavigationElementInit; protected GrMethodWrapper(PsiMethod method, PsiSubstitutor substitutor) { @@ -55,6 +57,16 @@ public class GrMethodWrapper extends GrLightMethodBuilder implements PsiMirrorEl setReturnType(TYPE_MARKER); } + @Override + public PsiElement getContext() { + if (myContext != null) return myContext; + return super.getContext(); + } + + public void setContext(@Nullable PsiElement context) { + myContext = context; + } + @Override public void setNavigationElement(@NotNull PsiElement navigationElement) { myNavigationElementInit = true; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index a13325a10aec..5be0698908bb 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -51,7 +51,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.GrTypeDefinitionImpl; @@ -67,9 +66,6 @@ import java.util.*; public class GrClassImplUtil { private static final Logger LOG = Logger.getInstance(GrClassImplUtil.class); - private static final Condition IS_GROOVY_OBJECT = - psiClassType -> TypesUtil.isClassType(psiClassType, GroovyCommonClassNames.GROOVY_OBJECT); - private GrClassImplUtil() { } @@ -126,44 +122,6 @@ public class GrClassImplUtil { } } - @NotNull - public static PsiClassType[] getExtendsListTypes(@NotNull GrTypeDefinition grType, @NotNull PsiClassType[] extendsTypes) { - if (grType.isInterface()) { - return extendsTypes; - } - - for (PsiClassType type : extendsTypes) { - final PsiClass superClass = type.resolve(); - if (superClass instanceof GrTypeDefinition && !superClass.isInterface() || - superClass != null && GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT.equals(superClass.getQualifiedName())) { - return extendsTypes; - } - } - - PsiClass grObSupport = GroovyPsiManager.getInstance(grType.getProject()) - .findClassWithCache(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT, grType.getResolveScope()); - if (grObSupport != null) { - final PsiClassType type = JavaPsiFacade.getInstance(grType.getProject()).getElementFactory().createType(grObSupport); - return ArrayUtil.append(extendsTypes, type, PsiClassType.ARRAY_FACTORY); - } - return extendsTypes; - } - - @NotNull - public static PsiClassType[] getImplementsListTypes(@NotNull GrTypeDefinition grType, @NotNull PsiClassType[] implementsTypes) { - final Collection result = ContainerUtil.newLinkedHashSet(); - final PsiClassType[] extendsTypes = getReferenceListTypes(grType.getExtendsClause()); - result.addAll(Arrays.asList(implementsTypes)); - if (!grType.isInterface() && !ContainerUtil.or(implementsTypes, IS_GROOVY_OBJECT) && !ContainerUtil.or(extendsTypes, IS_GROOVY_OBJECT)) { - result.add(getGroovyObjectType(grType)); - } - return result.toArray(new PsiClassType[result.size()]); - } - - public static PsiClassType getGroovyObjectType(@NotNull PsiElement context) { - return TypesUtil.createTypeByFQClassName(GroovyCommonClassNames.GROOVY_OBJECT, context); - } - @NotNull public static PsiClassType[] getSuperTypes(GrTypeDefinition grType, boolean includeSynthetic) { PsiClassType[] extendsList = grType.getExtendsListTypes(includeSynthetic); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/DelegateTransformationSupport.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/DelegateTransformationSupport.java index 55ebadfdd0bc..432ce97d3c35 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/DelegateTransformationSupport.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/DelegateTransformationSupport.java @@ -243,6 +243,8 @@ public class DelegateTransformationSupport implements AstTransformationSupport { ); private static boolean overridesObjectOrGroovyObject(PsiMethod method) { + if (GroovyObjectTransformationSupport.isGroovyObjectSupportMethod(method)) return true; + final String name = method.getName(); if (!OBJECT_METHODS.contains(name) && !GROOVY_OBJECT_METHODS.contains(name)) return false; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/GroovyObjectTransformationSupport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/GroovyObjectTransformationSupport.kt new file mode 100644 index 000000000000..a0d8402410fb --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/transformations/impl/GroovyObjectTransformationSupport.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.groovy.transformations.impl + +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiMethod +import org.jetbrains.plugins.groovy.GroovyLanguage +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierFlags +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrMethodWrapper +import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_OBJECT +import org.jetbrains.plugins.groovy.transformations.AstTransformationSupport +import org.jetbrains.plugins.groovy.transformations.TransformationContext + +class GroovyObjectTransformationSupport : AstTransformationSupport { + + companion object { + private val ORIGIN_INFO = "via GroovyObject" + private val KEY: Key = Key.create("groovy.object.method") + + private fun TransformationContext.findClass(fqn: String) = psiFacade.findClass(fqn, resolveScope) + @JvmStatic fun isGroovyObjectSupportMethod(method: PsiMethod) = method.getUserData(KEY) == true + } + + override fun applyTransformation(context: TransformationContext) { + if (context.codeClass.isInterface) return + if (context.superClass?.language == GroovyLanguage) return + + val groovyObject = context.findClass(GROOVY_OBJECT) + if (groovyObject == null || !GrTraitUtil.isInterface(groovyObject)) return + + context.addInterface(TypesUtil.createType(groovyObject)) + + val implementedMethods = groovyObject.methods.map { + GrMethodWrapper.wrap(it).apply { + setContext(context.codeClass) + modifierList.removeModifier(GrModifierFlags.ABSTRACT_MASK) + originInfo = ORIGIN_INFO + putUserData(KEY, true) + } + } + context.addMethods(implementedMethods) + } +} \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 89c27c800218..1ebe273012ab 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -108,6 +108,8 @@ + @@ -343,6 +345,8 @@ + + + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt index 663707f63b46..7dc107310bd9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt @@ -94,9 +94,7 @@ class LogbackDelegateMemberContributor : NonCodeMembersContributor() { return true } val propertyName = method.name.removePrefix(prefix).decapitalize() - if (name != null) assert(propertyName == name) { - "$propertyName, $name" - } + if (name != null && name != propertyName) return true val parameter = method.parameterList.parameters.singleOrNull() ?: return true val classType = wrapClassType(parameter.type, place) ?: return true diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/AnonymousFromMapGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/AnonymousFromMapGenerator.java index 501dc14f16c2..0f4b86ec3214 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/AnonymousFromMapGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/AnonymousFromMapGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,7 +21,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -117,7 +116,7 @@ public class AnonymousFromMapGenerator { final ExpressionContext extended = context.extend(); extended.setInAnonymousContext(true); if (param == allParameters.length) { - new CodeBlockGenerator(builder, extended).generateCodeBlock((GrCodeBlock)expression, false); + new CodeBlockGenerator(builder, extended).generateCodeBlock(allParameters, closure, false); } else { builder.append("{\n"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java index 00f4aedf8198..2316f6bcaffc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -45,11 +45,15 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.transformations.impl.GroovyObjectTransformationSupport; import java.util.*; +import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_OBJECT; +import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT; + /** * @author Maxim.Medvedev */ @@ -146,7 +150,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator { GenerationUtil.writeThrowsList(builder, method.getThrowsList(), getMethodExceptions(method), classNameProvider); if (!isAbstract) { - /************* body **********/ + /* ************ body ********* */ if (method instanceof GrMethod) { if (method instanceof GrReflectedMethod && ((GrReflectedMethod)method).getSkippedParameters().length > 0) { builder.append("{\n").append(generateDelegateCall((GrReflectedMethod)method)).append("\n}\n"); @@ -184,7 +188,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator { for (GrParameter param : actualParams) { actual.add(param.getName()); } - + StringBuilder builder = new StringBuilder(); if (method.isConstructor()) { builder.append("this"); @@ -337,8 +341,10 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator { @Override public Collection collectMethods(PsiClass typeDefinition) { - List result = new ArrayList<>(Arrays.asList(typeDefinition.getMethods())); - + List result = ContainerUtil.filter( + typeDefinition.getMethods(), + m -> !GroovyObjectTransformationSupport.isGroovyObjectSupportMethod(m) + ); if (typeDefinition instanceof GroovyScriptClass) { final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(context.project); final String name = typeDefinition.getName(); @@ -368,7 +374,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator { Map setters = context.getSetters(); Set> entries = setters.entrySet(); if (ApplicationManager.getApplication().isUnitTestMode()) { - entries = ImmutableSortedSet.copyOf((o1, o2) -> o1.getValue().compareTo(o2.getValue()), entries); + entries = ImmutableSortedSet.copyOf(Comparator.comparing(Map.Entry::getValue), entries); } for (Map.Entry entry : entries) { new SetterWriter(builder, psiClass, entry.getKey(), entry.getValue(), classNameProvider, context).write(); @@ -404,29 +410,31 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator { } private static boolean shouldSkipInImplements(PsiClass typeDefinition, PsiClassType implementsType) { - return implementsType.equalsToText(GroovyCommonClassNames.GROOVY_OBJECT) && - typeDefinition instanceof GrTypeDefinition && - !typeDefinition.isInterface() && - !GenerationSettings.implementGroovyObjectAlways && - !isInList(implementsType, ((GrTypeDefinition)typeDefinition).getImplementsClause()) && - !containsMethodsOf((GrTypeDefinition)typeDefinition, GroovyCommonClassNames.GROOVY_OBJECT); + return implementsType.equalsToText(GROOVY_OBJECT) && + typeDefinition instanceof GrTypeDefinition && + !typeDefinition.isInterface() && + !GenerationSettings.implementGroovyObjectAlways && + !isInList(implementsType, ((GrTypeDefinition)typeDefinition).getImplementsClause()) && + !containsMethodsOf((GrTypeDefinition)typeDefinition, GROOVY_OBJECT); } @Override public void writeExtendsList(StringBuilder text, PsiClass typeDefinition) { final PsiClassType[] extendsClassesTypes = typeDefinition.getExtendsListTypes(); + PsiClassType type = null; if (extendsClassesTypes.length > 0) { - PsiClassType type = extendsClassesTypes[0]; - - if (type.equalsToText(GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT) && - typeDefinition instanceof GrTypeDefinition && - !GenerationSettings.implementGroovyObjectAlways && - !isInList(type, ((GrTypeDefinition)typeDefinition).getExtendsClause()) && - !containsMethodsOf((GrTypeDefinition)typeDefinition, GroovyCommonClassNames.GROOVY_OBJECT)) { - return; + type = extendsClassesTypes[0]; + } + else { + if (typeDefinition instanceof GrTypeDefinition) { + if (GenerationSettings.implementGroovyObjectAlways || containsMethodsOf((GrTypeDefinition)typeDefinition, GROOVY_OBJECT)) { + type = TypesUtil.createType(GROOVY_OBJECT_SUPPORT, typeDefinition); + } } + } + if (type != null) { text.append("extends "); TypeWriter.writeType(text, type, typeDefinition, classNameProvider); text.append(' '); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java index 221246b2e337..d62d1fcc1df2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -94,7 +94,7 @@ public class ClosureGenerator { boolean shouldInsertReturnNull = !(returnType instanceof PsiPrimitiveType) && MissingReturnInspection.methodMissesSomeReturns(block, MissingReturnInspection.ReturnStatus.shouldNotReturnValue); - new CodeBlockGenerator(builder, context.extend(), myExitPoints).generateCodeBlock(block, shouldInsertReturnNull); + new CodeBlockGenerator(builder, context.extend(), myExitPoints).generateCodeBlock(parameters, block, shouldInsertReturnNull); builder.append('\n'); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java index dacd643e8cb9..90c69e04884e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java @@ -55,6 +55,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.transformations.impl.GroovyObjectTransformationSupport; import java.util.Collection; import java.util.Set; @@ -101,7 +102,10 @@ public class CodeBlockGenerator extends Generator { boolean shouldInsertReturnNull; myExitPoints.clear(); PsiType returnType = context.typeProvider.getReturnType(method); - if (!method.isConstructor() && !PsiType.VOID.equals(returnType)) { + if (GroovyObjectTransformationSupport.isGroovyObjectSupportMethod(method)) { + shouldInsertReturnNull = !(returnType instanceof PsiPrimitiveType); + } + else if (!method.isConstructor() && !PsiType.VOID.equals(returnType)) { myExitPoints.addAll(ControlFlowUtils.collectReturns(block)); shouldInsertReturnNull = block != null && !(returnType instanceof PsiPrimitiveType) && @@ -112,9 +116,7 @@ public class CodeBlockGenerator extends Generator { shouldInsertReturnNull = false; } - if (block != null) { - generateCodeBlock(block, shouldInsertReturnNull); - } + generateCodeBlock(method.getParameters(), block, shouldInsertReturnNull); } @Override @@ -124,22 +126,19 @@ public class CodeBlockGenerator extends Generator { @Override public void visitOpenBlock(@NotNull GrOpenBlock block) { - generateCodeBlock(block, false); - } - - public void generateCodeBlock(GrCodeBlock block, boolean shouldInsertReturnNull) { - builder.append("{"); GrParameter[] parameters; if (block.getParent() instanceof GrMethod) { GrMethod method = (GrMethod)block.getParent(); parameters = method.getParameters(); } - else if (block instanceof GrClosableBlock) { - parameters = ((GrClosableBlock)block).getAllParameters(); - } else { parameters = GrParameter.EMPTY_ARRAY; } + generateCodeBlock(parameters, block, false); + } + + public void generateCodeBlock(@NotNull GrParameter[] parameters, @Nullable GrCodeBlock block, boolean shouldInsertReturnNull) { + builder.append("{"); for (GrParameter parameter : parameters) { if (context.analyzedVars.toWrap(parameter)) { @@ -154,9 +153,9 @@ public class CodeBlockGenerator extends Generator { builder.append("}\n"); } - public void visitStatementOwner(GrStatementOwner owner, boolean shouldInsertReturnNull) { + public void visitStatementOwner(@Nullable GrStatementOwner owner, boolean shouldInsertReturnNull) { boolean hasLineFeed = false; - for (PsiElement e = owner.getFirstChild(); e != null; e = e.getNextSibling()) { + for (PsiElement e = owner == null ? null : owner.getFirstChild(); e != null; e = e.getNextSibling()) { if (e instanceof GrStatement) { ((GrStatement)e).accept(this); hasLineFeed = false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/GroovyAutomaticOverloadsRenamerFactory.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/GroovyAutomaticOverloadsRenamerFactory.kt new file mode 100644 index 000000000000..22389f08fa90 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/GroovyAutomaticOverloadsRenamerFactory.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.groovy.refactoring.rename + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.refactoring.rename.naming.AutomaticOverloadsRenamer +import com.intellij.refactoring.rename.naming.AutomaticOverloadsRenamerFactory +import com.intellij.refactoring.rename.naming.AutomaticRenamer +import com.intellij.usageView.UsageInfo +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod + +class GroovyAutomaticOverloadsRenamerFactory : AutomaticOverloadsRenamerFactory() { + + override fun isApplicable(element: PsiElement): Boolean { + if (element !is GrMethod || element.isConstructor) return false + val containingClass = element.containingClass ?: return false + val allSameNameMethods = containingClass.findMethodsByName(element.name, false) + return allSameNameMethods.filter { + it !is GrReflectedMethod || it.baseMethod !== element + }.isNotEmpty() + } + + override fun createRenamer(element: PsiElement?, newName: String?, usages: MutableCollection?): AutomaticRenamer { + return object : AutomaticOverloadsRenamer(element as GrMethod, newName) { + override fun getOverloads(method: PsiMethod): Array { + val containingClass = method.containingClass ?: return PsiMethod.EMPTY_ARRAY + val allSameNameMethods = containingClass.findMethodsByName(method.name, false) + return allSameNameMethods.mapNotNullTo(mutableSetOf()) { + if (it !is GrReflectedMethod) { + it + } + else { + val baseMethod = it.baseMethod + if (baseMethod !== method) baseMethod else null + } + }.toTypedArray() + } + } + } +} \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameGrReflectedMethodProcessor.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameGrReflectedMethodProcessor.kt new file mode 100644 index 000000000000..9bdbdad46344 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameGrReflectedMethodProcessor.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2016 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 org.jetbrains.plugins.groovy.refactoring.rename + +import com.intellij.psi.PsiElement +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod + +class RenameGrReflectedMethodProcessor : RenameAliasImportedMethodProcessor() { + + override fun canProcessElement(element: PsiElement): Boolean { + return element is GrMethod && element.reflectedMethods.isNotEmpty() + } + + override fun isInplaceRenameSupported() = false +} \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy index 93411a9a05d8..6f5ecd60b611 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy @@ -172,6 +172,7 @@ overridden thisProp fromSuper fromSuper2 +metaClass metaPropertyValues properties superProp @@ -181,7 +182,6 @@ getProperty hashCode identity invokeMethod -metaClass notify notifyAll setProperty diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/logback/LogbackTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/logback/LogbackTest.groovy index 666b553886b6..3d642a57f12e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/logback/LogbackTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/logback/LogbackTest.groovy @@ -179,4 +179,25 @@ appender('FOO_APP', ConsoleAppender) assert targetElement.target instanceof AppenderTarget } } + + void 'test no error when class with same name exists'() { + fixture.with { + addClass '''\ +package pckg1; +public class SomeClass {} +''' + addClass ''' +package pckg2; +public class SomeConfigurableClass { + public void setSomeClass(pckg1.SomeClass someClass) {} +}''' + configureByText 'logback.groovy', '''\ +appender('foo', pckg2.SomeConfigurableClass) { + someClass = SomeClass. +} +''' + enableInspections GrUnresolvedAccessInspection + completeBasic() + } + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy index c76a9ca405fd..dc9b47065f5e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy @@ -1605,15 +1605,15 @@ A.foo = 3 //no error void testSOEIfExtendsItself() { testHighlighting('''\ -class A extends A { +class A extends A { def foo } -class B extends C { +class B extends C { def foo } -class C extends B { +class C extends B { } ''') } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GrAliasedImportInheritorsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GrAliasedImportInheritorsTest.groovy index f18562f9b4a7..8ac2aff7564f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GrAliasedImportInheritorsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GrAliasedImportInheritorsTest.groovy @@ -61,7 +61,10 @@ new Roo() {} def inheritors = DirectClassInheritorsSearch.search(iface).findAll() assert inheritors.size() == 4 inheritors.each { - def type = (it as GrTypeDefinition).getImplementsListTypes(false).first() + def type = (it as GrTypeDefinition).getSuperTypes(false).find { + it.resolve() == iface + } + assert type != null def resolveResult = type.resolveGenerics() assert resolveResult.element == iface assert resolveResult.substitutor.substitute(iface.typeParameters.first()) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveCacheTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveCacheTest.groovy index e3911061fc8f..af34f831f9a0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveCacheTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolveCacheTest.groovy @@ -47,7 +47,7 @@ class GroovyResolveCacheTest extends LightGroovyTestCase { def clazz = file.typeDefinitions.first() assert counter == 0 - assert clazz.methods.size() == 1 + assert clazz.methods.size() == 6 assert counter == 1 WriteCommandAction.runWriteCommandAction(project) { @@ -55,7 +55,7 @@ class GroovyResolveCacheTest extends LightGroovyTestCase { } assert counter == 1 - assert clazz.methods.size() == 0 + assert clazz.methods.size() == 5 assert counter == 2 } @@ -70,7 +70,7 @@ class GroovyResolveCacheTest extends LightGroovyTestCase { def clazz = file.typeDefinitions.first() assert counter == 0 - assert clazz.methods.size() == 1 + assert clazz.methods.size() == 6 assert (clazz.methods.first() as GrMethod).block.statements.size() == 1 assert counter == 1 @@ -79,7 +79,7 @@ class GroovyResolveCacheTest extends LightGroovyTestCase { } assert counter == 1 - assert clazz.methods.size() == 1 + assert clazz.methods.size() == 6 assert (clazz.methods.first() as GrMethod).block.statements.size() == 0 assert counter == 1 } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy index d59039014072..fb3ae6884eca 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/RenameTest.groovy @@ -759,4 +759,22 @@ trait T2 extends T { ''') } } + + void 'test rename reflected method with overloads'() { + fixture.with { + configureByText '_.groovy', '''\ +class A { + def foo(a, b, c = 1) {} + def foo(d = 2) {} +} +''' + renameElementAtCaretUsingHandler 'foo1' + checkResult '''\ +class A { + def foo1(a, b, c = 1) {} + def foo1(d = 2) {} +} +''' + } + } } diff --git a/plugins/groovy/testdata/highlighting/CircularInheritance.groovy b/plugins/groovy/testdata/highlighting/CircularInheritance.groovy index d0e3ad217322..02092831586a 100644 --- a/plugins/groovy/testdata/highlighting/CircularInheritance.groovy +++ b/plugins/groovy/testdata/highlighting/CircularInheritance.groovy @@ -1,4 +1,4 @@ -class Foo extends Bar {} -class Bar extends Foo {} +class Foo extends Bar {} +class Bar extends Foo {} println(new Foo()) \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/CyclicInheritance.groovy b/plugins/groovy/testdata/highlighting/CyclicInheritance.groovy index 43f9fc4ea85b..e7d16480ce3d 100644 --- a/plugins/groovy/testdata/highlighting/CyclicInheritance.groovy +++ b/plugins/groovy/testdata/highlighting/CyclicInheritance.groovy @@ -1,15 +1,15 @@ -class A extends C { +class A extends C { } -class B extends A { +class B extends A { } -class C extends B { +class C extends B { } -class D extends B { +class D extends B { } \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/dynamicPropertiesAccess.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/dynamicPropertiesAccess.java index f17a7336bc4b..f18329592fcd 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/dynamicPropertiesAccess.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/dynamicPropertiesAccess.java @@ -10,8 +10,8 @@ org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, getProperty("bar")) org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, s.bar); } -private static Value setProperty0(groovy.lang.GroovyObjectSupport propOwner, java.lang.String property, Value newValue) { -propOwner.setProperty(property, newValue); -return newValue; +private static Value setProperty0(A propOwner, java.lang.String s, Value o) { +propOwner.setProperty(s, o); +return o; } } diff --git a/plugins/settings-repository/src/IcsManager.kt b/plugins/settings-repository/src/IcsManager.kt index 8966318a5a8b..d88a8b02aae0 100644 --- a/plugins/settings-repository/src/IcsManager.kt +++ b/plugins/settings-repository/src/IcsManager.kt @@ -47,7 +47,7 @@ internal const val PLUGIN_NAME = "Settings Repository" internal val LOG = logger() -val icsManager by lazy(LazyThreadSafetyMode.NONE) { +internal val icsManager by lazy(LazyThreadSafetyMode.NONE) { ApplicationLoadListener.EP_NAME.findExtension(IcsApplicationLoadListener::class.java).icsManager } @@ -58,6 +58,7 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: val settings: IcsSettings val repositoryManager: RepositoryManager = GitRepositoryManager(credentialsStore, dir.resolve("repository")) + val readOnlySourcesManager = ReadOnlySourceManager(this, dir) init { settings = try { @@ -69,8 +70,6 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: } } - val readOnlySourcesManager = ReadOnlySourceManager(settings, dir) - val repositoryService: RepositoryService = GitRepositoryService() private val commitAlarm = SingleAlarm(Runnable { @@ -98,7 +97,11 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: } inner class ApplicationLevelProvider : IcsStreamProvider(null) { - override fun delete(fileSpec: String, roamingType: RoamingType) { + override fun delete(fileSpec: String, roamingType: RoamingType): Boolean { + if (!repositoryActive) { + return false + } + if (syncManager.writeAndDeleteProhibited) { throw IllegalStateException("Delete is prohibited now") } @@ -106,6 +109,8 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: if (repositoryManager.delete(toRepositoryPath(fileSpec, roamingType))) { scheduleCommit() } + + return true } } @@ -179,9 +184,9 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: override val enabled: Boolean get() = this@IcsManager.active - override fun isApplicable(fileSpec: String, roamingType: RoamingType): Boolean = enabled + override fun isApplicable(fileSpec: String, roamingType: RoamingType): Boolean = repositoryActive - override fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean) { + override fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean): Boolean { val fullPath = toRepositoryPath(path, roamingType, null) // first of all we must load read-only schemes - scheme could be overridden if bundled or read-only, so, such schemes must be loaded first @@ -189,7 +194,12 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: repository.processChildren(fullPath, filter) { name, input -> processor(name, input, true) } } + if (!repositoryActive) { + return false + } + repositoryManager.processChildren(fullPath, filter) { name, input -> processor(name, input, false) } + return true } override fun write(fileSpec: String, content: ByteArray, size: Int, roamingType: RoamingType) { @@ -206,9 +216,17 @@ class IcsManager @JvmOverloads constructor(dir: Path, val schemeManagerFactory: protected open fun isAutoCommit(fileSpec: String, roamingType: RoamingType) = true - override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> R): R = repositoryManager.read(toRepositoryPath(fileSpec, roamingType, projectId), consumer) + override fun read(fileSpec: String, roamingType: RoamingType, consumer: (InputStream?) -> Unit): Boolean { + if (!repositoryActive) { + return false + } - override fun delete(fileSpec: String, roamingType: RoamingType) { + repositoryManager.read(toRepositoryPath(fileSpec, roamingType, projectId), consumer) + return true + } + + override fun delete(fileSpec: String, roamingType: RoamingType): Boolean { + return false } } } @@ -218,6 +236,10 @@ class IcsApplicationLoadListener : ApplicationLoadListener { private set override fun beforeApplicationLoaded(application: Application, configPath: String) { + if (application.isUnitTestMode) { + return + } + val customPath = System.getProperty("ics.settingsRepository") val pluginSystemDir = if (customPath == null) Paths.get(configPath, "settingsRepository") else Paths.get(FileUtil.expandUserHome(customPath)) icsManager = IcsManager(pluginSystemDir) diff --git a/plugins/settings-repository/src/ReadOnlySourceManager.kt b/plugins/settings-repository/src/ReadOnlySourceManager.kt index f41094f5531c..ac131954bd1b 100644 --- a/plugins/settings-repository/src/ReadOnlySourceManager.kt +++ b/plugins/settings-repository/src/ReadOnlySourceManager.kt @@ -33,14 +33,14 @@ import org.jetbrains.settingsRepository.git.upstream import org.jetbrains.settingsRepository.git.use import java.nio.file.Path -class ReadOnlySourceManager(private val settings: IcsSettings, val rootDir: Path) { +class ReadOnlySourceManager(private val icsManager: IcsManager, val rootDir: Path) { private val repositoryList = object : AtomicClearableLazyValue>() { override fun compute(): List { - if (settings.readOnlySources.isEmpty()) { + if (icsManager.settings.readOnlySources.isEmpty()) { return emptyList() } - return settings.readOnlySources.mapSmartNotNull { source -> + return icsManager.settings.readOnlySources.mapSmartNotNull { source -> LOG.catchAndLog { if (!source.active) { return@mapSmartNotNull null @@ -64,7 +64,7 @@ class ReadOnlySourceManager(private val settings: IcsSettings, val rootDir: Path get() = repositoryList.value fun setSources(sources: List) { - settings.readOnlySources = sources + icsManager.settings.readOnlySources = sources repositoryList.drop() } diff --git a/plugins/settings-repository/src/autoSync.kt b/plugins/settings-repository/src/autoSync.kt index 5373f0ad42b7..1a9829f40bb5 100644 --- a/plugins/settings-repository/src/autoSync.kt +++ b/plugins/settings-repository/src/autoSync.kt @@ -152,7 +152,7 @@ internal class AutoSyncManager(private val icsManager: IcsManager) { if (!onAppExit && !app.isDisposeInProgress && updateResult != null && - updateStoragesFromStreamProvider(app.stateStore as ComponentStoreImpl, updateResult, app.messageBus)) { + updateStoragesFromStreamProvider(icsManager, app.stateStore as ComponentStoreImpl, updateResult, app.messageBus)) { // force to avoid saveAll & confirmation app.exit(true, true, true) } diff --git a/plugins/settings-repository/src/git/pull.kt b/plugins/settings-repository/src/git/pull.kt index 287e28d67c4a..5052063b19f4 100644 --- a/plugins/settings-repository/src/git/pull.kt +++ b/plugins/settings-repository/src/git/pull.kt @@ -164,7 +164,7 @@ open internal class Pull(val manager: GitRepositoryClient, val indicator: Progre if (headId == null) { revWalk.parseHeaders(srcCommit) dirCacheCheckout = DirCacheCheckout(repository, repository.lockDirCache(), srcCommit.tree) - dirCacheCheckout.setFailOnConflict(true) + dirCacheCheckout.setFailOnConflict(false) dirCacheCheckout.checkout() val refUpdate = repository.updateRef(head.target.name) refUpdate.setNewObjectId(objectId) @@ -187,7 +187,7 @@ open internal class Pull(val manager: GitRepositoryClient, val indicator: Progre // FAST_FORWARD detected: skip doing a real merge but only update HEAD refLogMessage.append(": ").append(MergeStatus.FAST_FORWARD) dirCacheCheckout = DirCacheCheckout(repository, headCommit.tree, repository.lockDirCache(), srcCommit.tree) - dirCacheCheckout.setFailOnConflict(true) + dirCacheCheckout.setFailOnConflict(false) dirCacheCheckout.checkout() val mergeStatus: MergeStatus if (squash) { @@ -241,7 +241,7 @@ open internal class Pull(val manager: GitRepositoryClient, val indicator: Progre // ResolveMerger does checkout if (merger !is ResolveMerger) { dirCacheCheckout = DirCacheCheckout(repository, headCommit.tree, repository.lockDirCache(), merger.resultTreeId) - dirCacheCheckout.setFailOnConflict(true) + dirCacheCheckout.setFailOnConflict(false) dirCacheCheckout.checkout() result = ImmutableUpdateResult(dirCacheCheckout.updated.keys, dirCacheCheckout.removed) } diff --git a/plugins/settings-repository/src/git/reset.kt b/plugins/settings-repository/src/git/reset.kt index cb7beeed771d..79d52751a770 100644 --- a/plugins/settings-repository/src/git/reset.kt +++ b/plugins/settings-repository/src/git/reset.kt @@ -18,6 +18,7 @@ package org.jetbrains.settingsRepository.git import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.progress.ProgressIndicator import org.eclipse.jgit.api.MergeResult +import org.eclipse.jgit.lib.RepositoryState import org.eclipse.jgit.merge.MergeStrategy import org.jetbrains.settingsRepository.LOG import org.jetbrains.settingsRepository.MutableUpdateResult @@ -67,6 +68,10 @@ internal class Reset(manager: GitRepositoryManager, indicator: ProgressIndicator return result } + if (repository.repositoryState == RepositoryState.MERGING) { + repository.resetHard() + } + val secondMergeResult = merge(latestUpstreamCommit, mergeStrategy, true, forceMerge = true, commitMessage = commitMessage) if (!secondMergeResult.status.isSuccessful) { throw IllegalStateException(secondMergeResult.toString()) diff --git a/plugins/settings-repository/src/readOnlySourcesEditor.kt b/plugins/settings-repository/src/readOnlySourcesEditor.kt index 8e8c07233e3c..02fe228f2072 100644 --- a/plugins/settings-repository/src/readOnlySourcesEditor.kt +++ b/plugins/settings-repository/src/readOnlySourcesEditor.kt @@ -15,19 +15,20 @@ */ package org.jetbrains.settingsRepository +import com.intellij.openapi.diagnostic.catchAndLog import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.options.ConfigurableUi import com.intellij.openapi.progress.runModalTask import com.intellij.openapi.ui.DialogBuilder import com.intellij.openapi.ui.TextBrowseFolderListener import com.intellij.openapi.ui.TextFieldWithBrowseButton -import com.intellij.openapi.util.text.StringUtil import com.intellij.ui.DocumentAdapter import com.intellij.util.Function import com.intellij.util.containers.ContainerUtil import com.intellij.util.io.delete import com.intellij.util.io.exists import com.intellij.util.text.nullize +import com.intellij.util.text.trimMiddle import com.intellij.util.ui.FormBuilder import com.intellij.util.ui.table.TableModelEditor import gnu.trove.THashSet @@ -117,34 +118,33 @@ internal fun createReadOnlySourcesEditor(): ConfigurableUi { indicator.text = "Deleting old repositories" for (path in toDelete) { indicator.checkCanceled() - try { + LOG.catchAndLog { indicator.text2 = path root.resolve(path).delete() } - catch (e: Exception) { - LOG.error(e) - } } } if (toCheckout.isNotEmpty()) { for (source in toCheckout) { indicator.checkCanceled() - try { - indicator.text = "Cloning ${StringUtil.trimMiddle(source.url!!, 255)}" + LOG.catchAndLog { + indicator.text = "Cloning ${source.url!!.trimMiddle(255)}" val dir = root.resolve(source.path!!) if (dir.exists()) { dir.delete() } cloneBare(source.url!!, dir, icsManager.credentialsStore, indicator.asProgressMonitor()).close() } - catch (e: Exception) { - LOG.error(e) - } } } icsManager.readOnlySourcesManager.setSources(newList) + + // blindly reload all + icsManager.schemeManagerFactory.value.process { + it.reload() + } } } diff --git a/plugins/settings-repository/src/repositoryListEditor.kt b/plugins/settings-repository/src/repositoryListEditor.kt index 1b666bd65c72..2cbab16c2f1e 100644 --- a/plugins/settings-repository/src/repositoryListEditor.kt +++ b/plugins/settings-repository/src/repositoryListEditor.kt @@ -50,17 +50,18 @@ internal fun createRepositoryListEditor(): ConfigurableUi { } return object: ConfigurableUi { + private var noRepositoryRow: Row? = null + private var repositoryRow: Row? = null + override fun isModified(settings: IcsSettings) = editor.isModified override fun getComponent() = panel { - row("Repository:") { - if (editor.model.isEmpty) { - hint("Use File -> Settings Repository... to configure") - } - else { - editor.comboBox() - deleteButton() - } + noRepositoryRow = row("Repository:") { + hint("Use File -> Settings Repository... to configure") + } + repositoryRow = row("Repository:") { + editor.comboBox() + deleteButton() } } @@ -82,6 +83,9 @@ internal fun createRepositoryListEditor(): ConfigurableUi { editor.reset(list) editor.model.selectedItem = upstream + noRepositoryRow!!.visible = list.isEmpty() + repositoryRow!!.visible = list.isNotEmpty() + deleteButton.isEnabled = editor.model.selectedItem != null } } diff --git a/plugins/settings-repository/src/sync.kt b/plugins/settings-repository/src/sync.kt index 224b45dbd3e1..4ae7e3d3d417 100644 --- a/plugins/settings-repository/src/sync.kt +++ b/plugins/settings-repository/src/sync.kt @@ -142,7 +142,7 @@ internal class SyncManager(private val icsManager: IcsManager, private val autoS if (updateResult != null) { val app = ApplicationManager.getApplication() - restartApplication = updateStoragesFromStreamProvider(app.stateStore as ComponentStoreImpl, updateResult!!, app.messageBus, + restartApplication = updateStoragesFromStreamProvider(icsManager, app.stateStore as ComponentStoreImpl, updateResult!!, app.messageBus, reloadAllSchemes = syncType == SyncType.OVERWRITE_LOCAL) } } @@ -158,30 +158,28 @@ internal class SyncManager(private val icsManager: IcsManager, private val autoS } return updateResult != null || isReadOnlySourcesChanged } -} -private fun updateCloudSchemes(indicator: ProgressIndicator): Boolean { - val changedRootDirs = icsManager.readOnlySourcesManager.update(indicator) ?: return false - val schemeManagersToReload = SmartList>() - icsManager.schemeManagerFactory.value.process { - val fileSpec = toRepositoryPath(it.fileSpec, it.roamingType) - if (changedRootDirs.contains(fileSpec)) { - schemeManagersToReload.add(it) + private fun updateCloudSchemes(indicator: ProgressIndicator): Boolean { + val changedRootDirs = icsManager.readOnlySourcesManager.update(indicator) ?: return false + val schemeManagersToReload = SmartList>() + icsManager.schemeManagerFactory.value.process { + val fileSpec = toRepositoryPath(it.fileSpec, it.roamingType) + if (changedRootDirs.contains(fileSpec)) { + schemeManagersToReload.add(it) + } } - } - if (schemeManagersToReload.isNotEmpty()) { - invokeAndWaitIfNeed { + if (schemeManagersToReload.isNotEmpty()) { for (schemeManager in schemeManagersToReload) { schemeManager.reload() } } - } - return schemeManagersToReload.isNotEmpty() + return schemeManagersToReload.isNotEmpty() + } } -internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateResult: UpdateResult, messageBus: MessageBus, reloadAllSchemes: Boolean = false): Boolean { +internal fun updateStoragesFromStreamProvider(icsManager: IcsManager, store: ComponentStoreImpl, updateResult: UpdateResult, messageBus: MessageBus, reloadAllSchemes: Boolean = false): Boolean { val (changed, deleted) = (store.storageManager as StateStorageManagerImpl).getCachedFileStorages(updateResult.changed, updateResult.deleted, ::toIdeaPath) val schemeManagersToReload = SmartList>()