Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2016-12-27 19:51:39 +01:00
91 changed files with 1429 additions and 819 deletions
@@ -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
@@ -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();
@@ -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;
}
@@ -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())) {
@@ -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);
}
}
@@ -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<UsageInfo> usages) {
return new AutomaticOverloadsRenamer((PsiMethod)element, newName);
}
@@ -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() &&
@@ -0,0 +1,4 @@
import a.A;
@SuppressWarnings(A.<error descr="'A_FOO' has protected access in 'a.A'">A_FOO</error>)
class B extends A {}
@@ -1,4 +1,4 @@
@SomeAnnotation(<error descr="'Foo.Bar' has private access in 'Foo'">Foo.Bar</error>.class)
@SomeAnnotation(Foo.<error descr="'Foo.Bar' has private access in 'Foo'">Bar</error>.class)
public class Foo{
private static class Bar {
}
@@ -1,4 +1,4 @@
@SuppressWarnings(<error descr="'ThisClass.FOO' has private access in 'ThisClass'">ThisClass.FOO</error>)
@SuppressWarnings(ThisClass.<error descr="'FOO' has private access in 'ThisClass'">FOO</error>)
public class ThisClass {
private static final String FOO = "foo";
}
@@ -1,4 +1,4 @@
@FooAnnotation(<error descr="'Foo.BAR' has private access in 'Foo'">Foo.BAR</error>)
@FooAnnotation(Foo.<error descr="'BAR' has private access in 'Foo'">BAR</error>)
class Foo {
private static final String BAR = "bar";
}
@@ -0,0 +1,5 @@
interface Test {
<error descr="'foo(A)' clashes with 'foo(B)'; both methods have same erasure">static <A, B> void foo(A a)</error> {}
static <A, B> void foo(B b) {}
}
@@ -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";
@@ -1012,4 +1012,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
public void testBoundsPromotionForDerivedType() throws Exception {
doTest();
}
public void testSameErasureForStaticMethodsInInterfaces() throws Exception {
doTest();
}
}
@@ -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,<caret>};" +
"}");
assertEmpty(myFixture.filterAvailableIntentions("Flip"));
}
}
@@ -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<String> 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<String> getExternalBuildProcessOptions(@NotNull JavaCompilingTool compilingTool) {
return Collections.emptyList();
}
private static final ExtensionsSupport<JavaCompilerToolExtension> ourExtSupport = new ExtensionsSupport<JavaCompilerToolExtension>(JavaCompilerToolExtension.class);
@NotNull
public static Collection<JavaCompilerToolExtension> 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;
}
}
@@ -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);
}
}
@@ -0,0 +1 @@
org.jetbrains.jps.javac.ast.JavacAstCustomDataListener
@@ -0,0 +1 @@
org.jetbrains.jps.javac.ast.ReferenceCollectorExternalJavacOptionsProvider
@@ -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
org.jetbrains.jps.javac.ast.ExternalRefCollectorCompilerToolExtension
org.jetbrains.jps.javac.ast.InProcessRefCollectorCompilerToolExtension
@@ -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);
}
@@ -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<String> getOptions(@NotNull JavaCompilingTool tool);
}
@@ -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;
}
}
}
@@ -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<String> options,
@NotNull DiagnosticOutputConsumer diagnosticConsumer) {
if (isEnabled()) {
JavacReferenceCollector.installOn(task, divideImportsRefs(), getFileDataConsumer(diagnosticConsumer));
}
}
protected abstract boolean isEnabled();
protected abstract boolean divideImportsRefs();
@NotNull
protected abstract Consumer<JavacFileData> getFileDataConsumer(@NotNull DiagnosticOutputConsumer diagnosticConsumer);
}
@@ -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<JavacFileData> getFileDataConsumer(@NotNull final DiagnosticOutputConsumer diagnosticConsumer) {
return new Consumer<JavacFileData>() {
@Override
public void consume(JavacFileData data) {
diagnosticConsumer.customOutputData(ID, "javac-refs", data.asBytes());
}
};
}
}
@@ -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 = 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<JavacFileData> getFileDataConsumer(@NotNull DiagnosticOutputConsumer diagnosticConsumer) {
return createFileDataConsumer();
}
@NotNull
static Consumer<JavacFileData> createFileDataConsumer() {
return new JavacFileDataConsumer();
}
private static class JavacFileDataConsumer implements Consumer<JavacFileData> {
final JavacFileReferencesRegistrar[] myRegistrars;
private JavacFileDataConsumer() {
List<JavacFileReferencesRegistrar> registrars = new ArrayList<JavacFileReferencesRegistrar>();
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());
}
}
}
}
}
@@ -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<JavacFileData> 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));
}
}
@@ -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<Name> myAsterisk = new NotNullLazyValue<Name>() {
@NotNull
@Override
protected Name compute() {
return myElementUtility.getName("*");
}
};
private final Map<String, ReferenceCollector> myIncompletelyProcessedFiles = new THashMap<String, ReferenceCollector>(10);
static void installOn(JavaCompiler.CompilationTask task,
boolean divideImportRefs,
Consumer<JavacFileData> 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) {
@@ -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<List<JavacFileReferencesRegistrar>> myRegistrars = new AtomicClearableLazyValue<List<JavacFileReferencesRegistrar>>() {
@NotNull
@Override
protected List<JavacFileReferencesRegistrar> compute() {
List<JavacFileReferencesRegistrar> result = new ArrayList<JavacFileReferencesRegistrar>();
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<String> options,
@NotNull final DiagnosticOutputConsumer diagnosticConsumer) {
if (isJavac(compilingTool)) {
final String isEnabledProperty = System.getProperty(ENABLED_PARAM);
Consumer<JavacFileData> fileDataConsumer;
boolean divideImportsRefs;
if (isEnabledProperty == null) {
//in-process
final RefCollectorOptions refCollectorOptions = new RefCollectorOptions();
fileDataConsumer = refCollectorOptions.enabled ? new Consumer<JavacFileData>() {
@Override
public void consume(JavacFileData data) {
submitFileData(data);
}
} : null;
divideImportsRefs = refCollectorOptions.divideImportRefs;
} else if (isEnabledProperty.equals("true")) {
//external
fileDataConsumer = new Consumer<JavacFileData>() {
@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<String> getExternalBuildProcessOptions(@NotNull JavaCompilingTool compilingTool) {
List<String> options = new ArrayList<String>(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();
}
}
@@ -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<String> getOptions(@NotNull JavaCompilingTool tool) {
List<String> options = new ArrayList<String>(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;
}
}
}
@@ -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<JavacRef> myRefs;
private final Collection<JavacRef> 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<JavacFileData> EXTERNALIZER = new DataExternalizer<JavacFileData>() {
DataExternalizer<JavacRef> myRefSeqExternalizer = createRefExternalizer();
DataExternalizer<JavacDef> 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<JavacRef> refs) throws IOException {
DataInputOutputUtil.writeSeq(out, refs, new ThrowableConsumer<JavacRef, IOException>() {
@Override
public void consume(JavacRef ref) throws IOException {
myRefSeqExternalizer.save(out, ref);
}
});
}
private Collection<JavacRef> readRefs(final DataInput in) throws IOException {
return DataInputOutputUtil.readSeq(in, new ThrowableComputable<JavacRef, IOException>() {
@Override
public JavacRef compute() throws IOException {
return myRefSeqExternalizer.read(in);
}
});
}
private void saveDefs(final DataOutput out, List<JavacDef> defs) throws IOException {
DataInputOutputUtil.writeSeq(out, defs, new ThrowableConsumer<JavacDef, IOException>() {
@Override
public void consume(JavacDef def) throws IOException {
myDefSeqExternalizer.save(out, def);
}
});
}
private List<JavacDef> readDefs(final DataInput in) throws IOException {
return DataInputOutputUtil.readSeq(in, new ThrowableComputable<JavacDef, IOException>() {
@Override
public JavacDef compute() throws IOException {
return myDefSeqExternalizer.read(in);
}
});
}
};
private static DataExternalizer<JavacDef> createDefExternalizer() {
return new DataExternalizer<JavacDef>() {
private static final byte CLASS_MARKER = 0;
private static final byte FUN_EXPR_MARKER = 1;
DataExternalizer<JavacRef> refExternalizer = createRefExternalizer();
private static void saveRefs(final DataOutput out, Collection<JavacRef> refs) throws IOException {
DataInputOutputUtil.writeSeq(out, refs, new ThrowableConsumer<JavacRef, IOException>() {
@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<JavacRef> createRefExternalizer() {
return new DataExternalizer<JavacRef>() {
private static final byte CLASS_MARKER = 0;
private static final byte METHOD_MARKER = 1;
private static final byte FIELD_MARKER = 2;
private static Collection<JavacRef> readRefs(final DataInput in) throws IOException {
return DataInputOutputUtil.readSeq(in, new ThrowableComputable<JavacRef, IOException>() {
@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<JavacDef> defs) throws IOException {
DataInputOutputUtil.writeSeq(out, defs, new ThrowableConsumer<JavacDef, IOException>() {
@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<JavacDef> readDefs(final DataInput in) throws IOException {
return DataInputOutputUtil.readSeq(in, new ThrowableComputable<JavacDef, IOException>() {
@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<Modifier> modifiers) throws IOException {
DataInputOutputUtil.writeSeq(output, modifiers, new ThrowableConsumer<Modifier, IOException>() {
@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<Modifier> readModifiers(final DataInput input) throws IOException {
return EnumSet.copyOf(DataInputOutputUtil.readSeq(input, new ThrowableComputable<Modifier, IOException>() {
@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<Modifier> modifiers) throws IOException {
DataInputOutputUtil.writeSeq(output, modifiers, new ThrowableConsumer<Modifier, IOException>() {
@Override
public void consume(Modifier modifier) throws IOException {
output.writeUTF(modifier.name());
}
};
});
}
private static Set<Modifier> readModifiers(final DataInput input) throws IOException {
final List<Modifier> modifierList = DataInputOutputUtil.readSeq(input, new ThrowableComputable<Modifier, IOException>() {
@Override
public Modifier compute() throws IOException {
return Modifier.valueOf(input.readUTF());
}
});
return modifierList.isEmpty() ? Collections.<Modifier>emptySet() : EnumSet.copyOf(modifierList);
}
}
@@ -26,6 +26,7 @@ import javax.lang.model.util.Elements;
public class JavacNameTable {
private final SLRUCache<Name, String> myParsedNameCache;
private final Elements myElements;
private Name myAsterisk;
public JavacNameTable(Elements elements) {
myParsedNameCache = new SLRUCache<Name, String>(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;
}
}
@@ -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)
}
@@ -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);
@@ -278,16 +278,15 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(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<T : Scheme, MUTABLE_SCHEME : T>(val fileSpec: String,
loadSchemes()
(processor as? LazySchemeProcessor)?.reloaded()
(processor as? LazySchemeProcessor)?.reloaded(this)
}
private fun removeExternalizableSchemes() {
@@ -717,14 +716,13 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(val fileSpec: String,
}
private fun deleteFiles(errors: MutableList<Throwable>, filesToDelete: MutableSet<String>) {
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)
}
}
}
@@ -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 <R> 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<String, Boolean>,
processor: Function3<String, InputStream, Boolean, Boolean>) {
streamProvider!!.processChildren(path, roamingType, filter, processor)
processor: Function3<String, InputStream, Boolean, Boolean>): 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
@@ -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<String>, deleted: Boolean, streamProvider: Boolean) {
fun updatedFrom(changedComponentNames: MutableSet<String>, 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
@@ -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<RoamingType, MutableMap<String, String>> = THashMap()
@@ -341,13 +342,15 @@ internal class ApplicationStoreTest {
return map
}
override fun <R> 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
}
}
@@ -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()))
}
}
@@ -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(" ")
}
}
@@ -11,17 +11,18 @@ class MockStreamProvider(private val dir: Path) : StreamProvider {
dir.resolve(fileSpec).write(content, 0, size)
}
override fun <R> 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
}
}
@@ -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);
@@ -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);
}
}
}
}
@@ -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;
}
}
@@ -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) {
}
@@ -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;
@@ -31,19 +31,27 @@ public final class IdeInitialConfigButtonUsages {
private static volatile Set<String> ourPredefinedDisabledPlugins = ALL_PLUGINS_SELECTED;
private static volatile Set<String> ourDownloadedPlugins = Collections.emptySet();
private static Set<String> 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<String> getDownloadedPlugins() {
public synchronized static Set<String> getDownloadedPlugins() {
return ourDownloadedPlugins;
}
public static void addDownloadedPlugin(String pluginId) {
public synchronized static void addDownloadedPlugin(String pluginId) {
if (ourDownloadedPlugins.isEmpty()) {
ourDownloadedPlugins = new HashSet<>();
}
@@ -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<EditorColorsScheme> 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());
@@ -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<Keymap>) {
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()
@@ -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)
@@ -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<Componen
}
}
override var visible: Boolean = true
get() = field
set(value) {
if (field == value) {
return
}
field = value
for (c in components) {
c.isVisible = value
}
}
override var subRowsEnabled: Boolean = true
get() = field
set(value) {
@@ -220,6 +234,17 @@ private class MigLayoutRow(private val componentConstraints: MutableMap<Componen
_subRows?.forEach { it.enabled = value }
}
override var subRowsVisible: Boolean = true
get() = field
set(value) {
if (field == value) {
return
}
field = value
_subRows?.forEach { it.visible = value }
}
override operator fun JComponent.invoke(vararg constraints: CCFlags, gapLeft: Int, growPolicy: GrowPolicy?) {
addComponent(this, constraints, gapLeft = gapLeft, growPolicy = growPolicy)
}
@@ -45,8 +45,12 @@ import javax.swing.JLabel
abstract class Row() {
abstract var enabled: Boolean
abstract var visible: Boolean
abstract var subRowsEnabled: Boolean
abstract var subRowsVisible: Boolean
abstract val subRows: List<Row>
protected abstract val builder: LayoutBuilderImpl
@@ -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 <R> 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
@@ -27,24 +27,26 @@ import java.io.InputStream
class SchemeManagerIprProvider(private val subStateTagName: String) : StreamProvider {
private val nameToData = ContainerUtil.newConcurrentMap<String, ByteArray>()
override fun <R> 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) {
@@ -66,7 +66,10 @@ abstract class LazySchemeProcessor<SCHEME : Scheme, MUTABLE_SCHEME : SCHEME>(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<SCHEME>) {
}
}
@@ -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 {
@@ -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 <code>null</code> 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);
@@ -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();
@@ -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();
@@ -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
@@ -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() {
@@ -98,12 +98,10 @@ public class GrTypeDefinitionMembersCache<T extends GrTypeDefinition> {
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<T extends GrTypeDefinition> {
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
));
@@ -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;
@@ -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<PsiClassType> 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<PsiClassType> 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);
@@ -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;
@@ -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<Boolean> = 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)
}
}
+6
View File
@@ -108,6 +108,8 @@
<closureMissingMethodContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.PluginXmlClosureMemberContributor"/>
<astTransformationSupport id="groovyObjectTransformation" order="first"
implementation="org.jetbrains.plugins.groovy.transformations.impl.GroovyObjectTransformationSupport"/>
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.AutoExternalizeContributor"/>
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.transformations.impl.autoClone.AutoCloneTransformationSupport"/>
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.ConstructorAnnotationsProcessor"/>
@@ -343,6 +345,8 @@
<renamePsiElementProcessor id="groovyLightElementRenamer"
implementation="org.jetbrains.plugins.groovy.refactoring.rename.GrLightElementRenamer"
order="first, after groovyPropertyRenameProcessor"/>
<renamePsiElementProcessor implementation="org.jetbrains.plugins.groovy.refactoring.rename.RenameGrReflectedMethodProcessor"
order="first"/>
<renamePsiElementProcessor implementation="org.jetbrains.plugins.groovy.refactoring.rename.RenameAliasImportedClassProcessor"
order="first"/>
<renamePsiElementProcessor implementation="org.jetbrains.plugins.groovy.refactoring.rename.RenameAliasImportedMethodProcessor"
@@ -351,6 +355,8 @@
<renamePsiElementProcessor implementation="org.jetbrains.plugins.groovy.transformations.impl.synch.SynchronizedRenameFieldProcessor"
order="first, before groovyFieldRenameProcessor"/>
<automaticRenamerFactory implementation="org.jetbrains.plugins.groovy.refactoring.rename.GroovyAutomaticOverloadsRenamerFactory"/>
<rename.inplace.resolveSnapshotProvider language="Groovy"
implementationClass="org.jetbrains.plugins.groovy.refactoring.rename.inplace.GroovyResolveSnapshotProvider"/>
@@ -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
@@ -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");
@@ -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<PsiMethod> collectMethods(PsiClass typeDefinition) {
List<PsiMethod> result = new ArrayList<>(Arrays.asList(typeDefinition.getMethods()));
List<PsiMethod> 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<PsiMethod, String> setters = context.getSetters();
Set<Map.Entry<PsiMethod, String>> 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<PsiMethod, String> 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(' ');
@@ -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');
}
@@ -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;
@@ -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<UsageInfo>?): AutomaticRenamer {
return object : AutomaticOverloadsRenamer(element as GrMethod, newName) {
override fun getOverloads(method: PsiMethod): Array<out PsiMethod> {
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()
}
}
}
}
@@ -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
}
@@ -172,6 +172,7 @@ overridden
thisProp
fromSuper
fromSuper2
metaClass
metaPropertyValues
properties
superProp
@@ -181,7 +182,6 @@ getProperty
hashCode
identity
invokeMethod
metaClass
notify
notifyAll
setProperty
@@ -179,4 +179,25 @@ appender('FOO_<caret>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.<caret>
}
'''
enableInspections GrUnresolvedAccessInspection
completeBasic()
}
}
}
@@ -1605,15 +1605,15 @@ A.foo = 3 //no error
void testSOEIfExtendsItself() {
testHighlighting('''\
<error descr="Cyclic inheritance involving 'A'"><error descr="Method 'invokeMethod' is not implemented">class A extends A</error></error> {
<error descr="Cyclic inheritance involving 'A'">class A extends A</error> {
def foo
}
<error descr="Cyclic inheritance involving 'B'"><error descr="Method 'invokeMethod' is not implemented">class B extends C</error></error> {
<error descr="Cyclic inheritance involving 'B'">class B extends C</error> {
def foo
}
<error descr="Cyclic inheritance involving 'C'"><error descr="Method 'invokeMethod' is not implemented">class C extends B</error></error> {
<error descr="Cyclic inheritance involving 'C'">class C extends B</error> {
}
''')
}
@@ -61,7 +61,10 @@ new Roo<Double>() {}
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())
@@ -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
}
@@ -759,4 +759,22 @@ trait T2 extends T {
''')
}
}
void 'test rename reflected method with overloads'() {
fixture.with {
configureByText '_.groovy', '''\
class A {
def fo<caret>o(a, b, c = 1) {}
def foo(d = 2) {}
}
'''
renameElementAtCaretUsingHandler 'foo1'
checkResult '''\
class A {
def foo1(a, b, c = 1) {}
def foo1(d = 2) {}
}
'''
}
}
}
@@ -1,4 +1,4 @@
<error descr="Cyclic inheritance involving 'Foo'"><error descr="Method 'invokeMethod' is not implemented">class Foo extends Bar</error></error> {}
<error descr="Cyclic inheritance involving 'Bar'"><error descr="Method 'invokeMethod' is not implemented">class Bar extends Foo</error></error> {}
<error descr="Cyclic inheritance involving 'Foo'">class Foo extends Bar</error> {}
<error descr="Cyclic inheritance involving 'Bar'">class Bar extends Foo</error> {}
println(new Foo())
@@ -1,15 +1,15 @@
<error descr="Cyclic inheritance involving 'A'"><error descr="Method 'invokeMethod' is not implemented">class A extends C</error></error> {
<error descr="Cyclic inheritance involving 'A'">class A extends C</error> {
}
<error descr="Cyclic inheritance involving 'B'"><error descr="Method 'invokeMethod' is not implemented">class B extends A</error></error> {
<error descr="Cyclic inheritance involving 'B'">class B extends A</error> {
}
<error descr="Cyclic inheritance involving 'C'"><error descr="Method 'invokeMethod' is not implemented">class C extends B</error></error> {
<error descr="Cyclic inheritance involving 'C'">class C extends B</error> {
}
<error descr="Cyclic inheritance involving 'B'"><error descr="Method 'invokeMethod' is not implemented">class D extends B</error></error> {
<error descr="Cyclic inheritance involving 'B'">class D extends B</error> {
}
@@ -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>Value setProperty0(groovy.lang.GroovyObjectSupport propOwner, java.lang.String property, Value newValue) {
propOwner.setProperty(property, newValue);
return newValue;
private static <Value>Value setProperty0(A propOwner, java.lang.String s, Value o) {
propOwner.setProperty(s, o);
return o;
}
}
+30 -8
View File
@@ -47,7 +47,7 @@ internal const val PLUGIN_NAME = "Settings Repository"
internal val LOG = logger<IcsManager>()
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 <R> 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)
@@ -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<List<Repository>>() {
override fun compute(): List<Repository> {
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<ReadonlySource>) {
settings.readOnlySources = sources
icsManager.settings.readOnlySources = sources
repositoryList.drop()
}
+1 -1
View File
@@ -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)
}
+3 -3
View File
@@ -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)
}
@@ -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())
@@ -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<IcsSettings> {
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()
}
}
}
@@ -50,17 +50,18 @@ internal fun createRepositoryListEditor(): ConfigurableUi<IcsSettings> {
}
return object: ConfigurableUi<IcsSettings> {
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<IcsSettings> {
editor.reset(list)
editor.model.selectedItem = upstream
noRepositoryRow!!.visible = list.isEmpty()
repositoryRow!!.visible = list.isNotEmpty()
deleteButton.isEnabled = editor.model.selectedItem != null
}
}
+13 -15
View File
@@ -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<SchemeManagerImpl<*, *>>()
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<SchemeManagerImpl<*, *>>()
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<SchemeManagerImpl<*, *>>()