Cleanup 192 patchset files (KTI-315)
This commit is contained in:
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler;
|
||||
|
||||
import com.intellij.codeInsight.ContainerProvider;
|
||||
import com.intellij.codeInsight.runner.JavaMainMethodProvider;
|
||||
import com.intellij.core.CoreApplicationEnvironment;
|
||||
import com.intellij.core.JavaCoreApplicationEnvironment;
|
||||
import com.intellij.lang.MetaLanguage;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.extensions.ExtensionsArea;
|
||||
import com.intellij.openapi.fileTypes.FileTypeExtensionPoint;
|
||||
import com.intellij.openapi.vfs.VirtualFileSystem;
|
||||
import com.intellij.psi.FileContextProvider;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.augment.TypeAnnotationModifier;
|
||||
import com.intellij.psi.compiled.ClassFileDecompilers;
|
||||
import com.intellij.psi.meta.MetaDataContributor;
|
||||
import com.intellij.psi.stubs.BinaryFileStubBuilders;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
|
||||
|
||||
// Mostly a placeholder for the functionality added to the bunch 193
|
||||
public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
|
||||
|
||||
public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
|
||||
Extensions.cleanRootArea(parentDisposable);
|
||||
registerExtensionPoints();
|
||||
return new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
|
||||
}
|
||||
|
||||
private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
|
||||
super(parentDisposable, unitTestMode);
|
||||
}
|
||||
|
||||
private static void registerExtensionPoints() {
|
||||
ExtensionsArea area = Extensions.getRootArea();
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class);
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider.class);
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor.class);
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider.class);
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier.class);
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage.class);
|
||||
|
||||
IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(area);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected VirtualFileSystem createJrtFileSystem() {
|
||||
return new CoreJrtFileSystem();
|
||||
}
|
||||
}
|
||||
-332
@@ -1,332 +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.kotlin.test.testFramework;
|
||||
|
||||
import com.intellij.core.CoreASTFactory;
|
||||
import com.intellij.lang.*;
|
||||
import com.intellij.lang.impl.PsiBuilderFactoryImpl;
|
||||
import com.intellij.mock.*;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.fileTypes.FileTypeFactory;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.impl.CoreProgressManager;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.pom.PomModel;
|
||||
import com.intellij.pom.core.impl.PomModelImpl;
|
||||
import com.intellij.pom.tree.TreeAspect;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.*;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.testFramework.TestDataFile;
|
||||
import com.intellij.util.CachedValuesManagerImpl;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.messages.MessageBusFactory;
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.picocontainer.ComponentAdapter;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
public abstract class KtParsingTestCase extends KtPlatformLiteFixture {
|
||||
public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
|
||||
protected String myFilePrefix = "";
|
||||
protected String myFileExt;
|
||||
protected final String myFullDataPath;
|
||||
protected PsiFile myFile;
|
||||
private MockPsiManager myPsiManager;
|
||||
private PsiFileFactoryImpl myFileFactory;
|
||||
protected Language myLanguage;
|
||||
private final ParserDefinition[] myDefinitions;
|
||||
private final boolean myLowercaseFirstLetter;
|
||||
|
||||
protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, @NotNull ParserDefinition... definitions) {
|
||||
this(dataPath, fileExt, false, definitions);
|
||||
}
|
||||
|
||||
protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, boolean lowercaseFirstLetter, @NotNull ParserDefinition... definitions) {
|
||||
myDefinitions = definitions;
|
||||
myFullDataPath = getTestDataPath() + "/" + dataPath;
|
||||
myFileExt = fileExt;
|
||||
myLowercaseFirstLetter = lowercaseFirstLetter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
initApplication();
|
||||
ComponentAdapter component = getApplication().getPicoContainer().getComponentAdapter(ProgressManager.class.getName());
|
||||
|
||||
Extensions.registerAreaClass("IDEA_PROJECT", null);
|
||||
myProject = new MockProjectEx(getTestRootDisposable());
|
||||
myPsiManager = new MockPsiManager(myProject);
|
||||
myFileFactory = new PsiFileFactoryImpl(myPsiManager);
|
||||
MutablePicoContainer appContainer = getApplication().getPicoContainer();
|
||||
registerComponentInstance(appContainer, MessageBus.class, MessageBusFactory.newMessageBus(getApplication()));
|
||||
final MockEditorFactory editorFactory = new MockEditorFactory();
|
||||
registerComponentInstance(appContainer, EditorFactory.class, editorFactory);
|
||||
registerComponentInstance(appContainer, FileDocumentManager.class, new MockFileDocumentManagerImpl(new Function<CharSequence, Document>() {
|
||||
@Override
|
||||
public Document fun(CharSequence charSequence) {
|
||||
return editorFactory.createDocument(charSequence);
|
||||
}
|
||||
}, HARD_REF_TO_DOCUMENT_KEY));
|
||||
registerComponentInstance(appContainer, PsiDocumentManager.class, new MockPsiDocumentManager());
|
||||
registerApplicationService(PsiBuilderFactory.class, new PsiBuilderFactoryImpl());
|
||||
registerApplicationService(DefaultASTFactory.class, new CoreASTFactory());
|
||||
|
||||
registerApplicationService(ProgressManager.class, new CoreProgressManager());
|
||||
|
||||
myProject.registerService(CachedValuesManager.class, new CachedValuesManagerImpl(myProject, new PsiCachedValuesFactory(myPsiManager)));
|
||||
myProject.registerService(PsiManager.class, myPsiManager);
|
||||
|
||||
this.registerExtensionPoint(FileTypeFactory.FILE_TYPE_FACTORY_EP, FileTypeFactory.class);
|
||||
registerExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
|
||||
|
||||
for (ParserDefinition definition : myDefinitions) {
|
||||
addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition);
|
||||
}
|
||||
if (myDefinitions.length > 0) {
|
||||
configureFromParserDefinition(myDefinitions[0], myFileExt);
|
||||
}
|
||||
|
||||
// That's for reparse routines
|
||||
final PomModelImpl pomModel = new PomModelImpl(myProject);
|
||||
myProject.registerService(PomModel.class, pomModel);
|
||||
new TreeAspect(pomModel);
|
||||
}
|
||||
|
||||
public void configureFromParserDefinition(ParserDefinition definition, String extension) {
|
||||
myLanguage = definition.getFileNodeType().getLanguage();
|
||||
myFileExt = extension;
|
||||
addExplicitExtension(LanguageParserDefinitions.INSTANCE, this.myLanguage, definition);
|
||||
registerComponentInstance(
|
||||
getApplication().getPicoContainer(), FileTypeManager.class,
|
||||
new MockFileTypeManager(new MockLanguageFileType(myLanguage, myFileExt)));
|
||||
}
|
||||
|
||||
protected <T> void addExplicitExtension(final LanguageExtension<T> instance, final Language language, final T object) {
|
||||
instance.addExplicitExtension(language, object);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
instance.removeExplicitExtension(language, object);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> void registerExtensionPoint(final ExtensionPointName<T> extensionPointName, Class<T> aClass) {
|
||||
super.registerExtensionPoint(extensionPointName, aClass);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
Extensions.getRootArea().unregisterExtensionPoint(extensionPointName.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected <T> void registerApplicationService(final Class<T> aClass, T object) {
|
||||
getApplication().registerService(aClass, object);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
getApplication().getPicoContainer().unregisterComponent(aClass.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MockProjectEx getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public MockPsiManager getPsiManager() {
|
||||
return myPsiManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
myFile = null;
|
||||
myProject = null;
|
||||
myPsiManager = null;
|
||||
}
|
||||
|
||||
protected String getTestDataPath() {
|
||||
return PathManager.getHomePath();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final String getTestName() {
|
||||
return getTestName(myLowercaseFirstLetter);
|
||||
}
|
||||
|
||||
protected boolean includeRanges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean skipSpaces() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean checkAllPsiRoots() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void doTest(boolean checkResult) {
|
||||
String name = getTestName();
|
||||
try {
|
||||
String text = loadFile(name + "." + myFileExt);
|
||||
myFile = createPsiFile(name, text);
|
||||
ensureParsed(myFile);
|
||||
assertEquals("light virtual file text mismatch", text, ((LightVirtualFile)myFile.getVirtualFile()).getContent().toString());
|
||||
assertEquals("virtual file text mismatch", text, LoadTextUtil.loadText(myFile.getVirtualFile()));
|
||||
assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText());
|
||||
assertEquals("psi text mismatch", text, myFile.getText());
|
||||
ensureCorrectReparse(myFile);
|
||||
if (checkResult){
|
||||
checkResult(name, myFile);
|
||||
}
|
||||
else{
|
||||
toParseTreeText(myFile, skipSpaces(), includeRanges());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doTest(String suffix) throws IOException {
|
||||
String name = getTestName();
|
||||
String text = loadFile(name + "." + myFileExt);
|
||||
myFile = createPsiFile(name, text);
|
||||
ensureParsed(myFile);
|
||||
assertEquals(text, myFile.getText());
|
||||
checkResult(name + suffix, myFile);
|
||||
}
|
||||
|
||||
protected void doCodeTest(String code) throws IOException {
|
||||
String name = getTestName();
|
||||
myFile = createPsiFile("a", code);
|
||||
ensureParsed(myFile);
|
||||
assertEquals(code, myFile.getText());
|
||||
checkResult(myFilePrefix + name, myFile);
|
||||
}
|
||||
|
||||
protected PsiFile createPsiFile(String name, String text) {
|
||||
return createFile(name + "." + myFileExt, text);
|
||||
}
|
||||
|
||||
protected PsiFile createFile(@NonNls String name, String text) {
|
||||
LightVirtualFile virtualFile = new LightVirtualFile(name, myLanguage, text);
|
||||
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
|
||||
return createFile(virtualFile);
|
||||
}
|
||||
|
||||
protected PsiFile createFile(LightVirtualFile virtualFile) {
|
||||
return myFileFactory.trySetupPsiForFile(virtualFile, myLanguage, true, false);
|
||||
}
|
||||
|
||||
protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws IOException {
|
||||
doCheckResult(myFullDataPath, file, checkAllPsiRoots(), targetDataName, skipSpaces(), includeRanges());
|
||||
}
|
||||
|
||||
public static void doCheckResult(String testDataDir,
|
||||
PsiFile file,
|
||||
boolean checkAllPsiRoots,
|
||||
String targetDataName,
|
||||
boolean skipSpaces,
|
||||
boolean printRanges) throws IOException {
|
||||
FileViewProvider provider = file.getViewProvider();
|
||||
Set<Language> languages = provider.getLanguages();
|
||||
|
||||
if (!checkAllPsiRoots || languages.size() == 1) {
|
||||
doCheckResult(testDataDir, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim());
|
||||
return;
|
||||
}
|
||||
|
||||
for (Language language : languages) {
|
||||
PsiFile root = provider.getPsi(language);
|
||||
String expectedName = targetDataName + "." + language.getID() + ".txt";
|
||||
doCheckResult(testDataDir, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim());
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkResult(String actual) throws IOException {
|
||||
String name = getTestName();
|
||||
doCheckResult(myFullDataPath, myFilePrefix + name + ".txt", actual);
|
||||
}
|
||||
|
||||
protected void checkResult(@TestDataFile @NonNls String targetDataName, String actual) throws IOException {
|
||||
doCheckResult(myFullDataPath, targetDataName, actual);
|
||||
}
|
||||
|
||||
public static void doCheckResult(String fullPath, String targetDataName, String actual) throws IOException {
|
||||
String expectedFileName = fullPath + File.separatorChar + targetDataName;
|
||||
KtUsefulTestCase.assertSameLinesWithFile(expectedFileName, actual);
|
||||
}
|
||||
|
||||
protected static String toParseTreeText(PsiElement file, boolean skipSpaces, boolean printRanges) {
|
||||
return DebugUtil.psiToString(file, skipSpaces, printRanges);
|
||||
}
|
||||
|
||||
protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
|
||||
return loadFileDefault(myFullDataPath, name);
|
||||
}
|
||||
|
||||
public static String loadFileDefault(String dir, String name) throws IOException {
|
||||
return FileUtil.loadFile(new File(dir, name), CharsetToolkit.UTF8, true).trim();
|
||||
}
|
||||
|
||||
public static void ensureParsed(PsiFile file) {
|
||||
file.accept(new PsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
element.acceptChildren(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void ensureCorrectReparse(@NotNull PsiFile file) {
|
||||
String psiToStringDefault = DebugUtil.psiToString(file, false, false);
|
||||
String fileText = file.getText();
|
||||
DiffLog diffLog = (new BlockSupportImpl(file.getProject())).reparseRange(
|
||||
file, file.getNode(), TextRange.allOf(fileText), fileText, new EmptyProgressIndicator(), fileText);
|
||||
diffLog.performActualPsiChange(file);
|
||||
|
||||
TestCase.assertEquals(psiToStringDefault, DebugUtil.psiToString(file, false, false));
|
||||
}
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.test.testFramework;
|
||||
|
||||
import com.intellij.core.CoreEncodingProjectManager;
|
||||
import com.intellij.mock.MockApplicationEx;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.extensions.ExtensionPoint;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.extensions.ExtensionsArea;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public abstract class KtPlatformLiteFixture extends KtUsefulTestCase {
|
||||
protected MockProjectEx myProject;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Extensions.cleanRootArea(getTestRootDisposable());
|
||||
}
|
||||
|
||||
public static MockApplicationEx getApplication() {
|
||||
return (MockApplicationEx)ApplicationManager.getApplication();
|
||||
}
|
||||
|
||||
public void initApplication() {
|
||||
MockApplicationEx instance = new MockApplicationEx(getTestRootDisposable());
|
||||
ApplicationManager.setApplication(instance, FileTypeManager::getInstance, getTestRootDisposable());
|
||||
getApplication().registerService(EncodingManager.class, CoreEncodingProjectManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
clearFields(this);
|
||||
myProject = null;
|
||||
}
|
||||
|
||||
protected <T> void registerExtensionPoint(ExtensionPointName<T> extensionPointName, Class<T> aClass) {
|
||||
registerExtensionPoint(Extensions.getRootArea(), extensionPointName, aClass);
|
||||
}
|
||||
|
||||
private static <T> void registerExtensionPoint(
|
||||
ExtensionsArea area, ExtensionPointName<T> extensionPointName,
|
||||
Class<? extends T> aClass
|
||||
) {
|
||||
String name = extensionPointName.getName();
|
||||
if (!area.hasExtensionPoint(name)) {
|
||||
ExtensionPoint.Kind kind = aClass.isInterface() || (aClass.getModifiers() & Modifier.ABSTRACT) != 0 ? ExtensionPoint.Kind.INTERFACE : ExtensionPoint.Kind.BEAN_CLASS;
|
||||
area.registerExtensionPoint(name, aClass.getName(), kind);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T registerComponentInstance(MutablePicoContainer container, Class<T> key, T implementation) {
|
||||
Object old = container.getComponentInstance(key);
|
||||
container.unregisterComponent(key);
|
||||
container.registerComponentInstance(key, implementation);
|
||||
return (T)old;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
versions.intellijSdk=192.7142.36
|
||||
versions.androidBuildTools=r23.0.1
|
||||
versions.idea.NodeJS=181.3494.12
|
||||
versions.jar.asm-all=7.0.1
|
||||
versions.jar.guava=25.1-jre
|
||||
versions.jar.groovy-all=2.4.17
|
||||
versions.jar.lombok-ast=0.2.3
|
||||
versions.jar.swingx-core=1.6.2-2
|
||||
versions.jar.kxml2=2.3.0
|
||||
versions.jar.streamex=0.6.8
|
||||
versions.jar.gson=2.8.5
|
||||
versions.jar.oro=2.0.8
|
||||
versions.jar.picocontainer=1.2
|
||||
versions.jar.lz4-java=1.6.0
|
||||
ignore.jar.snappy-in-java=true
|
||||
versions.gradle-api=4.5.1
|
||||
versions.shadow=5.2.0
|
||||
-420
@@ -1,420 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.caches
|
||||
|
||||
import com.intellij.ProjectTopics
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.openapi.roots.ModuleRootEvent
|
||||
import com.intellij.openapi.roots.ModuleRootListener
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener
|
||||
import com.intellij.openapi.vfs.newvfs.events.*
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.impl.PsiManagerEx
|
||||
import com.intellij.psi.impl.PsiTreeChangeEventImpl
|
||||
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.DEBUG_LOG_ENABLE_PerModulePackageCache
|
||||
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.FULL_DROP_THRESHOLD
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfoByVirtualFile
|
||||
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
|
||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||
import org.jetbrains.kotlin.idea.util.getSourceRoot
|
||||
import org.jetbrains.kotlin.idea.util.sourceRoot
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPackageDirective
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
class KotlinPackageContentModificationListener(private val project: Project) : Disposable {
|
||||
val connection = project.messageBus.connect()
|
||||
|
||||
companion object {
|
||||
val LOG = Logger.getInstance(this::class.java)
|
||||
}
|
||||
|
||||
init {
|
||||
connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
|
||||
override fun before(events: MutableList<out VFileEvent>) = onEvents(events, false)
|
||||
override fun after(events: List<VFileEvent>) = onEvents(events, true)
|
||||
|
||||
private fun isRelevant(event: VFileEvent): Boolean = when (event) {
|
||||
is VFilePropertyChangeEvent -> false
|
||||
is VFileCreateEvent -> true
|
||||
is VFileMoveEvent -> true
|
||||
is VFileDeleteEvent -> true
|
||||
is VFileContentChangeEvent -> true
|
||||
is VFileCopyEvent -> true
|
||||
else -> {
|
||||
LOG.warn("Unknown vfs event: ${event.javaClass}")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun onEvents(events: List<VFileEvent>, isAfter: Boolean) {
|
||||
val service = PerModulePackageCacheService.getInstance(project)
|
||||
val fileManager = PsiManagerEx.getInstanceEx(project).fileManager
|
||||
if (events.size >= FULL_DROP_THRESHOLD) {
|
||||
service.onTooComplexChange()
|
||||
} else {
|
||||
events.asSequence()
|
||||
.filter(::isRelevant)
|
||||
.filter {
|
||||
(it.isValid || it !is VFileCreateEvent) && it.file != null
|
||||
}
|
||||
.filter {
|
||||
val vFile = it.file!!
|
||||
vFile.isDirectory || vFile.fileType == KotlinFileType.INSTANCE
|
||||
}
|
||||
.filter {
|
||||
// It expected that content change events will be duplicated with more precise PSI events and processed
|
||||
// in KotlinPackageStatementPsiTreeChangePreprocessor, but events might have been missing if PSI view provider
|
||||
// is absent.
|
||||
if (it is VFileContentChangeEvent) {
|
||||
isAfter && fileManager.findCachedViewProvider(it.file) == null
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
.filter {
|
||||
when (val origin = it.requestor) {
|
||||
is Project -> origin == project
|
||||
is PsiManager -> origin.project == project
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
.forEach { event -> service.notifyPackageChange(event) }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
|
||||
override fun rootsChanged(event: ModuleRootEvent) {
|
||||
PerModulePackageCacheService.getInstance(project).onTooComplexChange()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
connection.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
|
||||
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
||||
val eFile = event.file ?: event.child as? PsiFile
|
||||
if (eFile == null) {
|
||||
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without file" }
|
||||
}
|
||||
val file = eFile as? KtFile ?: return
|
||||
|
||||
when (event.code) {
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
|
||||
val child = event.child ?: run {
|
||||
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without child" }
|
||||
return
|
||||
}
|
||||
if (child.getParentOfType<KtPackageDirective>(false) != null)
|
||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
|
||||
}
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
|
||||
val parent = event.parent ?: run {
|
||||
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without parent" }
|
||||
return
|
||||
}
|
||||
val childrenOfType = parent.getChildrenOfType<KtPackageDirective>()
|
||||
if (
|
||||
(!event.isGenericChange && (childrenOfType.any() || parent is KtPackageDirective)) ||
|
||||
(childrenOfType.any { it.name.isEmpty() } && parent is KtFile)
|
||||
) {
|
||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG = Logger.getInstance(this::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private typealias ImplicitPackageData = MutableMap<FqName, MutableList<VirtualFile>>
|
||||
|
||||
class ImplicitPackagePrefixCache(private val project: Project) {
|
||||
private val implicitPackageCache = ConcurrentHashMap<VirtualFile, ImplicitPackageData>()
|
||||
|
||||
fun getPrefix(sourceRoot: VirtualFile): FqName {
|
||||
val implicitPackageMap = implicitPackageCache.getOrPut(sourceRoot) { analyzeImplicitPackagePrefixes(sourceRoot) }
|
||||
return implicitPackageMap.keys.singleOrNull() ?: FqName.ROOT
|
||||
}
|
||||
|
||||
internal fun clear() {
|
||||
implicitPackageCache.clear()
|
||||
}
|
||||
|
||||
private fun analyzeImplicitPackagePrefixes(sourceRoot: VirtualFile): MutableMap<FqName, MutableList<VirtualFile>> {
|
||||
val result = mutableMapOf<FqName, MutableList<VirtualFile>>()
|
||||
val ktFiles = sourceRoot.children.filter { it.fileType == KotlinFileType.INSTANCE }
|
||||
for (ktFile in ktFiles) {
|
||||
result.addFile(ktFile)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun ImplicitPackageData.addFile(ktFile: VirtualFile) {
|
||||
synchronized(this) {
|
||||
val psiFile = PsiManager.getInstance(project).findFile(ktFile) as? KtFile ?: return
|
||||
addPsiFile(psiFile, ktFile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImplicitPackageData.addPsiFile(
|
||||
psiFile: KtFile,
|
||||
ktFile: VirtualFile
|
||||
) = getOrPut(psiFile.packageFqName) { mutableListOf() }.add(ktFile)
|
||||
|
||||
private fun ImplicitPackageData.removeFile(file: VirtualFile) {
|
||||
synchronized(this) {
|
||||
for ((key, value) in this) {
|
||||
if (value.remove(file)) {
|
||||
if (value.isEmpty()) remove(key)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImplicitPackageData.updateFile(file: KtFile) {
|
||||
synchronized(this) {
|
||||
removeFile(file.virtualFile)
|
||||
addPsiFile(file, file.virtualFile)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun update(event: VFileEvent) {
|
||||
when (event) {
|
||||
is VFileCreateEvent -> checkNewFileInSourceRoot(event.file)
|
||||
is VFileDeleteEvent -> checkDeletedFileInSourceRoot(event.file)
|
||||
is VFileCopyEvent -> {
|
||||
val newParent = event.newParent
|
||||
if (newParent.isValid) {
|
||||
checkNewFileInSourceRoot(newParent.findChild(event.newChildName))
|
||||
}
|
||||
}
|
||||
is VFileMoveEvent -> {
|
||||
checkNewFileInSourceRoot(event.file)
|
||||
if (event.oldParent.getSourceRoot(project) == event.oldParent) {
|
||||
implicitPackageCache[event.oldParent]?.removeFile(event.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNewFileInSourceRoot(file: VirtualFile?) {
|
||||
if (file == null) return
|
||||
if (file.getSourceRoot(project) == file.parent) {
|
||||
implicitPackageCache[file.parent]?.addFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDeletedFileInSourceRoot(file: VirtualFile?) {
|
||||
val directory = file?.parent
|
||||
if (directory == null || !directory.isValid) return
|
||||
if (directory.getSourceRoot(project) == directory) {
|
||||
implicitPackageCache[directory]?.removeFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun update(ktFile: KtFile) {
|
||||
val parent = ktFile.virtualFile?.parent ?: return
|
||||
if (ktFile.sourceRoot == parent) {
|
||||
implicitPackageCache[parent]?.updateFile(ktFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PerModulePackageCacheService(private val project: Project) : Disposable {
|
||||
|
||||
/*
|
||||
* Actually an WeakMap<Module, SoftMap<ModuleSourceInfo, SoftMap<FqName, Boolean>>>
|
||||
*/
|
||||
private val cache = ContainerUtil.createConcurrentWeakMap<Module, ConcurrentMap<ModuleSourceInfo, ConcurrentMap<FqName, Boolean>>>()
|
||||
private val implicitPackagePrefixCache = ImplicitPackagePrefixCache(project)
|
||||
|
||||
private val pendingVFileChanges: MutableSet<VFileEvent> = mutableSetOf()
|
||||
private val pendingKtFileChanges: MutableSet<KtFile> = mutableSetOf()
|
||||
|
||||
private val projectScope = GlobalSearchScope.projectScope(project)
|
||||
|
||||
internal fun onTooComplexChange() {
|
||||
clear()
|
||||
}
|
||||
|
||||
private fun clear() {
|
||||
synchronized(this) {
|
||||
pendingVFileChanges.clear()
|
||||
pendingKtFileChanges.clear()
|
||||
cache.clear()
|
||||
implicitPackagePrefixCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun notifyPackageChange(file: VFileEvent): Unit = synchronized(this) {
|
||||
pendingVFileChanges += file
|
||||
}
|
||||
|
||||
internal fun notifyPackageChange(file: KtFile): Unit = synchronized(this) {
|
||||
pendingKtFileChanges += file
|
||||
}
|
||||
|
||||
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
|
||||
LOG.debugIfEnabled(project) { "Invalidated cache for $moduleSourceInfo" }
|
||||
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
|
||||
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
|
||||
dataForSourceInfo.clear()
|
||||
}
|
||||
|
||||
private fun checkPendingChanges() = synchronized(this) {
|
||||
if (pendingVFileChanges.size + pendingKtFileChanges.size >= FULL_DROP_THRESHOLD) {
|
||||
onTooComplexChange()
|
||||
} else {
|
||||
pendingVFileChanges.processPending { event ->
|
||||
val vfile = event.file ?: return@processPending
|
||||
// When VirtualFile !isValid (deleted for example), it impossible to use getModuleInfoByVirtualFile
|
||||
// For directory we must check both is it in some sourceRoot, and is it contains some sourceRoot
|
||||
if (vfile.isDirectory || !vfile.isValid) {
|
||||
for ((module, data) in cache) {
|
||||
val sourceRootUrls = module.rootManager.sourceRootUrls
|
||||
if (sourceRootUrls.any { url ->
|
||||
vfile.containedInOrContains(url)
|
||||
}) {
|
||||
LOG.debugIfEnabled(project) { "Invalidated cache for $module" }
|
||||
data.clear()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val infoByVirtualFile = getModuleInfoByVirtualFile(project, vfile)
|
||||
if (infoByVirtualFile == null || infoByVirtualFile !is ModuleSourceInfo) {
|
||||
LOG.debugIfEnabled(project) { "Skip $vfile as it has mismatched ModuleInfo=$infoByVirtualFile" }
|
||||
}
|
||||
(infoByVirtualFile as? ModuleSourceInfo)?.let {
|
||||
invalidateCacheForModuleSourceInfo(it)
|
||||
}
|
||||
}
|
||||
|
||||
implicitPackagePrefixCache.update(event)
|
||||
}
|
||||
|
||||
pendingKtFileChanges.processPending { file ->
|
||||
if (file.virtualFile != null && file.virtualFile !in projectScope) {
|
||||
LOG.debugIfEnabled(project) {
|
||||
"Skip $file without vFile, or not in scope: ${file.virtualFile?.let { it !in projectScope }}"
|
||||
}
|
||||
return@processPending
|
||||
}
|
||||
val nullableModuleInfo = file.getNullableModuleInfo()
|
||||
(nullableModuleInfo as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
|
||||
if (nullableModuleInfo == null || nullableModuleInfo !is ModuleSourceInfo) {
|
||||
LOG.debugIfEnabled(project) { "Skip $file as it has mismatched ModuleInfo=$nullableModuleInfo" }
|
||||
}
|
||||
implicitPackagePrefixCache.update(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> MutableCollection<T>.processPending(crossinline body: (T) -> Unit) {
|
||||
this.removeIf { value ->
|
||||
try {
|
||||
body(value)
|
||||
} catch (pce: ProcessCanceledException) {
|
||||
throw pce
|
||||
} catch (exc: Exception) {
|
||||
// Log and proceed. Otherwise pending object processing won't be cleared and exception will be thrown forever.
|
||||
LOG.error(exc)
|
||||
}
|
||||
|
||||
return@removeIf true
|
||||
}
|
||||
}
|
||||
|
||||
private fun VirtualFile.containedInOrContains(root: String) =
|
||||
(VfsUtilCore.isEqualOrAncestor(url, root)
|
||||
|| isDirectory && VfsUtilCore.isEqualOrAncestor(root, url))
|
||||
|
||||
|
||||
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo): Boolean {
|
||||
val module = moduleInfo.module
|
||||
checkPendingChanges()
|
||||
|
||||
val perSourceInfoCache = cache.getOrPut(module) {
|
||||
ContainerUtil.createConcurrentSoftMap()
|
||||
}
|
||||
val cacheForCurrentModuleInfo = perSourceInfoCache.getOrPut(moduleInfo) {
|
||||
ContainerUtil.createConcurrentSoftMap()
|
||||
}
|
||||
|
||||
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
|
||||
val packageExists = PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
|
||||
LOG.debugIfEnabled(project) { "Computed cache value for $packageFqName in $moduleInfo is $packageExists" }
|
||||
packageExists
|
||||
}
|
||||
}
|
||||
|
||||
fun getImplicitPackagePrefix(sourceRoot: VirtualFile): FqName {
|
||||
checkPendingChanges()
|
||||
return implicitPackagePrefixCache.getPrefix(sourceRoot)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FULL_DROP_THRESHOLD = 1000
|
||||
private val LOG = Logger.getInstance(this::class.java)
|
||||
|
||||
fun getInstance(project: Project): PerModulePackageCacheService =
|
||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java)
|
||||
|
||||
var Project.DEBUG_LOG_ENABLE_PerModulePackageCache: Boolean
|
||||
by NotNullableUserDataProperty<Project, Boolean>(Key.create("debug.PerModulePackageCache"), false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Logger.debugIfEnabled(project: Project, withCurrentTrace: Boolean = false, message: () -> String) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode && project.DEBUG_LOG_ENABLE_PerModulePackageCache) {
|
||||
val msg = message()
|
||||
if (withCurrentTrace) {
|
||||
val e = Exception().apply { fillInStackTrace() }
|
||||
this.debug(msg, e)
|
||||
} else {
|
||||
this.debug(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.kotlin.idea.highlighter
|
||||
|
||||
import com.intellij.codeHighlighting.Pass
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPass
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil
|
||||
import com.intellij.lang.annotation.Annotation
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.lang.annotation.HighlightSeverity.*
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.ui.MessageType
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.openapi.wm.ex.StatusBarEx
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
|
||||
import org.jetbrains.kotlin.idea.script.ScriptDiagnosticFixProvider
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
import kotlin.script.experimental.api.SourceCode
|
||||
|
||||
class ScriptExternalHighlightingPass(
|
||||
private val file: KtFile,
|
||||
document: Document
|
||||
) : TextEditorHighlightingPass(file.project, document), DumbAware {
|
||||
override fun doCollectInformation(progress: ProgressIndicator) = Unit
|
||||
|
||||
override fun doApplyInformationToEditor() {
|
||||
val document = document ?: return
|
||||
|
||||
if (!file.isScript()) return
|
||||
|
||||
val reports = IdeScriptReportSink.getReports(file)
|
||||
|
||||
val annotations = reports.mapNotNull { scriptDiagnostic ->
|
||||
val (startOffset, endOffset) = scriptDiagnostic.location?.let { computeOffsets(document, it) } ?: 0 to 0
|
||||
val exception = scriptDiagnostic.exception
|
||||
val exceptionMessage = if (exception != null) " ($exception)" else ""
|
||||
val message = scriptDiagnostic.message + exceptionMessage
|
||||
val annotation = Annotation(
|
||||
startOffset,
|
||||
endOffset,
|
||||
scriptDiagnostic.severity.convertSeverity() ?: return@mapNotNull null,
|
||||
message,
|
||||
message
|
||||
)
|
||||
|
||||
// if range is empty, show notification panel in editor
|
||||
annotation.isFileLevelAnnotation = startOffset == endOffset
|
||||
|
||||
for (provider in ScriptDiagnosticFixProvider.EP_NAME.extensions) {
|
||||
provider.provideFixes(scriptDiagnostic).forEach {
|
||||
annotation.registerFix(it)
|
||||
}
|
||||
}
|
||||
|
||||
annotation
|
||||
}
|
||||
|
||||
val infos = annotations.map { HighlightInfo.fromAnnotation(it) }
|
||||
UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id)
|
||||
}
|
||||
|
||||
private fun computeOffsets(document: Document, position: SourceCode.Location): Pair<Int, Int> {
|
||||
val startLine = position.start.line.coerceLineIn(document)
|
||||
val startOffset = document.offsetBy(startLine, position.start.col)
|
||||
|
||||
val endLine = position.end?.line?.coerceAtLeast(startLine)?.coerceLineIn(document) ?: startLine
|
||||
val endOffset = document.offsetBy(
|
||||
endLine,
|
||||
position.end?.col ?: document.getLineEndOffset(endLine)
|
||||
).coerceAtLeast(startOffset)
|
||||
|
||||
return startOffset to endOffset
|
||||
}
|
||||
|
||||
private fun Int.coerceLineIn(document: Document) = coerceIn(0, document.lineCount - 1)
|
||||
|
||||
private fun Document.offsetBy(line: Int, col: Int): Int {
|
||||
return (getLineStartOffset(line) + col).coerceIn(getLineStartOffset(line), getLineEndOffset(line))
|
||||
}
|
||||
|
||||
private fun ScriptDiagnostic.Severity.convertSeverity(): HighlightSeverity? {
|
||||
return when (this) {
|
||||
ScriptDiagnostic.Severity.FATAL -> ERROR
|
||||
ScriptDiagnostic.Severity.ERROR -> ERROR
|
||||
ScriptDiagnostic.Severity.WARNING -> WARNING
|
||||
ScriptDiagnostic.Severity.INFO -> INFORMATION
|
||||
ScriptDiagnostic.Severity.DEBUG -> if (ApplicationManager.getApplication().isInternal) INFORMATION else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun showNotification(file: KtFile, message: String) {
|
||||
UIUtil.invokeLaterIfNeeded {
|
||||
val ideFrame = WindowManager.getInstance().getIdeFrame(file.project)
|
||||
if (ideFrame != null) {
|
||||
val statusBar = ideFrame.statusBar as StatusBarEx
|
||||
statusBar.notifyProgressByBalloon(
|
||||
MessageType.WARNING,
|
||||
message,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(registrar: TextEditorHighlightingPassRegistrar) : ProjectComponent,
|
||||
TextEditorHighlightingPassFactory {
|
||||
init {
|
||||
registrar.registerTextEditorHighlightingPass(
|
||||
this,
|
||||
TextEditorHighlightingPassRegistrar.Anchor.BEFORE,
|
||||
Pass.UPDATE_FOLDING,
|
||||
false,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
|
||||
if (file !is KtFile) return null
|
||||
return ScriptExternalHighlightingPass(file, editor.document)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.klib
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.BaseComponent
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class KlibLoadingMetadataCache : KlibLoadingMetadataCacheCompat(), BaseComponent {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): KlibLoadingMetadataCache =
|
||||
ApplicationManager.getApplication().getComponent(KlibLoadingMetadataCache::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.kotlin.idea.modules;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.PsiJavaModule;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.impl.light.LightJavaModule;
|
||||
import kotlin.collections.ArraysKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
|
||||
|
||||
// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil
|
||||
public class ModuleHighlightUtil2 {
|
||||
private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release");
|
||||
|
||||
@Nullable
|
||||
static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) {
|
||||
ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
if (index.isInLibrary(file)) {
|
||||
VirtualFile root;
|
||||
if ((root = index.getClassRootForFile(file)) != null) {
|
||||
VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE);
|
||||
if (descriptorFile == null) {
|
||||
VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE);
|
||||
if (alt != null && isMultiReleaseJar(root)) {
|
||||
descriptorFile = alt;
|
||||
}
|
||||
}
|
||||
if (descriptorFile != null) {
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
|
||||
if (psiFile instanceof PsiJavaFile) {
|
||||
return ((PsiJavaFile) psiFile).getModuleDeclaration();
|
||||
}
|
||||
}
|
||||
else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
|
||||
return LightJavaModule.getModule(PsiManager.getInstance(project), root);
|
||||
}
|
||||
}
|
||||
else if ((root = index.getSourceRootForFile(file)) != null) {
|
||||
VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE);
|
||||
if (descriptorFile != null) {
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
|
||||
if (psiFile instanceof PsiJavaFile) {
|
||||
return ((PsiJavaFile) psiFile).getModuleDeclaration();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Module module = index.getModuleForFile(file);
|
||||
if (module != null) {
|
||||
boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file);
|
||||
VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest),
|
||||
root -> root.findChild(MODULE_INFO_FILE) != null);
|
||||
if (modularRoot != null) {
|
||||
VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE);
|
||||
assert moduleInfo != null : modularRoot;
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo);
|
||||
if (psiFile instanceof PsiJavaFile) {
|
||||
return ((PsiJavaFile) psiFile).getModuleDeclaration();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isMultiReleaseJar(VirtualFile root) {
|
||||
if (root.getFileSystem() instanceof JarFileSystem) {
|
||||
VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME);
|
||||
if (manifest != null) {
|
||||
try (InputStream stream = manifest.getInputStream()) {
|
||||
return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE));
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
typealias LookupCancelService = LookupCancelWatcher
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.application.subscribe
|
||||
import com.intellij.codeInsight.completion.CompletionPhaseListener
|
||||
import com.intellij.codeInsight.lookup.Lookup
|
||||
import com.intellij.codeInsight.lookup.LookupEvent
|
||||
import com.intellij.codeInsight.lookup.LookupListener
|
||||
import com.intellij.codeInsight.lookup.LookupManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.editor.event.CaretEvent
|
||||
import com.intellij.openapi.editor.event.CaretListener
|
||||
import com.intellij.openapi.editor.event.EditorFactoryEvent
|
||||
import com.intellij.openapi.editor.event.EditorFactoryListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.idea.statistics.CompletionFUSCollector
|
||||
import org.jetbrains.kotlin.idea.statistics.CompletionFUSCollector.completionStatsData
|
||||
import org.jetbrains.kotlin.idea.statistics.FinishReasonStats
|
||||
|
||||
class LookupCancelWatcher(val project: Project) : ProjectComponent {
|
||||
private class Reminiscence(editor: Editor, offset: Int) {
|
||||
var editor: Editor? = editor
|
||||
private var marker: RangeMarker? = editor.document.createRangeMarker(offset, offset)
|
||||
|
||||
// forget about auto-popup cancellation when the caret is moved to the start or before it
|
||||
private var editorListener: CaretListener? = object : CaretListener {
|
||||
override fun caretPositionChanged(e: CaretEvent) {
|
||||
if (marker != null && (!marker!!.isValid || editor.logicalPositionToOffset(e.newPosition) <= offset)) {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
ApplicationManager.getApplication()!!.assertIsDispatchThread()
|
||||
editor.caretModel.addCaretListener(editorListener!!)
|
||||
}
|
||||
|
||||
fun matches(editor: Editor, offset: Int): Boolean {
|
||||
return editor == this.editor && marker?.startOffset == offset
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
ApplicationManager.getApplication()!!.assertIsDispatchThread()
|
||||
if (marker != null) {
|
||||
editor!!.caretModel.removeCaretListener(editorListener!!)
|
||||
marker = null
|
||||
editor = null
|
||||
editorListener = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var lastReminiscence: Reminiscence? = null
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): LookupCancelWatcher = project.getComponent(LookupCancelWatcher::class.java)!!
|
||||
|
||||
val AUTO_POPUP_AT = Key<Int>("LookupCancelWatcher.AUTO_POPUP_AT")
|
||||
}
|
||||
|
||||
fun wasAutoPopupRecentlyCancelled(editor: Editor, offset: Int): Boolean {
|
||||
return lastReminiscence?.matches(editor, offset) ?: false
|
||||
}
|
||||
|
||||
private val lookupCancelListener = object : LookupListener {
|
||||
override fun lookupCanceled(event: LookupEvent) {
|
||||
val lookup = event.lookup
|
||||
if (event.isCanceledExplicitly && lookup.isCompletion) {
|
||||
val offset = lookup.currentItem?.getUserData(AUTO_POPUP_AT)
|
||||
if (offset != null) {
|
||||
lastReminiscence?.dispose()
|
||||
if (offset <= lookup.editor.document.textLength) {
|
||||
lastReminiscence = Reminiscence(lookup.editor, offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initComponent() {
|
||||
CompletionPhaseListener.TOPIC.subscribe(project, CompletionPhaseListener { isCompletionRunning ->
|
||||
if (isCompletionRunning) {
|
||||
if (completionStatsData != null) {
|
||||
completionStatsData = completionStatsData?.copy(finishReason = FinishReasonStats.INTERRUPTED)
|
||||
CompletionFUSCollector.log(completionStatsData)
|
||||
completionStatsData = null
|
||||
}
|
||||
completionStatsData = CompletionFUSCollector.CompletionStatsData(System.currentTimeMillis())
|
||||
}
|
||||
|
||||
if (!isCompletionRunning) {
|
||||
completionStatsData = completionStatsData?.copy(finishTime = System.currentTimeMillis())
|
||||
}
|
||||
})
|
||||
|
||||
EditorFactory.getInstance().addEditorFactoryListener(
|
||||
object : EditorFactoryListener {
|
||||
override fun editorReleased(event: EditorFactoryEvent) {
|
||||
if (lastReminiscence?.editor == event.editor) {
|
||||
lastReminiscence!!.dispose()
|
||||
}
|
||||
}
|
||||
},
|
||||
project
|
||||
)
|
||||
|
||||
LookupManager.getInstance(project).addPropertyChangeListener { event ->
|
||||
if (event.propertyName == LookupManager.PROP_ACTIVE_LOOKUP) {
|
||||
val lookup = event.newValue as Lookup?
|
||||
lookup?.addLookupListener(lookupCancelListener)
|
||||
lookup?.addLookupListener(object : LookupListener {
|
||||
override fun lookupShown(event: LookupEvent) {
|
||||
completionStatsData = completionStatsData?.copy(shownTime = System.currentTimeMillis())
|
||||
}
|
||||
|
||||
override fun lookupCanceled(event: LookupEvent) {
|
||||
completionStatsData = completionStatsData?.copy(
|
||||
finishReason = if (event.isCanceledExplicitly) FinishReasonStats.CANCELLED else FinishReasonStats.HIDDEN
|
||||
)
|
||||
CompletionFUSCollector.log(completionStatsData)
|
||||
completionStatsData = null
|
||||
}
|
||||
|
||||
override fun itemSelected(event: LookupEvent) {
|
||||
val eventLookup = event.lookup
|
||||
val lookupIndex = eventLookup.items.indexOf(eventLookup.currentItem)
|
||||
if (lookupIndex >= 0) completionStatsData = completionStatsData?.copy(selectedItem = lookupIndex)
|
||||
|
||||
completionStatsData = completionStatsData?.copy(finishReason = FinishReasonStats.DONE)
|
||||
CompletionFUSCollector.log(completionStatsData)
|
||||
completionStatsData = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
public class Testing {
|
||||
public static void test() {
|
||||
DefaultImpl<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "DefaultImpls", tailText: " (defaultImpls.NonAbstractFun)" }
|
||||
// EXIST: { lookupString: "DefaultImpls", tailText: " (defaultImpls.NonAbstractFunWithExpressionBody)" }
|
||||
// EXIST: { lookupString: "DefaultImpls", tailText: " (defaultImpls.NonAbstractProperty)" }
|
||||
// EXIST: { lookupString: "DefaultImpls", tailText: " (defaultImpls.NonAbstractPropertyWithBody)" }
|
||||
// ABSENT: { lookupString: "DefaultImpls", tailText: " (defaultImpls.AllAbstract)" }
|
||||
@@ -1,9 +0,0 @@
|
||||
public class Testing {
|
||||
public static void test() {
|
||||
List<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: EmptyList
|
||||
// EXIST: { lookupString:List,tailText:"<E> (java.util)" }
|
||||
// ABSENT: { lookupString:List,tailText:"<E> (kotlin.collections)" }
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.test
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractKotlinSourceInJavaCompletionTest : KotlinFixtureCompletionBaseTestCase() {
|
||||
override fun getPlatform() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
|
||||
override fun doTest(testPath: String) {
|
||||
val mockPath = RELATIVE_COMPLETION_TEST_DATA_BASE_PATH + "/injava/mockLib"
|
||||
val mockLibDir = File(mockPath)
|
||||
fun collectPaths(dir: File): List<String> {
|
||||
return dir.listFiles()!!.flatMap {
|
||||
if (it.isDirectory) {
|
||||
collectPaths(it)
|
||||
} else listOf(FileUtil.toSystemIndependentName(it.path))
|
||||
}
|
||||
}
|
||||
|
||||
val paths = collectPaths(mockLibDir).toTypedArray()
|
||||
paths.forEach { path ->
|
||||
val vFile = myFixture.copyFileToProject(path, path.substring(mockPath.length))
|
||||
myFixture.configureFromExistingVirtualFile(vFile)
|
||||
}
|
||||
|
||||
LightClassComputationControl.testWithControl(project, FileUtil.loadFile(File(testPath))) {
|
||||
super.doTest(testPath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
||||
override fun defaultCompletionType() = CompletionType.BASIC
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.highlighter
|
||||
|
||||
import com.intellij.codeHighlighting.Pass
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPass
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar
|
||||
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil
|
||||
import com.intellij.lang.annotation.AnnotationSession
|
||||
import com.intellij.lang.annotation.AnnotationHolder
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
class KotlinBeforeResolveHighlightingPass(
|
||||
private val file: KtFile,
|
||||
document: Document
|
||||
) : TextEditorHighlightingPass(file.project, document), DumbAware {
|
||||
|
||||
@Volatile
|
||||
private var annotationHolder: AnnotationHolderImpl? = null
|
||||
|
||||
override fun doCollectInformation(progress: ProgressIndicator) {
|
||||
val annotationHolder = AnnotationHolderImpl(AnnotationSession(file))
|
||||
val visitor = BeforeResolveHighlightingVisitor(annotationHolder)
|
||||
val extensions = EP_NAME.extensionList.map { it.createVisitor(annotationHolder) }
|
||||
file.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
super.visitElement(element)
|
||||
element.accept(visitor)
|
||||
extensions.forEach(element::accept)
|
||||
}
|
||||
})
|
||||
this.annotationHolder = annotationHolder
|
||||
}
|
||||
|
||||
override fun doApplyInformationToEditor() {
|
||||
if (annotationHolder == null) return
|
||||
|
||||
val infos = annotationHolder!!.map { HighlightInfo.fromAnnotation(it) }
|
||||
|
||||
UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id)
|
||||
annotationHolder = null
|
||||
}
|
||||
|
||||
class Factory(registrar: TextEditorHighlightingPassRegistrar) : ProjectComponent, TextEditorHighlightingPassFactory {
|
||||
init {
|
||||
registrar.registerTextEditorHighlightingPass(
|
||||
this,
|
||||
TextEditorHighlightingPassRegistrar.Anchor.BEFORE,
|
||||
Pass.UPDATE_FOLDING,
|
||||
false,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
|
||||
if (file !is KtFile) return null
|
||||
return KotlinBeforeResolveHighlightingPass(file, editor.document)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EP_NAME = ExtensionPointName.create<BeforeResolveHighlightingExtension>("org.jetbrains.kotlin.beforeResolveHighlightingVisitor")
|
||||
}
|
||||
}
|
||||
|
||||
interface BeforeResolveHighlightingExtension {
|
||||
fun createVisitor(holder: AnnotationHolder): HighlightingVisitor
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util.application
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
fun <T> runReadAction(action: () -> T): T {
|
||||
return ApplicationManager.getApplication().runReadAction<T>(action)
|
||||
}
|
||||
|
||||
fun <T> runWriteAction(action: () -> T): T {
|
||||
return ApplicationManager.getApplication().runWriteAction<T>(action)
|
||||
}
|
||||
|
||||
fun Project.executeWriteCommand(name: String, command: () -> Unit) {
|
||||
CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
|
||||
}
|
||||
|
||||
fun <T> Project.executeWriteCommand(name: String, groupId: Any? = null, command: () -> T): T {
|
||||
return executeCommand<T>(name, groupId) { runWriteAction(command) }
|
||||
}
|
||||
|
||||
fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -> T): T {
|
||||
@Suppress("UNCHECKED_CAST") var result: T = null as T
|
||||
CommandProcessor.getInstance().executeCommand(this, { result = command() }, name, groupId)
|
||||
@Suppress("USELESS_CAST")
|
||||
return result as T
|
||||
}
|
||||
|
||||
fun <T> runWithCancellationCheck(block: () -> T): T = block()
|
||||
|
||||
inline fun executeOnPooledThread(crossinline action: () -> Unit) =
|
||||
ApplicationManager.getApplication().executeOnPooledThread { action() }
|
||||
|
||||
inline fun invokeLater(crossinline action: () -> Unit) =
|
||||
ApplicationManager.getApplication().invokeLater { action() }
|
||||
|
||||
inline fun isUnitTestMode(): Boolean = ApplicationManager.getApplication().isUnitTestMode
|
||||
|
||||
inline fun <reified T : Any> Project.getServiceSafe(): T =
|
||||
ServiceManager.getService(this, T::class.java) ?: error("Unable to locate service ${T::class.java.name}")
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.git
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Couple
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vcs.FilePath
|
||||
import git4idea.checkin.GitCheckinExplicitMovementProvider
|
||||
import org.jetbrains.kotlin.idea.actions.pathBeforeJ2K
|
||||
import org.jetbrains.kotlin.idea.git.KotlinGitBundle
|
||||
import java.util.*
|
||||
|
||||
class KotlinExplicitMovementProvider : GitCheckinExplicitMovementProvider() {
|
||||
init {
|
||||
Registry.get("git.explicit.commit.renames.prohibit.multiple.calls").setValue(false)
|
||||
}
|
||||
|
||||
override fun isEnabled(project: Project): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getDescription(): String {
|
||||
return KotlinGitBundle.message("j2k.extra.commit.description")
|
||||
}
|
||||
|
||||
override fun getCommitMessage(oldCommitMessage: String): String {
|
||||
return KotlinGitBundle.message("j2k.extra.commit.commit.message")
|
||||
}
|
||||
|
||||
override fun collectExplicitMovements(
|
||||
project: Project,
|
||||
beforePaths: List<FilePath>,
|
||||
afterPaths: List<FilePath>
|
||||
): Collection<Movement> {
|
||||
val movedChanges = ArrayList<Movement>()
|
||||
for (after in afterPaths) {
|
||||
val pathBeforeJ2K = after.virtualFile?.pathBeforeJ2K
|
||||
if (pathBeforeJ2K != null) {
|
||||
val before = beforePaths.firstOrNull { it.path == pathBeforeJ2K }
|
||||
if (before != null) {
|
||||
movedChanges.add(Movement(before, after))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return movedChanges
|
||||
}
|
||||
|
||||
override fun afterMovementsCommitted(project: Project, movedPaths: MutableList<Couple<FilePath>>) {
|
||||
movedPaths.forEach { it.second.virtualFile?.pathBeforeJ2K = null }
|
||||
}
|
||||
}
|
||||
-227
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ide.konan
|
||||
|
||||
import com.intellij.ProjectTopics
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.*
|
||||
import com.intellij.openapi.application.ReadAction.nonBlocking
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.roots.ModuleRootEvent
|
||||
import com.intellij.openapi.roots.ModuleRootListener
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.util.PathUtilRt
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
import org.jetbrains.concurrency.CancellablePromise
|
||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfosFromIdeaModel
|
||||
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.isGradleLibraryName
|
||||
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.parseIDELibraryName
|
||||
import org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider
|
||||
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||
import org.jetbrains.kotlin.idea.klib.KlibCompatibilityInfo.IncompatibleMetadata
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
/** TODO: merge [KotlinNativeABICompatibilityChecker] in the future with [UnsupportedAbiVersionNotificationPanelProvider], KT-34525 */
|
||||
class KotlinNativeABICompatibilityChecker(private val project: Project) : ProjectComponent, Disposable {
|
||||
|
||||
private sealed class LibraryGroup(private val ordinal: Int) : Comparable<LibraryGroup> {
|
||||
|
||||
override fun compareTo(other: LibraryGroup) = when {
|
||||
this == other -> 0
|
||||
this is FromDistribution && other is FromDistribution -> kotlinVersion.compareTo(other.kotlinVersion)
|
||||
else -> ordinal.compareTo(other.ordinal)
|
||||
}
|
||||
|
||||
data class FromDistribution(val kotlinVersion: String) : LibraryGroup(0)
|
||||
object ThirdParty : LibraryGroup(1)
|
||||
object User : LibraryGroup(2)
|
||||
}
|
||||
|
||||
private val cachedIncompatibleLibraries = HashSet<String>()
|
||||
|
||||
@Volatile
|
||||
private var backgroundJob: CancellablePromise<*>? = null
|
||||
|
||||
init {
|
||||
project.messageBus.connect().subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
|
||||
override fun rootsChanged(event: ModuleRootEvent) {
|
||||
// run when project roots are changes, e.g. on project import
|
||||
validateKotlinNativeLibraries()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun projectOpened() {
|
||||
// run when project is opened
|
||||
validateKotlinNativeLibraries()
|
||||
}
|
||||
|
||||
private fun validateKotlinNativeLibraries() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode || project.isDisposed)
|
||||
return
|
||||
|
||||
backgroundJob = nonBlocking<List<Notification>> {
|
||||
val librariesToNotify = getLibrariesToNotifyAbout()
|
||||
prepareNotifications(librariesToNotify)
|
||||
}
|
||||
.finishOnUiThread(ModalityState.defaultModalityState()) { notifications ->
|
||||
notifications.forEach {
|
||||
it.notify(project)
|
||||
}
|
||||
}
|
||||
.expireWith(project) // cancel job when project is disposed
|
||||
.withDocumentsCommitted(project)
|
||||
.submit(AppExecutorUtil.getAppExecutorService())
|
||||
.also {
|
||||
it.onProcessed {
|
||||
backgroundJob = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLibrariesToNotifyAbout(): Map<String, NativeKlibLibraryInfo> {
|
||||
val incompatibleLibraries = getModuleInfosFromIdeaModel(project)
|
||||
.filterIsInstance<NativeKlibLibraryInfo>()
|
||||
.filter { !it.compatibilityInfo.isCompatible }
|
||||
.associateBy { it.libraryRoot }
|
||||
|
||||
val newEntries = if (cachedIncompatibleLibraries.isNotEmpty())
|
||||
incompatibleLibraries.filterKeys { it !in cachedIncompatibleLibraries }
|
||||
else
|
||||
incompatibleLibraries
|
||||
|
||||
cachedIncompatibleLibraries.clear()
|
||||
cachedIncompatibleLibraries.addAll(incompatibleLibraries.keys)
|
||||
|
||||
return newEntries
|
||||
}
|
||||
|
||||
private fun prepareNotifications(librariesToNotify: Map<String, NativeKlibLibraryInfo>): List<Notification> {
|
||||
if (librariesToNotify.isEmpty())
|
||||
return emptyList()
|
||||
|
||||
val librariesByGroups = HashMap<Pair<LibraryGroup, Boolean>, MutableList<Pair<String, String>>>()
|
||||
librariesToNotify.forEach { (libraryRoot, libraryInfo) ->
|
||||
val isOldMetadata = (libraryInfo.compatibilityInfo as? IncompatibleMetadata)?.isOlder ?: true
|
||||
val (libraryName, libraryGroup) = parseIDELibraryName(libraryInfo)
|
||||
librariesByGroups.computeIfAbsent(libraryGroup to isOldMetadata) { mutableListOf() } += libraryName to libraryRoot
|
||||
}
|
||||
|
||||
return librariesByGroups.keys.sortedWith(
|
||||
compareBy(
|
||||
{ (libraryGroup, _) -> libraryGroup },
|
||||
{ (_, isOldMetadata) -> isOldMetadata }
|
||||
)
|
||||
).map { key ->
|
||||
|
||||
val (libraryGroup, isOldMetadata) = key
|
||||
val libraries =
|
||||
librariesByGroups.getValue(key).sortedWith(compareBy(LIBRARY_NAME_COMPARATOR) { (libraryName, _) -> libraryName })
|
||||
|
||||
|
||||
val message = when (libraryGroup) {
|
||||
is LibraryGroup.FromDistribution -> {
|
||||
val libraryNamesInOneLine = libraries
|
||||
.joinToString(limit = MAX_LIBRARY_NAMES_IN_ONE_LINE) { (libraryName, _) -> libraryName }
|
||||
val text = KotlinGradleNativeBundle.message(
|
||||
"error.incompatible.libraries",
|
||||
libraries.size, libraryGroup.kotlinVersion, libraryNamesInOneLine
|
||||
)
|
||||
val explanation = when (isOldMetadata) {
|
||||
true -> KotlinGradleNativeBundle.message("error.incompatible.libraries.older")
|
||||
false -> KotlinGradleNativeBundle.message("error.incompatible.libraries.newer")
|
||||
}
|
||||
val recipe = KotlinGradleNativeBundle.message("error.incompatible.libraries.recipe", bundledRuntimeVersion())
|
||||
"$text\n\n$explanation\n$recipe"
|
||||
}
|
||||
is LibraryGroup.ThirdParty -> {
|
||||
val text = when (isOldMetadata) {
|
||||
true -> KotlinGradleNativeBundle.message("error.incompatible.3p.libraries.older", libraries.size)
|
||||
false -> KotlinGradleNativeBundle.message("error.incompatible.3p.libraries.newer", libraries.size)
|
||||
}
|
||||
val librariesLineByLine = libraries.joinToString(separator = "\n") { (libraryName, _) -> libraryName }
|
||||
val recipe = KotlinGradleNativeBundle.message("error.incompatible.3p.libraries.recipe", bundledRuntimeVersion())
|
||||
"$text\n$librariesLineByLine\n\n$recipe"
|
||||
}
|
||||
is LibraryGroup.User -> {
|
||||
val projectRoot = project.guessProjectDir()?.canonicalPath
|
||||
|
||||
fun getLibraryTextToPrint(libraryNameAndRoot: Pair<String, String>): String {
|
||||
val (libraryName, libraryRoot) = libraryNameAndRoot
|
||||
|
||||
val relativeRoot = projectRoot?.let {
|
||||
libraryRoot.substringAfter(projectRoot)
|
||||
.takeIf { it != libraryRoot }
|
||||
?.trimStart('/', '\\')
|
||||
?.let { "${'$'}project/$it" }
|
||||
} ?: libraryRoot
|
||||
|
||||
return KotlinGradleNativeBundle.message("library.name.0.at.1.relative.root", libraryName, relativeRoot)
|
||||
}
|
||||
|
||||
val text = when (isOldMetadata) {
|
||||
true -> KotlinGradleNativeBundle.message("error.incompatible.user.libraries.older", libraries.size)
|
||||
false -> KotlinGradleNativeBundle.message("error.incompatible.user.libraries.newer", libraries.size)
|
||||
}
|
||||
val librariesLineByLine = libraries.joinToString(separator = "\n", transform = ::getLibraryTextToPrint)
|
||||
val recipe = KotlinGradleNativeBundle.message("error.incompatible.user.libraries.recipe", bundledRuntimeVersion())
|
||||
"$text\n$librariesLineByLine\n\n$recipe"
|
||||
}
|
||||
}
|
||||
|
||||
Notification(
|
||||
NOTIFICATION_GROUP_ID,
|
||||
NOTIFICATION_TITLE,
|
||||
StringUtilRt.convertLineSeparators(message, "<br/>"),
|
||||
NotificationType.ERROR,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// returns pair of library name and library group
|
||||
private fun parseIDELibraryName(libraryInfo: NativeKlibLibraryInfo): Pair<String, LibraryGroup> {
|
||||
val ideLibraryName = libraryInfo.library.name?.takeIf(String::isNotEmpty)
|
||||
if (ideLibraryName != null) {
|
||||
parseIDELibraryName(ideLibraryName)?.let { (kotlinVersion, libraryName) ->
|
||||
return libraryName to LibraryGroup.FromDistribution(kotlinVersion)
|
||||
}
|
||||
|
||||
if (isGradleLibraryName(ideLibraryName))
|
||||
return ideLibraryName to LibraryGroup.ThirdParty
|
||||
}
|
||||
|
||||
return (ideLibraryName ?: PathUtilRt.getFileName(libraryInfo.libraryRoot)) to LibraryGroup.User
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
backgroundJob?.let(CancellablePromise<*>::cancel)
|
||||
backgroundJob = null
|
||||
|
||||
cachedIncompatibleLibraries.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LIBRARY_NAME_COMPARATOR = Comparator<String> { libraryName1, libraryName2 ->
|
||||
when {
|
||||
libraryName1 == libraryName2 -> 0
|
||||
libraryName1 == KONAN_STDLIB_NAME -> -1 // stdlib must go the first
|
||||
libraryName2 == KONAN_STDLIB_NAME -> 1
|
||||
else -> libraryName1.compareTo(libraryName2)
|
||||
}
|
||||
}
|
||||
|
||||
private const val MAX_LIBRARY_NAMES_IN_ONE_LINE = 5
|
||||
|
||||
private val NOTIFICATION_TITLE get() = KotlinGradleNativeBundle.message("error.incompatible.libraries.title")
|
||||
private const val NOTIFICATION_GROUP_ID = "Incompatible Kotlin/Native libraries"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#if (${MODULE_GROUP} && ${MODULE_GROUP} != "")
|
||||
group = "${MODULE_GROUP}"
|
||||
#end
|
||||
#if (${MODULE_VERSION} && ${MODULE_VERSION} != "")
|
||||
version = "${MODULE_VERSION}"
|
||||
#end
|
||||
@@ -1,20 +0,0 @@
|
||||
#if (${PROJECT_NAME} && ${PROJECT_NAME} != "")
|
||||
#if (((!${MODULE_PATH} || ${MODULE_PATH} == "")) && (${MODULE_NAME} && ${MODULE_NAME} != ""))
|
||||
rootProject.name = '${MODULE_NAME}'
|
||||
#else
|
||||
rootProject.name = '${PROJECT_NAME}'
|
||||
#end
|
||||
#end
|
||||
#if (${MODULE_PATH} && ${MODULE_PATH} != "")
|
||||
#if (${MODULE_FLAT_DIR} == "true")includeFlat '${MODULE_PATH}'
|
||||
#else
|
||||
include '${MODULE_PATH}'
|
||||
#end
|
||||
#if (${MODULE_NAME} && ${MODULE_NAME} != "" && ${MODULE_PATH} != ${MODULE_NAME})
|
||||
findProject(':${MODULE_PATH}')?.name = '${MODULE_NAME}'
|
||||
#end
|
||||
#end
|
||||
#if (${BUILD_FILE_NAME} && ${BUILD_FILE_NAME} != "")
|
||||
rootProject.buildFileName = '${BUILD_FILE_NAME}'
|
||||
#end
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.actions
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.ide.actions.ShowFilePathAction
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.MessageType
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.ui.BrowserHyperlinkListener
|
||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
||||
import java.io.File
|
||||
|
||||
class ShowKotlinGradleDslLogs : IntentionAction, AnAction(), DumbAware {
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
|
||||
openLogsDirIfPresent(project)
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
openLogsDirIfPresent(e.project)
|
||||
}
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) = ShowFilePathAction.isSupported()
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val presentation = e.presentation
|
||||
presentation.isVisible = ShowFilePathAction.isSupported()
|
||||
presentation.text = NAME
|
||||
}
|
||||
|
||||
private fun openLogsDirIfPresent(project: Project?) {
|
||||
val logsDir = findLogsDir()
|
||||
if (logsDir != null) {
|
||||
ShowFilePathAction.openDirectory(logsDir)
|
||||
} else {
|
||||
val parent = WindowManager.getInstance().getStatusBar(project)?.component
|
||||
?: WindowManager.getInstance().findVisibleFrame().rootPane
|
||||
JBPopupFactory.getInstance()
|
||||
.createHtmlTextBalloonBuilder(
|
||||
KotlinIdeaGradleBundle.message(
|
||||
"text.gradle.dsl.logs.cannot.be.found.automatically.see.how.to.find.logs",
|
||||
gradleTroubleshootingLink
|
||||
),
|
||||
MessageType.ERROR,
|
||||
BrowserHyperlinkListener.INSTANCE
|
||||
)
|
||||
.setFadeoutTime(5000)
|
||||
.createBalloon()
|
||||
.showInCenterOf(parent)
|
||||
}
|
||||
}
|
||||
|
||||
/** The way how to find Gradle logs is described here
|
||||
* @see org.jetbrains.kotlin.idea.actions.ShowKotlinGradleDslLogs.gradleTroubleshootingLink
|
||||
*/
|
||||
private fun findLogsDir(): File? {
|
||||
val userHome = System.getProperty("user.home")
|
||||
return when {
|
||||
SystemInfo.isMac -> File("$userHome/Library/Logs/gradle-kotlin-dsl")
|
||||
SystemInfo.isLinux -> File("$userHome/.gradle-kotlin-dsl/logs")
|
||||
SystemInfo.isWindows -> File("$userHome/AppData/Local/gradle-kotlin-dsl/log")
|
||||
else -> null
|
||||
}.takeIf { it?.exists() == true }
|
||||
}
|
||||
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun getText() = NAME
|
||||
|
||||
override fun getFamilyName() = NAME
|
||||
|
||||
companion object {
|
||||
private const val gradleTroubleshootingLink = "https://docs.gradle.org/current/userguide/kotlin_dsl.html#troubleshooting"
|
||||
|
||||
val NAME = KotlinIdeaGradleBundle.message("action.text.show.kotlin.gradle.dsl.logs.in", ShowFilePathAction.getFileManagerName())
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationAction
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginsAdvertiser
|
||||
import com.intellij.util.PlatformUtils
|
||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle
|
||||
|
||||
const val NATIVE_DEBUG_ID = "com.intellij.nativeDebug"
|
||||
|
||||
fun suggestNativeDebug(projectPath: String) {
|
||||
if (!PlatformUtils.isIdeaUltimate() ||
|
||||
PluginManager.isPluginInstalled(PluginId.getId(NATIVE_DEBUG_ID))) {
|
||||
return
|
||||
}
|
||||
|
||||
val project = ProjectManager.getInstance().openProjects.firstOrNull { it.basePath == projectPath } ?: return
|
||||
|
||||
PluginsAdvertiser.NOTIFICATION_GROUP.createNotification(
|
||||
KotlinIdeaGradleBundle.message("title.plugin.suggestion"),
|
||||
KotlinIdeaGradleBundle.message("notification.text.native.debug.provides.debugger.for.kotlin.native"),
|
||||
NotificationType.INFORMATION, null
|
||||
).addAction(object : NotificationAction(KotlinIdeaGradleBundle.message("action.text.install")) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
PluginsAdvertiser.installAndEnablePlugins(setOf(NATIVE_DEBUG_ID)) { notification.expire() }
|
||||
}
|
||||
}).notify(project)
|
||||
}
|
||||
-366
@@ -1,366 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.gradle.execution;
|
||||
|
||||
import com.intellij.build.BuildViewManager;
|
||||
import com.intellij.compiler.impl.CompilerUtil;
|
||||
import com.intellij.execution.executors.DefaultRunExecutor;
|
||||
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
|
||||
import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys;
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
|
||||
import com.intellij.openapi.externalSystem.task.TaskCallback;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.task.*;
|
||||
import com.intellij.task.impl.JpsProjectTaskRunner;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.config.KotlinFacetSettings;
|
||||
import org.jetbrains.kotlin.idea.KotlinIdeaGradleBundle;
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet;
|
||||
import org.jetbrains.kotlin.platform.TargetPlatformKt;
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform;
|
||||
import org.jetbrains.kotlin.platform.konan.NativePlatformKt;
|
||||
import org.jetbrains.plugins.gradle.execution.build.CachedModuleDataFinder;
|
||||
import org.jetbrains.plugins.gradle.execution.build.GradleProjectTaskRunner;
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleBuildSrcProjectsResolver;
|
||||
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil;
|
||||
import org.jetbrains.plugins.gradle.service.task.GradleTaskManager;
|
||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings;
|
||||
import org.jetbrains.plugins.gradle.settings.GradleSettings;
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration.PROGRESS_LISTENER_KEY;
|
||||
import static com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.*;
|
||||
import static com.intellij.openapi.util.text.StringUtil.*;
|
||||
import static org.jetbrains.plugins.gradle.execution.GradleRunnerUtil.resolveProjectPath;
|
||||
|
||||
/**
|
||||
* This is a modified copy of {@link GradleProjectTaskRunner} that allows building Kotlin Common and Kotlin Native modules
|
||||
* in IDEA by delegating to Gradle builder ("Delegate IDE build/run actions to gradle"). See #KT-27295, #KT-27296.
|
||||
*
|
||||
* TODO: Refactor this class to remove duplicated logic when {@link GradleProjectTaskRunner} will allow extending it to
|
||||
* collect custom Gradle tasks. See #IDEA-204372, #KT-28880.
|
||||
*/
|
||||
class KotlinMPPGradleProjectTaskRunner extends ProjectTaskRunner
|
||||
{
|
||||
|
||||
@Language("Groovy")
|
||||
private static final String FORCE_COMPILE_TASKS_INIT_SCRIPT_TEMPLATE = "projectsEvaluated { \n" +
|
||||
" rootProject.findProject('%s')?.tasks?.withType(AbstractCompile) { \n" +
|
||||
" outputs.upToDateWhen { false } \n" +
|
||||
" } \n" +
|
||||
"}\n";
|
||||
|
||||
@Override
|
||||
public void run(@NotNull Project project,
|
||||
@NotNull ProjectTaskContext context,
|
||||
@Nullable ProjectTaskNotification callback,
|
||||
@NotNull Collection<? extends ProjectTask> tasks) {
|
||||
MultiMap<String, String> buildTasksMap = MultiMap.createLinkedSet();
|
||||
MultiMap<String, String> cleanTasksMap = MultiMap.createLinkedSet();
|
||||
MultiMap<String, String> initScripts = MultiMap.createLinkedSet();
|
||||
|
||||
Map<Class<? extends ProjectTask>, List<ProjectTask>> taskMap = JpsProjectTaskRunner.groupBy(tasks);
|
||||
|
||||
List<Module> modules = addModulesBuildTasks(taskMap.get(ModuleBuildTask.class), buildTasksMap, initScripts);
|
||||
// TODO there should be 'gradle' way to build files instead of related modules entirely
|
||||
List<Module> modulesOfFiles = addModulesBuildTasks(taskMap.get(ModuleFilesBuildTask.class), buildTasksMap, initScripts);
|
||||
|
||||
// TODO send a message if nothing to build
|
||||
Set<String> rootPaths = buildTasksMap.keySet();
|
||||
AtomicInteger successCounter = new AtomicInteger();
|
||||
AtomicInteger errorCounter = new AtomicInteger();
|
||||
|
||||
TaskCallback taskCallback = callback == null ? null : new TaskCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
handle(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
handle(false);
|
||||
}
|
||||
|
||||
private void handle(boolean success) {
|
||||
int successes = success ? successCounter.incrementAndGet() : successCounter.get();
|
||||
int errors = success ? errorCounter.get() : errorCounter.incrementAndGet();
|
||||
if (successes + errors == rootPaths.size()) {
|
||||
if (!project.isDisposed()) {
|
||||
// refresh on output roots is required in order for the order enumerator to see all roots via VFS
|
||||
final List<Module> affectedModules = ContainerUtil.concat(modules, modulesOfFiles);
|
||||
// have to refresh in case of errors too, because run configuration may be set to ignore errors
|
||||
Collection<String> affectedRoots = ContainerUtil.newHashSet(
|
||||
CompilerPathsEx.getOutputPaths(affectedModules.toArray(Module.EMPTY_ARRAY)));
|
||||
if (!affectedRoots.isEmpty()) {
|
||||
CompilerUtil.refreshOutputRoots(affectedRoots);
|
||||
}
|
||||
}
|
||||
callback.finished(new ProjectTaskResult(false, errors, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO compiler options should be configurable
|
||||
@Language("Groovy")
|
||||
String compilerOptionsInitScript = "allprojects {\n" +
|
||||
" tasks.withType(JavaCompile) {\n" +
|
||||
" options.compilerArgs += [\"-Xlint:deprecation\"]\n" +
|
||||
" }" +
|
||||
"}\n";
|
||||
|
||||
String gradleVmOptions = GradleSettings.getInstance(project).getGradleVmOptions();
|
||||
for (String rootProjectPath : rootPaths) {
|
||||
Collection<String> buildTasks = buildTasksMap.get(rootProjectPath);
|
||||
if (buildTasks.isEmpty()) continue;
|
||||
Collection<String> cleanTasks = cleanTasksMap.get(rootProjectPath);
|
||||
|
||||
ExternalSystemTaskExecutionSettings settings = new ExternalSystemTaskExecutionSettings();
|
||||
|
||||
File projectFile = new File(rootProjectPath);
|
||||
final String projectName;
|
||||
if (projectFile.isFile()) {
|
||||
projectName = projectFile.getParentFile().getName();
|
||||
}
|
||||
else {
|
||||
projectName = projectFile.getName();
|
||||
}
|
||||
String executionName = KotlinIdeaGradleBundle.message("build.0.project", projectName);
|
||||
settings.setExecutionName(executionName);
|
||||
settings.setExternalProjectPath(rootProjectPath);
|
||||
settings.setTaskNames(ContainerUtil.collect(ContainerUtil.concat(cleanTasks, buildTasks).iterator()));
|
||||
//settings.setScriptParameters(scriptParameters);
|
||||
settings.setVmOptions(gradleVmOptions);
|
||||
settings.setExternalSystemIdString(GradleConstants.SYSTEM_ID.getId());
|
||||
|
||||
UserDataHolderBase userData = new UserDataHolderBase();
|
||||
userData.putUserData(PROGRESS_LISTENER_KEY, BuildViewManager.class);
|
||||
|
||||
Collection<String> scripts = initScripts.getModifiable(rootProjectPath);
|
||||
scripts.add(compilerOptionsInitScript);
|
||||
userData.putUserData(GradleTaskManager.INIT_SCRIPT_KEY, join(scripts, SystemProperties.getLineSeparator()));
|
||||
userData.putUserData(GradleTaskManager.INIT_SCRIPT_PREFIX_KEY, executionName);
|
||||
|
||||
ExternalSystemUtil.runTask(settings, DefaultRunExecutor.EXECUTOR_ID, project, GradleConstants.SYSTEM_ID,
|
||||
taskCallback, ProgressExecutionMode.IN_BACKGROUND_ASYNC, false, userData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRun(@NotNull ProjectTask projectTask) {
|
||||
if (projectTask instanceof ModuleBuildTask) {
|
||||
final ModuleBuildTask moduleBuildTask = (ModuleBuildTask) projectTask;
|
||||
final Module module = moduleBuildTask.getModule();
|
||||
|
||||
if (module.getProject().getPresentableUrl() == null || !GradleProjectSettings.isDelegatedBuildEnabled(module)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return false;
|
||||
|
||||
// ---------------------------------------- //
|
||||
// TODO BEGIN: Extract custom Kotlin logic. //
|
||||
// ---------------------------------------- //
|
||||
if (isProjectWithNativeSourceOrCommonProductionSourceModules(module.getProject())) return true;
|
||||
// ---------------------------------------- //
|
||||
// TODO END: Extract custom Kotlin logic. //
|
||||
// ---------------------------------------- //
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<Module> addModulesBuildTasks(@Nullable Collection<? extends ProjectTask> projectTasks,
|
||||
@NotNull MultiMap<String, String> buildTasksMap,
|
||||
@NotNull MultiMap<String, String> initScripts) {
|
||||
if (ContainerUtil.isEmpty(projectTasks)) return Collections.emptyList();
|
||||
|
||||
List<Module> affectedModules = new SmartList<>();
|
||||
Map<Module, String> rootPathsMap = FactoryMap.create(module -> notNullize(resolveProjectPath(module)));
|
||||
final CachedModuleDataFinder moduleDataFinder = new CachedModuleDataFinder();
|
||||
for (ProjectTask projectTask : projectTasks) {
|
||||
if (!(projectTask instanceof ModuleBuildTask)) continue;
|
||||
|
||||
ModuleBuildTask moduleBuildTask = (ModuleBuildTask)projectTask;
|
||||
Module module = moduleBuildTask.getModule();
|
||||
affectedModules.add(module);
|
||||
|
||||
final String rootProjectPath = rootPathsMap.get(module);
|
||||
if (isEmpty(rootProjectPath)) continue;
|
||||
|
||||
final String projectId = getExternalProjectId(module);
|
||||
if (projectId == null) continue;
|
||||
final String externalProjectPath = getExternalProjectPath(module);
|
||||
if (externalProjectPath == null || endsWith(externalProjectPath, "buildSrc")) continue;
|
||||
|
||||
final DataNode<? extends ModuleData> moduleDataNode = moduleDataFinder.findMainModuleData(module);
|
||||
if (moduleDataNode == null) continue;
|
||||
|
||||
// all buildSrc runtime projects will be built by gradle implicitly
|
||||
if (Boolean.parseBoolean(moduleDataNode.getData().getProperty(GradleBuildSrcProjectsResolver.BUILD_SRC_MODULE_PROPERTY))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String gradlePath = GradleProjectResolverUtil.getGradlePath(module);
|
||||
if (gradlePath == null) continue;
|
||||
String taskPrefix = endsWithChar(gradlePath, ':') ? gradlePath : (gradlePath + ':');
|
||||
|
||||
List<String> gradleTasks = ContainerUtil.mapNotNull(
|
||||
findAll(moduleDataNode, ProjectKeys.TASK), node ->
|
||||
node.getData().isInherited() ? null : trimStart(node.getData().getName(), taskPrefix));
|
||||
|
||||
Collection<String> projectInitScripts = initScripts.getModifiable(rootProjectPath);
|
||||
Collection<String> buildRootTasks = buildTasksMap.getModifiable(rootProjectPath);
|
||||
final String moduleType = getExternalModuleType(module);
|
||||
|
||||
if (!moduleBuildTask.isIncrementalBuild()) {
|
||||
projectInitScripts.add(String.format(FORCE_COMPILE_TASKS_INIT_SCRIPT_TEMPLATE, gradlePath));
|
||||
}
|
||||
String assembleTask = "assemble";
|
||||
if (GradleConstants.GRADLE_SOURCE_SET_MODULE_TYPE_KEY.equals(moduleType)) {
|
||||
String sourceSetName = GradleProjectResolverUtil.getSourceSetName(module);
|
||||
String gradleTask = isEmpty(sourceSetName) || "main".equals(sourceSetName) ? "classes" : sourceSetName + "Classes";
|
||||
if (gradleTasks.contains(gradleTask)) {
|
||||
buildRootTasks.add(taskPrefix + gradleTask);
|
||||
}
|
||||
else if ("main".equals(sourceSetName) || "test".equals(sourceSetName)) {
|
||||
buildRootTasks.add(taskPrefix + assembleTask);
|
||||
}
|
||||
// ---------------------------------------- //
|
||||
// TODO BEGIN: Extract custom Kotlin logic. //
|
||||
// ---------------------------------------- //
|
||||
else if (isNativeSourceModule(module)) {
|
||||
// Add tasks for Kotlin/Native.
|
||||
buildRootTasks.addAll(addPrefix(findNativeGradleBuildTasks(gradleTasks, sourceSetName), taskPrefix));
|
||||
}
|
||||
else if (isCommonProductionSourceModule(module)) {
|
||||
// Add tasks for compiling metadata.
|
||||
buildRootTasks.addAll(addPrefix(findMetadataBuildTasks(gradleTasks, sourceSetName), taskPrefix));
|
||||
}
|
||||
// ---------------------------------------- //
|
||||
// TODO END: Extract custom Kotlin logic. //
|
||||
// ---------------------------------------- //
|
||||
}
|
||||
else {
|
||||
if (gradleTasks.contains("classes")) {
|
||||
buildRootTasks.add(taskPrefix + "classes");
|
||||
buildRootTasks.add(taskPrefix + "testClasses");
|
||||
}
|
||||
else if (gradleTasks.contains(assembleTask)) {
|
||||
buildRootTasks.add(taskPrefix + assembleTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
return affectedModules;
|
||||
}
|
||||
|
||||
// ---------------------------------------- //
|
||||
// TODO BEGIN: Extract custom Kotlin logic. //
|
||||
// ---------------------------------------- //
|
||||
private static boolean isProjectWithNativeSourceOrCommonProductionSourceModules(Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(
|
||||
project,
|
||||
() -> new CachedValueProvider.Result<>(
|
||||
Arrays.stream(ModuleManager.getInstance(project).getModules()).anyMatch(
|
||||
module -> isNativeSourceModule(module) || isCommonProductionSourceModule(module)
|
||||
),
|
||||
ProjectRootModificationTracker.getInstance(project)
|
||||
));
|
||||
}
|
||||
|
||||
private static boolean isNativeSourceModule(Module module) {
|
||||
final KotlinFacet kotlinFacet = KotlinFacet.Companion.get(module);
|
||||
if (kotlinFacet == null) return false;
|
||||
|
||||
final TargetPlatform platform = kotlinFacet.getConfiguration().getSettings().getTargetPlatform();
|
||||
if (platform == null) return false;
|
||||
|
||||
return NativePlatformKt.isNative(platform);
|
||||
}
|
||||
|
||||
private static boolean isCommonProductionSourceModule(Module module) {
|
||||
final KotlinFacet kotlinFacet = KotlinFacet.Companion.get(module);
|
||||
if (kotlinFacet == null) return false;
|
||||
|
||||
final KotlinFacetSettings facetSettings = kotlinFacet.getConfiguration().getSettings();
|
||||
if (facetSettings.isTestModule()) return false;
|
||||
|
||||
final TargetPlatform platform = facetSettings.getTargetPlatform();
|
||||
if (platform == null) return false;
|
||||
|
||||
return TargetPlatformKt.isCommon(platform);
|
||||
}
|
||||
|
||||
private static Collection<String> findNativeGradleBuildTasks(Collection<String> gradleTasks, String sourceSetName) {
|
||||
// First, attempt to find Kotlin/Native convention Gradle task that unites all outputType-specific build tasks.
|
||||
final String conventionGradleTask = sourceSetName + "Binaries";
|
||||
if (gradleTasks.contains(conventionGradleTask)) {
|
||||
return Collections.singletonList(conventionGradleTask);
|
||||
}
|
||||
|
||||
// If convention task not found, then attempt to find all appropriate build tasks for the given source set.
|
||||
final Collection<String> linkPrefixes;
|
||||
final String targetName;
|
||||
if (sourceSetName.endsWith("Main")) {
|
||||
targetName = StringUtil.substringBeforeLast(sourceSetName,"Main");
|
||||
linkPrefixes = ContainerUtil.newArrayList("link", "linkMain");
|
||||
}
|
||||
else if (sourceSetName.endsWith("Test")) {
|
||||
targetName = StringUtil.substringBeforeLast(sourceSetName,"Test");
|
||||
linkPrefixes = Collections.singletonList("linkTest");
|
||||
}
|
||||
else {
|
||||
targetName = sourceSetName;
|
||||
linkPrefixes = Collections.singletonList("link");
|
||||
}
|
||||
|
||||
return linkPrefixes.stream()
|
||||
// get base task name (without disambiguation classifier)
|
||||
.map(linkPrefix -> linkPrefix + capitalize(targetName))
|
||||
// find all Gradle tasks that start with base task name
|
||||
.flatMap(nativeTaskName -> gradleTasks.stream().filter(taskName -> taskName.startsWith(nativeTaskName)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Collection<String> findMetadataBuildTasks(Collection<String> gradleTasks, String sourceSetName) {
|
||||
if ("commonMain".equals(sourceSetName)) {
|
||||
final String metadataTaskName = "metadataMainClasses";
|
||||
if (gradleTasks.contains(metadataTaskName)) {
|
||||
return Collections.singletonList(metadataTaskName);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static Collection<String> addPrefix(Collection<String> tasks, String taskPrefix) {
|
||||
return tasks.stream().map(task -> taskPrefix + task).collect(Collectors.toList());
|
||||
}
|
||||
// ---------------------------------------- //
|
||||
// TODO END: Extract custom Kotlin logic. //
|
||||
// ---------------------------------------- //
|
||||
}
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.gradle.testing
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||
import com.intellij.openapi.externalSystem.model.task.TaskData
|
||||
import com.intellij.openapi.externalSystem.util.Order
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.util.Consumer
|
||||
import org.gradle.tooling.model.idea.IdeaModule
|
||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
|
||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModelBuilder
|
||||
import org.jetbrains.kotlin.idea.configuration.getMppModel
|
||||
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||
|
||||
@Order(Int.MIN_VALUE)
|
||||
open class KotlinTestTasksResolver : AbstractProjectResolverExtension() {
|
||||
companion object {
|
||||
private const val ENABLED_REGISTRY_KEY = "kotlin.gradle.testing.enabled"
|
||||
}
|
||||
|
||||
private val LOG by lazy { Logger.getInstance(KotlinTestTasksResolver::class.java) }
|
||||
|
||||
override fun getToolingExtensionsClasses(): Set<Class<out Any>> {
|
||||
return setOf(KotlinMPPGradleModelBuilder::class.java, Unit::class.java)
|
||||
}
|
||||
|
||||
override fun populateModuleTasks(
|
||||
gradleModule: IdeaModule,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
ideProject: DataNode<ProjectData>
|
||||
): MutableCollection<TaskData> {
|
||||
if (!Registry.`is`(ENABLED_REGISTRY_KEY))
|
||||
return super.populateModuleTasks(gradleModule, ideModule, ideProject)
|
||||
|
||||
val mppModel = resolverCtx.getMppModel(gradleModule)
|
||||
?: return super.populateModuleTasks(gradleModule, ideModule, ideProject)
|
||||
|
||||
return postprocessTaskData(mppModel, ideModule, nextResolver.populateModuleTasks(gradleModule, ideModule, ideProject))
|
||||
}
|
||||
|
||||
private fun postprocessTaskData(
|
||||
mppModel: KotlinMPPGradleModel,
|
||||
ideModule: DataNode<ModuleData>,
|
||||
originalTaskData: MutableCollection<TaskData>
|
||||
): MutableCollection<TaskData> {
|
||||
val testTaskNames = mutableSetOf<String>().apply {
|
||||
mppModel.targets.forEach { target ->
|
||||
target.testRunTasks.forEach { testTaskModel ->
|
||||
add(testTaskModel.taskName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun buildNewTaskDataMarkedAsTest(original: TaskData): TaskData =
|
||||
TaskData(original.owner, original.name, original.linkedExternalProjectPath, original.description).apply {
|
||||
group = original.group
|
||||
type = original.type
|
||||
isInherited = original.isInherited
|
||||
|
||||
isTest = true
|
||||
}
|
||||
|
||||
val replacementMap: Map<TaskData, TaskData> = mutableMapOf<TaskData, TaskData>().apply {
|
||||
originalTaskData.forEach {
|
||||
if (it.name in testTaskNames && !it.isTest) {
|
||||
put(it, buildNewTaskDataMarkedAsTest(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ideModule.children.filter { it.data in replacementMap }.forEach { it.clear(true) }
|
||||
replacementMap.values.forEach { ideModule.createChild(ProjectKeys.TASK, it) }
|
||||
|
||||
return originalTaskData.mapTo(arrayListOf<TaskData>()) { replacementMap[it] ?: it }
|
||||
}
|
||||
|
||||
override fun enhanceTaskProcessing(
|
||||
taskNames: MutableList<String>,
|
||||
jvmParametersSetup: String?,
|
||||
initScriptConsumer: Consumer<String>,
|
||||
testExecutionExpected: kotlin.Boolean
|
||||
) {
|
||||
if (!Registry.`is`(ENABLED_REGISTRY_KEY))
|
||||
return
|
||||
|
||||
if (testExecutionExpected) {
|
||||
try {
|
||||
val addTestListenerScript = javaClass
|
||||
.getResourceAsStream("/org/jetbrains/kotlin/idea/gradle/testing/addKotlinMppTestListener.groovy")
|
||||
.bufferedReader()
|
||||
.readText()
|
||||
initScriptConsumer.consume(addTestListenerScript)
|
||||
} catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
enhanceTaskProcessing(taskNames, jvmParametersSetup, initScriptConsumer)
|
||||
}
|
||||
|
||||
override fun enhanceTaskProcessing(taskNames: MutableList<String>, jvmAgentSetup: String?, initScriptConsumer: Consumer<String>) {
|
||||
if (!Registry.`is`(ENABLED_REGISTRY_KEY))
|
||||
return
|
||||
|
||||
try {
|
||||
val testLoggerScript = javaClass
|
||||
.getResourceAsStream("/org/jetbrains/kotlin/idea/gradle/testing/KotlinMppTestLogger.groovy")
|
||||
.bufferedReader()
|
||||
.readText()
|
||||
|
||||
initScriptConsumer.consume(testLoggerScript)
|
||||
} catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.run
|
||||
|
||||
import com.intellij.execution.Location
|
||||
import com.intellij.execution.actions.ConfigurationFromContext
|
||||
import com.intellij.execution.junit.JUnitConfigurationProducer
|
||||
import com.intellij.execution.testframework.AbstractPatternBasedConfigurationProducer
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.openapi.extensions.PluginId.getId
|
||||
import com.intellij.openapi.util.component1
|
||||
import com.intellij.openapi.util.component2
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
|
||||
private val isJUnitEnabled by lazy { isPluginEnabled("JUnit") }
|
||||
private val isTestNgEnabled by lazy { isPluginEnabled("TestNG-J") }
|
||||
|
||||
private fun isPluginEnabled(id: String): Boolean {
|
||||
return PluginManager.isPluginInstalled(getId(id)) && id !in PluginManager.getDisabledPlugins()
|
||||
}
|
||||
|
||||
internal fun ConfigurationFromContext.isJpsJunitConfiguration(): Boolean {
|
||||
return isProducedBy(JUnitConfigurationProducer::class.java)
|
||||
|| isProducedBy(AbstractPatternBasedConfigurationProducer::class.java)
|
||||
}
|
||||
|
||||
internal fun canRunJvmTests() = isJUnitEnabled || isTestNgEnabled
|
||||
|
||||
internal fun getTestClassForJvm(location: Location<*>): PsiClass? {
|
||||
val leaf = location.psiElement ?: return null
|
||||
|
||||
if (leaf.language != KotlinLanguage.INSTANCE) return null
|
||||
|
||||
if (isJUnitEnabled) {
|
||||
KotlinJUnitRunConfigurationProducer.getTestClass(leaf)?.let { return it }
|
||||
}
|
||||
if (isTestNgEnabled) {
|
||||
KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.let { (testClass, testMethod) ->
|
||||
return if (testMethod == null) testClass else null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
internal fun getTestMethodForJvm(location: Location<*>): PsiMethod? {
|
||||
val leaf = location.psiElement ?: return null
|
||||
|
||||
if (leaf.language != KotlinLanguage.INSTANCE) return null
|
||||
|
||||
if (isJUnitEnabled) {
|
||||
KotlinJUnitRunConfigurationProducer.getTestMethod(leaf)?.let { return it }
|
||||
}
|
||||
if (isTestNgEnabled) {
|
||||
KotlinTestNgConfigurationProducer.getTestClassAndMethod(leaf)?.second?.let { return it }
|
||||
}
|
||||
return null
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scripting.gradle.importing
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||
import org.gradle.tooling.model.idea.IdeaProject
|
||||
import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
|
||||
import org.jetbrains.kotlin.gradle.KotlinDslScriptAdditionalTask
|
||||
import org.jetbrains.kotlin.gradle.KotlinDslScriptModelProvider
|
||||
import org.jetbrains.kotlin.idea.scripting.gradle.kotlinDslScriptsModelImportSupported
|
||||
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider
|
||||
import org.jetbrains.plugins.gradle.model.ClassSetBuildImportModelProvider
|
||||
|
||||
class KotlinDslScriptModelResolver : KotlinDslScriptModelResolverCommon() {
|
||||
override fun requiresTaskRunning() = true
|
||||
|
||||
override fun getModelProvider() = KotlinDslScriptModelProvider()
|
||||
|
||||
override fun getProjectsLoadedModelProvider(): ProjectImportModelProvider? {
|
||||
return ClassSetBuildImportModelProvider(
|
||||
setOf(KotlinDslScriptAdditionalTask::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun populateProjectExtraModels(gradleProject: IdeaProject, ideProject: DataNode<ProjectData>) {
|
||||
super.populateProjectExtraModels(gradleProject, ideProject)
|
||||
|
||||
populateBuildModels(gradleProject, ideProject)
|
||||
|
||||
resolverCtx.models.includedBuilds.forEach { includedRoot ->
|
||||
populateBuildModels(includedRoot, ideProject)
|
||||
}
|
||||
}
|
||||
|
||||
private fun populateBuildModels(
|
||||
root: IdeaProject,
|
||||
ideProject: DataNode<ProjectData>
|
||||
) {
|
||||
root.modules.forEach {
|
||||
if (it.gradleProject.parent == null) {
|
||||
if (kotlinDslScriptsModelImportSupported(resolverCtx.projectGradleVersion)) {
|
||||
resolverCtx.getExtraProject(it, KotlinDslScriptsModel::class.java)?.let { model ->
|
||||
processScriptModel(resolverCtx, model, it.name)
|
||||
}
|
||||
}
|
||||
|
||||
saveGradleBuildEnvironment(resolverCtx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scripting.gradle.settings
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class StandaloneScriptsUIComponent(val project: Project) : StandaloneScriptsUIComponentCompat(project) {
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight.gradle;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.packaging.artifacts.Artifact;
|
||||
import com.intellij.task.ProjectTaskManager;
|
||||
|
||||
//BUNCH 193
|
||||
class ExternalSystemTestCaseBunch {
|
||||
|
||||
protected static boolean isDefaultRefreshCallback(Object callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static void build(Object[] buildableElements, Project myProject) {
|
||||
if (buildableElements instanceof Module[]) {
|
||||
ProjectTaskManager.getInstance(myProject).build((Module[])buildableElements);
|
||||
}
|
||||
else if (buildableElements instanceof Artifact[]) {
|
||||
ProjectTaskManager.getInstance(myProject).build((Artifact[])buildableElements);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.idea
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.BaseComponent
|
||||
import org.jetbrains.kotlin.idea.ThreadTrackerPatcherForTeamCityTesting.patchThreadTracker
|
||||
import org.jetbrains.kotlin.idea.debugger.filter.addKotlinStdlibDebugFilterIfNeeded
|
||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class JvmPluginStartupComponent : BaseComponent {
|
||||
override fun getComponentName(): String = JvmPluginStartupComponent::class.java.name
|
||||
|
||||
override fun initComponent() {
|
||||
if (isUnitTestMode()) {
|
||||
patchThreadTracker()
|
||||
}
|
||||
addKotlinStdlibDebugFilterIfNeeded()
|
||||
}
|
||||
|
||||
override fun disposeComponent() {}
|
||||
|
||||
companion object {
|
||||
fun getInstance(): JvmPluginStartupComponent =
|
||||
ApplicationManager.getApplication().getComponent(JvmPluginStartupComponent::class.java)
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.kotlin.idea.compiler
|
||||
|
||||
import com.intellij.diagnostic.PluginException
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.compiler.CompilationStatusListener
|
||||
import com.intellij.openapi.compiler.CompileContext
|
||||
import com.intellij.openapi.compiler.CompilerManager
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.config.CompilerRunnerConstants
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.js.JavaScript
|
||||
import java.io.PrintStream
|
||||
import java.io.PrintWriter
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class KotlinCompilerManager(project: Project, manager: CompilerManager) : ProjectComponent {
|
||||
// Extending PluginException ensures that Exception Analyzer recognizes this as a Kotlin exception
|
||||
private class KotlinCompilerException(private val text: String) :
|
||||
PluginException("", PluginManagerCore.getPluginByClassName(KotlinCompilerManager::class.java.name)) {
|
||||
override fun printStackTrace(s: PrintWriter) {
|
||||
s.print(text)
|
||||
}
|
||||
|
||||
override fun printStackTrace(s: PrintStream) {
|
||||
s.print(text)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun fillInStackTrace(): Throwable {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getStackTrace(): Array<StackTraceElement> {
|
||||
LOG.error("Somebody called getStackTrace() on KotlinCompilerException")
|
||||
// Return some stack trace that originates in Kotlin
|
||||
return UnsupportedOperationException().stackTrace
|
||||
}
|
||||
|
||||
override val message: String
|
||||
get() = "<Exception from standalone Kotlin compiler>"
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(KotlinCompilerManager::class.java)
|
||||
|
||||
// Comes from external make
|
||||
private const val PREFIX_WITH_COMPILER_NAME =
|
||||
CompilerRunnerConstants.KOTLIN_COMPILER_NAME + ": " + CompilerRunnerConstants.INTERNAL_ERROR_PREFIX
|
||||
private val FILE_EXTS_WHICH_NEEDS_REFRESH = ContainerUtil.immutableSet(JavaScript.DOT_EXTENSION, ".map")
|
||||
}
|
||||
|
||||
init {
|
||||
manager.addCompilableFileType(KotlinFileType.INSTANCE)
|
||||
manager.addCompilationStatusListener(object : CompilationStatusListener {
|
||||
override fun compilationFinished(aborted: Boolean, errors: Int, warnings: Int, compileContext: CompileContext) {
|
||||
for (error in compileContext.getMessages(CompilerMessageCategory.ERROR)) {
|
||||
val message = error.message
|
||||
if (message.startsWith(CompilerRunnerConstants.INTERNAL_ERROR_PREFIX) || message.startsWith(PREFIX_WITH_COMPILER_NAME)) {
|
||||
LOG.error(KotlinCompilerException(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun fileGenerated(outputRoot: String, relativePath: String) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) return
|
||||
val ext = FileUtilRt.getExtension(relativePath).toLowerCase()
|
||||
if (FILE_EXTS_WHICH_NEEDS_REFRESH.contains(ext)) {
|
||||
val outFile = "$outputRoot/$relativePath"
|
||||
val virtualFile = LocalFileSystem.getInstance().findFileByPath(outFile)
|
||||
?: error("Virtual file not found for generated file path: $outFile")
|
||||
virtualFile.refresh( /*async =*/false, /*recursive =*/false)
|
||||
}
|
||||
}
|
||||
}, project)
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.compiler.configuration
|
||||
|
||||
import com.intellij.compiler.server.BuildProcessParametersProvider
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.idea.PluginStartupComponent
|
||||
|
||||
class KotlinBuildProcessParametersProvider(private val project: Project) : BuildProcessParametersProvider() {
|
||||
override fun getVMArguments(): MutableList<String> {
|
||||
val compilerWorkspaceSettings = KotlinCompilerWorkspaceSettings.getInstance(project)
|
||||
|
||||
val res = arrayListOf<String>()
|
||||
if (compilerWorkspaceSettings.preciseIncrementalEnabled) {
|
||||
res.add("-D" + IncrementalCompilation.INCREMENTAL_COMPILATION_JVM_PROPERTY + "=true")
|
||||
}
|
||||
if (compilerWorkspaceSettings.incrementalCompilationForJsEnabled) {
|
||||
res.add("-D" + IncrementalCompilation.INCREMENTAL_COMPILATION_JS_PROPERTY + "=true")
|
||||
}
|
||||
if (compilerWorkspaceSettings.enableDaemon) {
|
||||
res.add("-Dkotlin.daemon.enabled")
|
||||
}
|
||||
if (Registry.`is`("kotlin.jps.instrument.bytecode", false)) {
|
||||
res.add("-Dkotlin.jps.instrument.bytecode=true")
|
||||
}
|
||||
PluginStartupComponent.getInstance().aliveFlagPath.let {
|
||||
if (!it.isBlank()) {
|
||||
// TODO: consider taking the property name from compiler/daemon/common (check whether dependency will be not too heavy)
|
||||
res.add("-Dkotlin.daemon.client.alive.path=\"$it\"")
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.ReadAction.nonBlocking
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
import org.jetbrains.kotlin.idea.configuration.ui.notifications.ConfigureKotlinNotification
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
fun notify(manager: ConfigureKotlinNotificationManager, project: Project, excludeModules: List<Module>) {
|
||||
nonBlocking(Callable {
|
||||
ConfigureKotlinNotification.getNotificationState(project, excludeModules)
|
||||
})
|
||||
.expireWith(project)
|
||||
.finishOnUiThread(ModalityState.any()) { notificationState ->
|
||||
notificationState?.let {
|
||||
manager.notify(project, ConfigureKotlinNotification(project, excludeModules, it))
|
||||
}
|
||||
}
|
||||
.submit(AppExecutorUtil.getAppExecutorService())
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration.ui
|
||||
|
||||
import com.intellij.notification.NotificationDisplayType
|
||||
import com.intellij.notification.NotificationsConfiguration
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
|
||||
import org.jetbrains.kotlin.idea.configuration.notifyOutdatedBundledCompilerIfNecessary
|
||||
import org.jetbrains.kotlin.idea.configuration.ui.notifications.notifyKotlinStyleUpdateIfNeeded
|
||||
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
|
||||
import org.jetbrains.kotlin.idea.util.runReadActionInSmartMode
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class KotlinConfigurationCheckerComponent(val project: Project) : ProjectComponent {
|
||||
private val syncDepth = AtomicInteger()
|
||||
|
||||
init {
|
||||
NotificationsConfiguration.getNotificationsConfiguration()
|
||||
.register(CONFIGURE_NOTIFICATION_GROUP_ID, NotificationDisplayType.STICKY_BALLOON, true)
|
||||
|
||||
val connection = project.messageBus.connect(project)
|
||||
connection.subscribe(ProjectDataImportListener.TOPIC, ProjectDataImportListener {
|
||||
notifyOutdatedBundledCompilerIfNecessary(project)
|
||||
})
|
||||
|
||||
notifyKotlinStyleUpdateIfNeeded(project)
|
||||
}
|
||||
|
||||
override fun projectOpened() {
|
||||
super.projectOpened()
|
||||
|
||||
StartupManager.getInstance(project).registerPostStartupActivity {
|
||||
performProjectPostOpenActions()
|
||||
}
|
||||
}
|
||||
|
||||
fun performProjectPostOpenActions() {
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
val modulesWithKotlinFiles = project.runReadActionInSmartMode {
|
||||
getModulesWithKotlinFiles(project)
|
||||
}
|
||||
for (module in modulesWithKotlinFiles) {
|
||||
runReadAction {
|
||||
if (project.isDisposed) return@runReadAction
|
||||
module.getAndCacheLanguageLevelByDependencies()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isSyncing: Boolean get() = syncDepth.get() > 0
|
||||
|
||||
fun syncStarted() {
|
||||
syncDepth.incrementAndGet()
|
||||
}
|
||||
|
||||
fun syncDone() {
|
||||
syncDepth.decrementAndGet()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CONFIGURE_NOTIFICATION_GROUP_ID = "Configure Kotlin in Project"
|
||||
|
||||
fun getInstance(project: Project): KotlinConfigurationCheckerComponent =
|
||||
project.getComponent(KotlinConfigurationCheckerComponent::class.java)
|
||||
?: error("Can't find ${KotlinConfigurationCheckerComponent::class} component")
|
||||
|
||||
fun getInstanceIfNotDisposed(project: Project): KotlinConfigurationCheckerComponent? {
|
||||
return runReadAction {
|
||||
if (!project.isDisposed) getInstance(project) else null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration.ui
|
||||
|
||||
typealias KotlinConfigurationCheckerService = KotlinConfigurationCheckerComponent
|
||||
-190
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.internal.makeBackup
|
||||
|
||||
import com.intellij.compiler.server.BuildManager
|
||||
import com.intellij.history.core.RevisionsCollector
|
||||
import com.intellij.history.integration.LocalHistoryImpl
|
||||
import com.intellij.history.integration.patches.PatchCreator
|
||||
import com.intellij.ide.actions.ShowFilePathAction
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vcs.changes.Change
|
||||
import com.intellij.util.WaitForProgressToShow
|
||||
import com.intellij.util.io.ZipUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinJvmBundle
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
class CreateIncrementalCompilationBackup : AnAction(KotlinJvmBundle.message("create.backup.for.debugging.kotlin.incremental.compilation")) {
|
||||
companion object {
|
||||
const val BACKUP_DIR_NAME = ".backup"
|
||||
const val PATCHES_TO_CREATE = 5
|
||||
|
||||
const val PATCHES_FRACTION = .25
|
||||
const val LOGS_FRACTION = .05
|
||||
const val PROJECT_SYSTEM_FRACTION = .05
|
||||
const val ZIP_FRACTION = 1.0 - PATCHES_FRACTION - LOGS_FRACTION - PROJECT_SYSTEM_FRACTION
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project!!
|
||||
val projectBaseDir = File(project.baseDir!!.path)
|
||||
val backupDir = File(FileUtil.createTempDirectory("makeBackup", null), BACKUP_DIR_NAME)
|
||||
|
||||
ProgressManager.getInstance().run(
|
||||
object : Task.Backgroundable(
|
||||
project,
|
||||
KotlinJvmBundle.message("creating.backup.for.debugging.kotlin.incremental.compilation"),
|
||||
true
|
||||
) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
createPatches(backupDir, project, indicator)
|
||||
copyLogs(backupDir, indicator)
|
||||
copyProjectSystemDir(backupDir, project, indicator)
|
||||
|
||||
zipProjectDir(backupDir, project, projectBaseDir, indicator)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun createPatches(backupDir: File, project: Project, indicator: ProgressIndicator) {
|
||||
runReadAction {
|
||||
val localHistoryImpl = LocalHistoryImpl.getInstanceImpl()!!
|
||||
val gateway = localHistoryImpl.gateway!!
|
||||
val localHistoryFacade = localHistoryImpl.facade
|
||||
|
||||
val revisionsCollector = RevisionsCollector(
|
||||
localHistoryFacade,
|
||||
gateway.createTransientRootEntry(),
|
||||
project.baseDir!!.path,
|
||||
project.locationHash,
|
||||
null
|
||||
)
|
||||
|
||||
var patchesCreated = 0
|
||||
|
||||
val patchesDir = File(backupDir, "patches")
|
||||
patchesDir.mkdirs()
|
||||
|
||||
val revisions = revisionsCollector.result!!
|
||||
for (rev in revisions) {
|
||||
val label = rev.label
|
||||
if (label != null && label.startsWith(HISTORY_LABEL_PREFIX)) {
|
||||
val patchFile = File(patchesDir, label.removePrefix(HISTORY_LABEL_PREFIX) + ".patch")
|
||||
|
||||
indicator.text = KotlinJvmBundle.message("creating.patch.0", patchFile)
|
||||
indicator.fraction = PATCHES_FRACTION * patchesCreated / PATCHES_TO_CREATE
|
||||
|
||||
val differences = revisions[0].getDifferencesWith(rev)!!
|
||||
val changes = differences.map { d ->
|
||||
Change(d.getLeftContentRevision(gateway), d.getRightContentRevision(gateway))
|
||||
}
|
||||
|
||||
PatchCreator.create(project, changes, patchFile.path, false, null)
|
||||
|
||||
if (++patchesCreated >= PATCHES_TO_CREATE) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLogs(backupDir: File, indicator: ProgressIndicator) {
|
||||
indicator.text = KotlinJvmBundle.message("copying.logs")
|
||||
indicator.fraction = PATCHES_FRACTION
|
||||
|
||||
val logsDir = File(backupDir, "logs")
|
||||
FileUtil.copyDir(File(PathManager.getLogPath()), logsDir)
|
||||
|
||||
indicator.fraction = PATCHES_FRACTION + LOGS_FRACTION
|
||||
}
|
||||
|
||||
private fun copyProjectSystemDir(backupDir: File, project: Project, indicator: ProgressIndicator) {
|
||||
indicator.text = KotlinJvmBundle.message("copying.project.s.system.dir")
|
||||
indicator.fraction = PATCHES_FRACTION
|
||||
|
||||
val projectSystemDir = File(backupDir, "project-system")
|
||||
FileUtil.copyDir(BuildManager.getInstance().getProjectSystemDirectory(project)!!, projectSystemDir)
|
||||
|
||||
indicator.fraction = PATCHES_FRACTION + LOGS_FRACTION + PROJECT_SYSTEM_FRACTION
|
||||
}
|
||||
|
||||
private fun zipProjectDir(backupDir: File, project: Project, projectDir: File, indicator: ProgressIndicator) {
|
||||
// files and relative paths
|
||||
|
||||
val files = ArrayList<Pair<File, String>>() // files and relative paths
|
||||
var totalBytes = 0L
|
||||
|
||||
for (dir in listOf(projectDir, backupDir.parentFile!!)) {
|
||||
FileUtil.processFilesRecursively(
|
||||
dir,
|
||||
/*processor*/ {
|
||||
if (it!!.isFile
|
||||
&& !it.name.endsWith(".hprof")
|
||||
&& !(it.name.startsWith("make_backup_") && it.name.endsWith(".zip"))
|
||||
) {
|
||||
|
||||
indicator.text = KotlinJvmBundle.message("scanning.project.dir.0", it)
|
||||
|
||||
files.add(Pair(it, FileUtil.getRelativePath(dir, it)!!))
|
||||
totalBytes += it.length()
|
||||
}
|
||||
true
|
||||
},
|
||||
/*directoryFilter*/ {
|
||||
val name = it!!.name
|
||||
name != ".git" && name != "out"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val backupFile = File(projectDir, "make_backup_" + SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(Date()) + ".zip")
|
||||
|
||||
|
||||
val zos = ZipOutputStream(FileOutputStream(backupFile))
|
||||
|
||||
var processedBytes = 0L
|
||||
|
||||
zos.use {
|
||||
for ((file, relativePath) in files) {
|
||||
indicator.text = KotlinJvmBundle.message("adding.file.to.backup.0", relativePath)
|
||||
indicator.fraction = PATCHES_FRACTION + LOGS_FRACTION + processedBytes.toDouble() / totalBytes * ZIP_FRACTION
|
||||
|
||||
ZipUtil.addFileToZip(zos, file, relativePath, null, null)
|
||||
|
||||
processedBytes += file.length()
|
||||
}
|
||||
}
|
||||
|
||||
FileUtil.delete(backupDir)
|
||||
|
||||
WaitForProgressToShow.runOrInvokeLaterAboveProgress(
|
||||
{
|
||||
ShowFilePathAction.showDialog(
|
||||
project,
|
||||
KotlinJvmBundle.message("successfully.created.backup.0", backupFile.absolutePath),
|
||||
KotlinJvmBundle.message("created.backup"),
|
||||
backupFile,
|
||||
null
|
||||
)
|
||||
}, null, project
|
||||
)
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
|
||||
import org.jetbrains.kotlin.idea.core.script.scriptRelatedModuleName
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.getModule
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition.Companion.STD_SCRIPT_SUFFIX
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent {
|
||||
private val LOG = Logger.getInstance(this.javaClass)
|
||||
|
||||
override fun projectOpened() {
|
||||
project.messageBus.connect().subscribe(ScratchFileListener.TOPIC, object : ScratchFileListener {
|
||||
override fun fileCreated(scratchFile: ScratchFile) {
|
||||
val ktFile = scratchFile.getPsiFile() as? KtFile ?: return
|
||||
val file = ktFile.virtualFile ?: return
|
||||
|
||||
if (file.extension != STD_SCRIPT_SUFFIX) {
|
||||
LOG.error("Kotlin Scratch file should have .kts extension. Cannot add scratch panel for ${file.path}")
|
||||
return
|
||||
}
|
||||
|
||||
scratchFile.addModuleListener { psiFile, module ->
|
||||
psiFile.virtualFile.scriptRelatedModuleName = module?.name
|
||||
|
||||
// Drop caches for old module
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
// Force re-highlighting
|
||||
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
|
||||
}
|
||||
|
||||
if (file.isKotlinWorksheet) {
|
||||
val module = file.getModule(project) ?: return
|
||||
scratchFile.setModule(module)
|
||||
} else {
|
||||
val module = file.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } ?: return
|
||||
scratchFile.setModule(module)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.kotlin.idea.scratch.actions
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.keymap.KeymapManager
|
||||
import com.intellij.openapi.keymap.KeymapUtil
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.task.ProjectTaskManager
|
||||
import org.jetbrains.kotlin.idea.KotlinJvmBundle
|
||||
import org.jetbrains.kotlin.idea.scratch.*
|
||||
import org.jetbrains.kotlin.idea.scratch.printDebugMessage
|
||||
import org.jetbrains.kotlin.idea.scratch.LOG as log
|
||||
|
||||
class RunScratchAction : ScratchAction(
|
||||
KotlinJvmBundle.message("scratch.run.button"),
|
||||
AllIcons.Actions.Execute
|
||||
) {
|
||||
|
||||
init {
|
||||
KeymapManager.getInstance().activeKeymap.getShortcuts("Kotlin.RunScratch").firstOrNull()?.let {
|
||||
templatePresentation.text += " (${KeymapUtil.getShortcutText(it)})"
|
||||
}
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
|
||||
|
||||
doAction(scratchFile, false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun doAction(scratchFile: ScratchFile, isAutoRun: Boolean) {
|
||||
val isRepl = scratchFile.options.isRepl
|
||||
val executor = (if (isRepl) scratchFile.replScratchExecutor else scratchFile.compilingScratchExecutor) ?: return
|
||||
|
||||
log.printDebugMessage("Run Action: isRepl = $isRepl")
|
||||
|
||||
fun executeScratch() {
|
||||
try {
|
||||
if (isAutoRun && executor is SequentialScratchExecutor) {
|
||||
executor.executeNew()
|
||||
} else {
|
||||
executor.execute()
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
executor.errorOccurs(KotlinJvmBundle.message("exception.occurs.during.run.scratch.action"), ex, true)
|
||||
}
|
||||
}
|
||||
|
||||
val isMakeBeforeRun = scratchFile.options.isMakeBeforeRun
|
||||
log.printDebugMessage("Run Action: isMakeBeforeRun = $isMakeBeforeRun")
|
||||
|
||||
val module = scratchFile.module
|
||||
log.printDebugMessage("Run Action: module = ${module?.name}")
|
||||
|
||||
if (!isAutoRun && module != null && isMakeBeforeRun) {
|
||||
val project = scratchFile.project
|
||||
ProjectTaskManager.getInstance(project).build(arrayOf(module)) { result ->
|
||||
if (result.isAborted || result.errors > 0) {
|
||||
executor.errorOccurs(KotlinJvmBundle.message("there.were.compilation.errors.in.module.0", module.name))
|
||||
}
|
||||
|
||||
if (DumbService.isDumb(project)) {
|
||||
DumbService.getInstance(project).smartInvokeLater {
|
||||
executeScratch()
|
||||
}
|
||||
} else {
|
||||
executeScratch()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
executeScratch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
super.update(e)
|
||||
|
||||
e.presentation.isEnabled = !ScratchCompilationSupport.isAnyInProgress()
|
||||
|
||||
if (e.presentation.isEnabled) {
|
||||
e.presentation.text = templatePresentation.text
|
||||
} else {
|
||||
e.presentation.text = KotlinJvmBundle.message("other.scratch.file.execution.is.in.progress")
|
||||
}
|
||||
|
||||
val project = e.project ?: return
|
||||
val scratchFile = getScratchFileFromSelectedEditor(project) ?: return
|
||||
|
||||
e.presentation.isVisible = !ScratchCompilationSupport.isInProgress(scratchFile)
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.vcs
|
||||
|
||||
import com.intellij.BundleBase.replaceMnemonicAmpersand
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.ui.Messages.NO
|
||||
import com.intellij.openapi.ui.Messages.YES
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vcs.CheckinProjectPanel
|
||||
import com.intellij.openapi.vcs.changes.CommitContext
|
||||
import com.intellij.openapi.vcs.changes.CommitExecutor
|
||||
import com.intellij.openapi.vcs.checkin.CheckinHandler
|
||||
import com.intellij.openapi.vcs.checkin.CheckinHandlerFactory
|
||||
import com.intellij.openapi.vcs.ui.RefreshableOnComponent
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.NonFocusableCheckBox
|
||||
import com.intellij.util.PairConsumer
|
||||
import org.jetbrains.kotlin.idea.KotlinJvmBundle
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
import java.awt.GridLayout
|
||||
import java.io.File
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
|
||||
private val BUNCH_PLUGIN_ID = PluginId.getId("org.jetbrains.bunch.tool.idea.plugin")
|
||||
|
||||
private var Project.bunchFileCheckEnabled: Boolean
|
||||
by NotNullableUserDataProperty(Key.create("IS_BUNCH_FILE_CHECK_ENABLED_KOTLIN"), !PluginManager.isPluginInstalled(BUNCH_PLUGIN_ID))
|
||||
|
||||
class BunchFileCheckInHandlerFactory : CheckinHandlerFactory() {
|
||||
override fun createHandler(panel: CheckinProjectPanel, commitContext: CommitContext): CheckinHandler {
|
||||
return BunchCheckInHandler(panel)
|
||||
}
|
||||
|
||||
class BunchCheckInHandler(private val checkInProjectPanel: CheckinProjectPanel) : CheckinHandler() {
|
||||
private val project get() = checkInProjectPanel.project
|
||||
|
||||
override fun getBeforeCheckinConfigurationPanel(): RefreshableOnComponent? {
|
||||
if (PluginManager.isPluginInstalled(BUNCH_PLUGIN_ID)) return null
|
||||
BunchFileUtils.bunchFile(project) ?: return null
|
||||
|
||||
val bunchFilesCheckBox = NonFocusableCheckBox(replaceMnemonicAmpersand(KotlinJvmBundle.message("check.bunch.files")))
|
||||
return object : RefreshableOnComponent {
|
||||
override fun getComponent(): JComponent {
|
||||
val panel = JPanel(GridLayout(1, 0))
|
||||
panel.add(bunchFilesCheckBox)
|
||||
return panel
|
||||
}
|
||||
|
||||
override fun refresh() {}
|
||||
override fun saveState() {
|
||||
project.bunchFileCheckEnabled = bunchFilesCheckBox.isSelected
|
||||
}
|
||||
|
||||
override fun restoreState() {
|
||||
bunchFilesCheckBox.isSelected = project.bunchFileCheckEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeCheckin(
|
||||
executor: CommitExecutor?,
|
||||
additionalDataConsumer: PairConsumer<Any, Any>?
|
||||
): ReturnResult {
|
||||
if (!project.bunchFileCheckEnabled) return ReturnResult.COMMIT
|
||||
|
||||
val extensions = BunchFileUtils.bunchExtension(project)?.toSet() ?: return ReturnResult.COMMIT
|
||||
|
||||
val forgottenFiles = HashSet<File>()
|
||||
val commitFiles = checkInProjectPanel.files.filter { it.isFile }.toSet()
|
||||
for (file in commitFiles) {
|
||||
if (file.extension in extensions) continue
|
||||
|
||||
val parent = file.parent ?: continue
|
||||
val name = file.name
|
||||
for (extension in extensions) {
|
||||
val bunchFile = File(parent, "$name.$extension")
|
||||
if (bunchFile !in commitFiles && bunchFile.exists()) {
|
||||
forgottenFiles.add(bunchFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forgottenFiles.isEmpty()) return ReturnResult.COMMIT
|
||||
|
||||
val projectBaseFile = File(project.basePath)
|
||||
var filePaths = forgottenFiles.map { it.relativeTo(projectBaseFile).path }.sorted()
|
||||
if (filePaths.size > 15) {
|
||||
filePaths = filePaths.take(15) + "..."
|
||||
}
|
||||
|
||||
when (Messages.showYesNoCancelDialog(
|
||||
project,
|
||||
KotlinJvmBundle.message(
|
||||
"several.bunch.files.haven.t.been.updated.0.do.you.want.to.review.them.before.commit",
|
||||
filePaths.joinToString("\n")
|
||||
),
|
||||
KotlinJvmBundle.message("button.text.forgotten.bunch.files"),
|
||||
KotlinJvmBundle.message("button.text.review"),
|
||||
KotlinJvmBundle.message("button.text.commit"),
|
||||
CommonBundle.getCancelButtonText(),
|
||||
Messages.getWarningIcon()
|
||||
)) {
|
||||
YES -> {
|
||||
return ReturnResult.CLOSE_WINDOW
|
||||
}
|
||||
NO -> return ReturnResult.COMMIT
|
||||
}
|
||||
|
||||
return ReturnResult.CANCEL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object BunchFileUtils {
|
||||
fun bunchFile(project: Project): VirtualFile? {
|
||||
val baseDir = project.baseDir ?: return null
|
||||
return baseDir.findChild(".bunch")
|
||||
}
|
||||
|
||||
fun bunchExtension(project: Project): List<String>? {
|
||||
val bunchFile: VirtualFile = bunchFile(project) ?: return null
|
||||
val file = File(bunchFile.path)
|
||||
if (!file.exists()) return null
|
||||
|
||||
val lines = file.readLines().map { it.trim() }.filter { it.isNotEmpty() }
|
||||
if (lines.size <= 1) return null
|
||||
|
||||
return lines.drop(1).map { it.split('_').first() }
|
||||
}
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.maven
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
internal val Module.kotlinImporterComponent: KotlinImporterComponent
|
||||
get() = getComponent(KotlinImporterComponent::class.java) ?: throw IllegalStateException("No maven importer state configured")
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.maven
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.idea.maven.project.MavenImportListener
|
||||
import org.jetbrains.idea.maven.project.MavenProject
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService
|
||||
import org.jetbrains.kotlin.idea.configuration.notifyOutdatedBundledCompilerIfNecessary
|
||||
import org.jetbrains.kotlin.idea.util.ProgressIndicatorUtils.runUnderDisposeAwareIndicator
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class MavenImportListener(val project: Project) : MavenProjectsManager.Listener {
|
||||
init {
|
||||
project.messageBus.connect(project).subscribe(
|
||||
MavenImportListener.TOPIC,
|
||||
MavenImportListener { _: Collection<MavenProject>, _: List<Module> ->
|
||||
runUnderDisposeAwareIndicator(project) {
|
||||
notifyOutdatedBundledCompilerIfNecessary(project)
|
||||
KotlinMigrationProjectService.getInstance(project).onImportFinished()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
MavenProjectsManager.getInstance(project)?.addManagerListener(this)
|
||||
}
|
||||
|
||||
override fun projectsScheduled() {
|
||||
runUnderDisposeAwareIndicator(project) {
|
||||
KotlinMigrationProjectService.getInstance(project).onImportAboutToStart()
|
||||
}
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.tools.projectWizard.wizard.service
|
||||
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.service.BuildSystemAvailabilityWizardService
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
|
||||
|
||||
class IdeaBuildSystemAvailabilityWizardService : BuildSystemAvailabilityWizardService, IdeaWizardService {
|
||||
override fun isAvailable(buildSystemType: BuildSystemType): Boolean = when {
|
||||
buildSystemType.isGradle -> isPluginEnabled("org.jetbrains.plugins.gradle")
|
||||
buildSystemType == BuildSystemType.Maven -> isPluginEnabled("org.jetbrains.idea.maven")
|
||||
else -> true
|
||||
}
|
||||
|
||||
private fun isPluginEnabled(id: String) =
|
||||
PluginManager.getPlugin(PluginId.getId(id))?.isEnabled == true
|
||||
}
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.tools.projectWizard.wizard.service
|
||||
|
||||
import com.intellij.execution.executors.DefaultRunExecutor
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
|
||||
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings
|
||||
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.Reader
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.TaskResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.andThen
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.safe
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.service.ProjectImportingWizardService
|
||||
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.ModuleIR
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.isGradle
|
||||
import org.jetbrains.plugins.gradle.action.ImportProjectFromScriptAction
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.nio.file.Path
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class IdeaGradleWizardService(private val project: Project) : ProjectImportingWizardService,
|
||||
IdeaWizardService {
|
||||
override fun isSuitableFor(buildSystemType: BuildSystemType): Boolean =
|
||||
buildSystemType.isGradle
|
||||
|
||||
// We have to call action directly as there is no common way
|
||||
// to import Gradle project in all IDEAs from 183 to 193
|
||||
override fun importProject(
|
||||
reader: Reader,
|
||||
path: Path,
|
||||
modulesIrs: List<ModuleIR>,
|
||||
buildSystem: BuildSystemType
|
||||
): TaskResult<Unit> = performImport(path) andThen createGradleWrapper(path)
|
||||
|
||||
private fun performImport(path: Path) = safe {
|
||||
val virtualFile = LocalFileSystem.getInstance().findFileByPath(path.toString())
|
||||
?: error("No virtual file found for path $path")
|
||||
val dataContext = SimpleDataContext.getSimpleContext(
|
||||
mapOf(
|
||||
CommonDataKeys.PROJECT.name to project,
|
||||
CommonDataKeys.VIRTUAL_FILE.name to virtualFile
|
||||
),
|
||||
null
|
||||
)
|
||||
val action = ImportProjectFromScriptAction()
|
||||
val event = AnActionEvent.createFromAnAction(
|
||||
action,
|
||||
/*event=*/ null,
|
||||
ActionPlaces.UNKNOWN,
|
||||
dataContext
|
||||
)
|
||||
action.actionPerformed(event)
|
||||
}
|
||||
|
||||
|
||||
private fun createGradleWrapper(path: Path) = safe {
|
||||
val settings = ExternalSystemTaskExecutionSettings().apply {
|
||||
externalProjectPath = path.toString()
|
||||
taskNames = listOf(WRAPPER_TASK_NAME)
|
||||
externalSystemIdString = GradleConstants.SYSTEM_ID.id
|
||||
}
|
||||
|
||||
ExternalSystemUtil.runTask(
|
||||
settings,
|
||||
DefaultRunExecutor.EXECUTOR_ID,
|
||||
project,
|
||||
GradleConstants.SYSTEM_ID,
|
||||
/*callback=*/ null,
|
||||
ProgressExecutionMode.NO_PROGRESS_ASYNC
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@NonNls
|
||||
private const val WRAPPER_TASK_NAME = "wrapper"
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionGroup
|
||||
import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl
|
||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx
|
||||
|
||||
// needed for <=192 to work correctly
|
||||
abstract class ActionToolbarImplWrapper(
|
||||
place: String,
|
||||
actionGroup: ActionGroup,
|
||||
horizontal: Boolean
|
||||
) : ActionToolbarImpl(place, actionGroup, horizontal, KeymapManagerEx.getInstanceEx())
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.console
|
||||
|
||||
import com.intellij.execution.ExecutionManager
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.ui.RunContentDescriptor
|
||||
import com.intellij.openapi.compiler.CompilerManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.task.ProjectTaskManager
|
||||
|
||||
class ConsoleCompilerHelper(
|
||||
private val project: Project,
|
||||
private val module: Module,
|
||||
private val executor: Executor,
|
||||
private val contentDescriptor: RunContentDescriptor
|
||||
) {
|
||||
|
||||
fun moduleIsUpToDate(): Boolean {
|
||||
val compilerManager = CompilerManager.getInstance(project)
|
||||
val compilerScope = compilerManager.createModuleCompileScope(module, true)
|
||||
return compilerManager.isUpToDate(compilerScope)
|
||||
}
|
||||
|
||||
fun compileModule() {
|
||||
if (ExecutionManager.getInstance(project).contentManager.removeRunContent(executor, contentDescriptor)) {
|
||||
ProjectTaskManager.getInstance(project).build(arrayOf(module)) { result ->
|
||||
if (!module.isDisposed) {
|
||||
KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = result.errors > 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.test;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.module.StdModuleTypes;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class KotlinLightProjectDescriptor extends LightProjectDescriptor {
|
||||
protected KotlinLightProjectDescriptor() {
|
||||
}
|
||||
|
||||
public static final KotlinLightProjectDescriptor INSTANCE = new KotlinLightProjectDescriptor();
|
||||
|
||||
@Override
|
||||
public ModuleType getModuleType() {
|
||||
return StdModuleTypes.JAVA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sdk getSdk() {
|
||||
return PluginTestCaseBase.mockJdk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
|
||||
configureModule(module, model);
|
||||
}
|
||||
|
||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model) {
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.test
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.EditorTracker
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
fun editorTrackerProjectOpened(project: Project) {
|
||||
project.getComponent(EditorTracker::class.java)?.projectOpened()
|
||||
}
|
||||
|
||||
// FIX ME WHEN BUNCH 193 REMOVED
|
||||
fun runPostStartupActivitiesOnce(project: Project) {
|
||||
(StartupManager.getInstance(project) as StartupManagerImpl).runPostStartupActivities()
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||
|
||||
import com.intellij.debugger.engine.SuspendContextImpl
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
|
||||
import com.intellij.debugger.ui.breakpoints.RunToCursorBreakpoint
|
||||
import com.sun.jdi.Location
|
||||
import com.sun.jdi.Method
|
||||
import com.sun.jdi.event.LocatableEvent
|
||||
import org.jetbrains.kotlin.idea.debugger.safeLocation
|
||||
|
||||
object CoroutineBreakpointFacility : AbstractCoroutineBreakpointFacility() {
|
||||
override fun installCoroutineResumedBreakpoint(context: SuspendContextImpl, location: Location, method: Method): Boolean {
|
||||
val debugProcess = context.debugProcess
|
||||
val project = debugProcess.project
|
||||
|
||||
val methodLocation = method.location()
|
||||
val position = debugProcess.positionManager.getSourcePosition(methodLocation) ?: return false
|
||||
|
||||
val breakpoint = object : RunToCursorBreakpoint(project, position, false) {
|
||||
override fun processLocatableEvent(action: SuspendContextCommandImpl, event: LocatableEvent?): Boolean {
|
||||
val result = super.processLocatableEvent(action, event)
|
||||
if (result) {
|
||||
stepOverSuspendSwitch(action, debugProcess)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
breakpoint.setSuspendPolicy(context)
|
||||
applyEmptyThreadFilter(debugProcess)
|
||||
breakpoint.createRequest(debugProcess)
|
||||
debugProcess.setRunToCursorBreakpoint(breakpoint)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun SuspendContextImpl.getLocationCompat(): Location? {
|
||||
return this.frameProxy?.safeLocation()
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.testFramework
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener
|
||||
import com.intellij.testFramework.PlatformTestUtil.maskExtensions
|
||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import kotlin.test.assertNull
|
||||
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener.EP_NAME as EP
|
||||
|
||||
interface GradleProcessOutputInterceptor {
|
||||
companion object {
|
||||
fun getInstance(): GradleProcessOutputInterceptor? = EP.extensions.firstIsInstanceOrNull()
|
||||
|
||||
fun install(parentDisposable: Disposable) {
|
||||
val installedExtensions = EP.extensions
|
||||
|
||||
assertNull(
|
||||
installedExtensions.firstIsInstanceOrNull<GradleProcessOutputInterceptor>(),
|
||||
"Another ${GradleProcessOutputInterceptor::class.java.simpleName} is already installed"
|
||||
)
|
||||
|
||||
maskExtensions(
|
||||
EP,
|
||||
listOf(GradleProcessOutputInterceptorImpl()) + installedExtensions,
|
||||
parentDisposable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun reset()
|
||||
fun getOutput(): String
|
||||
}
|
||||
|
||||
private class GradleProcessOutputInterceptorImpl : GradleProcessOutputInterceptor, ExternalSystemTaskNotificationListener {
|
||||
private val buffer = StringBuilder()
|
||||
|
||||
override fun onTaskOutput(id: ExternalSystemTaskId, text: String, stdOut: Boolean) {
|
||||
if (id.projectSystemId == GRADLE_SYSTEM_ID && text.isNotEmpty())
|
||||
buffer.append(text)
|
||||
}
|
||||
|
||||
override fun reset() = buffer.setLength(0)
|
||||
override fun getOutput() = buffer.toString()
|
||||
|
||||
override fun onSuccess(id: ExternalSystemTaskId) = Unit
|
||||
override fun onFailure(id: ExternalSystemTaskId, e: Exception) = Unit
|
||||
override fun onStatusChange(event: ExternalSystemTaskNotificationEvent) = Unit
|
||||
override fun onCancel(id: ExternalSystemTaskId) = Unit
|
||||
override fun onEnd(id: ExternalSystemTaskId) = Unit
|
||||
override fun beforeCancel(id: ExternalSystemTaskId) = Unit
|
||||
override fun onQueued(id: ExternalSystemTaskId, workingDir: String?) = Unit
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
override fun onStart(id: ExternalSystemTaskId) = Unit
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.testFramework
|
||||
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
||||
import com.intellij.lang.LanguageAnnotators
|
||||
import com.intellij.lang.LanguageExtensionPoint
|
||||
import com.intellij.lang.annotation.Annotator
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.impl.PsiDocumentManagerBase
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.HintType
|
||||
import org.jetbrains.kotlin.idea.test.runPostStartupActivitiesOnce
|
||||
|
||||
fun commitAllDocuments() {
|
||||
val fileDocumentManager = FileDocumentManager.getInstance()
|
||||
runInEdtAndWait {
|
||||
fileDocumentManager.saveAllDocuments()
|
||||
}
|
||||
|
||||
ProjectManagerEx.getInstanceEx().openProjects.forEach { project ->
|
||||
val psiDocumentManagerBase = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase
|
||||
|
||||
runInEdtAndWait {
|
||||
psiDocumentManagerBase.clearUncommittedDocuments()
|
||||
psiDocumentManagerBase.commitAllDocuments()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun commitDocument(project: Project, document: Document) {
|
||||
val psiDocumentManagerBase = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase
|
||||
runInEdtAndWait {
|
||||
psiDocumentManagerBase.commitDocument(document)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveDocument(document: Document) {
|
||||
val fileDocumentManager = FileDocumentManager.getInstance()
|
||||
|
||||
runInEdtAndWait {
|
||||
fileDocumentManager.saveDocument(document)
|
||||
}
|
||||
}
|
||||
|
||||
fun enableHints(enable: Boolean) =
|
||||
HintType.values().forEach { it.option.set(enable) }
|
||||
|
||||
fun dispatchAllInvocationEvents() {
|
||||
runInEdtAndWait {
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
}
|
||||
}
|
||||
|
||||
fun loadProjectWithName(path: String, name: String): Project? =
|
||||
ProjectManagerEx.getInstanceEx().loadProject(name, path)
|
||||
|
||||
fun TestApplicationManager.closeProject(project: Project) {
|
||||
dispatchAllInvocationEvents()
|
||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||
projectManagerEx.forceCloseProjectEx(project, true)
|
||||
}
|
||||
|
||||
fun runStartupActivities(project: Project) {
|
||||
with(StartupManager.getInstance(project) as StartupManagerImpl) {
|
||||
scheduleInitialVfsRefresh()
|
||||
runStartupActivities()
|
||||
}
|
||||
runPostStartupActivitiesOnce(project)
|
||||
}
|
||||
|
||||
fun waitForAllEditorsFinallyLoaded(project: Project) {
|
||||
// routing is obsolete in 192
|
||||
}
|
||||
|
||||
fun replaceWithCustomHighlighter(parentDisposable: Disposable, fromImplementationClass: String, toImplementationClass: String) {
|
||||
val pointName = ExtensionPointName.create<LanguageExtensionPoint<Annotator>>(LanguageAnnotators.EP_NAME)
|
||||
val extensionPoint = pointName.getPoint(null)
|
||||
|
||||
val point = LanguageExtensionPoint<Annotator>()
|
||||
point.language = "kotlin"
|
||||
point.implementationClass = toImplementationClass
|
||||
|
||||
val extensions = extensionPoint.extensions
|
||||
val filteredExtensions =
|
||||
extensions.filter { it.language != "kotlin" || it.implementationClass != fromImplementationClass }
|
||||
.toList()
|
||||
// custom highlighter is already registered if filteredExtensions has the same size as extensions
|
||||
if (filteredExtensions.size < extensions.size) {
|
||||
PlatformTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2" url="http://kotlinlang.org" allow-bundled-update="true">
|
||||
<id>org.jetbrains.kotlin</id>
|
||||
|
||||
<name>Kotlin</name>
|
||||
<description><![CDATA[
|
||||
The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
<br>
|
||||
<a href="http://kotlinlang.org/docs/tutorials/getting-started.html">Getting Started in IntelliJ IDEA</a><br>
|
||||
<a href="http://kotlinlang.org/docs/tutorials/kotlin-android.html">Getting Started in Android Studio</a><br>
|
||||
<a href="http://slack.kotlinlang.org/">Public Slack</a><br>
|
||||
<a href="https://youtrack.jetbrains.com/issues/KT">Issue tracker</a><br>
|
||||
]]></description>
|
||||
<version>@snapshot@</version>
|
||||
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
|
||||
|
||||
<idea-version since-build="192.7142.36" until-build="192.*"/>
|
||||
|
||||
<change-notes><![CDATA[
|
||||
<h3>1.4.0</h3>
|
||||
Released: <b>August 17, 2020</b>
|
||||
<ul>
|
||||
<li>New compiler with better type inference.</li>
|
||||
<li>IR backends for JVM and JS in Alpha mode (<a href="https://kotlinlang.org/docs/reference/whatsnew14.html#unified-backends-and-extensibility">requires opt-in</a>).</li>
|
||||
<li>A new flexible Kotlin Project Wizard for easy creation and configuration of different types of projects.</li>
|
||||
<li>New IDE functionality to debug coroutines.</li>
|
||||
<li>IDE performance improvements: many actions, such as project opening and autocomplete suggestions now complete up to 4 times faster.</li>
|
||||
<li>New language features such as SAM conversions, trailing comma, and other.</li>
|
||||
<li>Type annotations in the JVM bytecode and new modes for generating default interfaces in Kotlin/JVM.</li>
|
||||
<li>New Gradle DSL for Kotlin/JS.</li>
|
||||
<li>Improved performance and interop with Swift and Objective-C in Kotlin/Native.</li>
|
||||
<li>Support for sharing code in several targets thanks to the hierarchical structure in multiplatform projects.</li>
|
||||
<li>New collection operators, delegated properties improvements, the double-ended queue implementation ArrayDeque, and much more new things in the standard library.</li>
|
||||
</ul>
|
||||
For more details, see <a href="https://kotlinlang.org/docs/reference/whatsnew14.html?utm_source=product&utm_medium=link">What’s New in Kotlin 1.4.0</a> and <a href="http://blog.jetbrains.com/kotlin/2020/08/kotlin-1-4-released-with-a-focus-on-quality-and-performance/?utm_source=product&utm_medium=link">this blog post</a>.
|
||||
<br><br>
|
||||
To get the most out of the changes and improvements introduced in Kotlin 1.4, join our <a href="https://kotlinlang.org/lp/event-14/">Online Event</a> where you will be able to enjoy four days of Kotlin talks, Q&As with the Kotlin team, and more.
|
||||
]]>
|
||||
</change-notes>
|
||||
|
||||
<depends>com.intellij.modules.platform</depends>
|
||||
|
||||
<depends optional="true" config-file="junit.xml">JUnit</depends>
|
||||
<depends optional="true" config-file="gradle.xml">org.jetbrains.plugins.gradle</depends>
|
||||
<depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle.java</depends>
|
||||
<depends optional="true" config-file="kotlin-gradle-testing.xml">org.jetbrains.plugins.gradle.java</depends>
|
||||
<depends optional="true" config-file="gradle-groovy.xml">org.intellij.groovy</depends>
|
||||
<depends optional="true" config-file="maven-common.xml">org.jetbrains.idea.maven</depends>
|
||||
<depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
|
||||
<depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
|
||||
<depends optional="true" config-file="coverage.xml">Coverage</depends>
|
||||
<depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
|
||||
<depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
|
||||
<depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
|
||||
<depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
|
||||
|
||||
<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
|
||||
|
||||
<!-- CIDR-PLUGIN-PLACEHOLDER-START -->
|
||||
<depends>com.intellij.modules.idea</depends>
|
||||
<depends>com.intellij.modules.java</depends>
|
||||
<depends optional="true" config-file="javaScriptDebug.xml">JavaScriptDebugger</depends>
|
||||
<depends optional="true" config-file="kotlin-copyright.xml">com.intellij.copyright</depends>
|
||||
<depends optional="true" config-file="injection.xml">org.intellij.intelliLang</depends>
|
||||
<!-- CIDR-PLUGIN-PLACEHOLDER-END -->
|
||||
|
||||
<xi:include href="plugin-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<!-- CIDR-PLUGIN-EXCLUDE-START -->
|
||||
<xi:include href="jvm-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
<xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
<!-- CIDR-PLUGIN-EXCLUDE-END -->
|
||||
|
||||
<xi:include href="native-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
<xi:include href="native.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<xi:include href="tipsAndTricks.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<xi:include href="kotlinx-serialization.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<xi:include href="scripting-support.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<application-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.versions.KotlinUpdatePluginComponent</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.completion.LookupCancelWatcher</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.caches.KotlinPackageContentModificationListener</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectComponent</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Factory</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory</implementation-class>
|
||||
<skipForDefaultProject/>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Factory</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<application-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.PluginStartupComponent</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<xi:include href="plugin-kotlin-extensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij.jvm">
|
||||
<declarationSearcher language="kotlin" implementationClass="org.jetbrains.kotlin.idea.jvm.KotlinDeclarationSearcher"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.j2k" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.editor" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.migrationTool" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.new.wizard" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.gradle.performance" version="1"/>
|
||||
<statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.IDESettingsFUSCollector"/>
|
||||
<statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.formatter.KotlinFormatterUsageCollector"/>
|
||||
<statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.ProjectConfigurationCollector"/>
|
||||
|
||||
<fileTypeUsageSchemaDescriptor schema="Gradle Script" implementationClass="org.jetbrains.kotlin.idea.core.script.KotlinGradleScriptFileTypeSchemaDetector"/>
|
||||
<defaultLiveTemplatesProvider implementation="org.jetbrains.kotlin.idea.liveTemplates.KotlinLiveTemplatesProvider"/>
|
||||
|
||||
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.core.KotlinFileTypeFactory"/>
|
||||
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinJavaScriptMetaFileTypeFactory"/>
|
||||
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinBuiltInFileTypeFactory"/>
|
||||
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinModuleFileFactory"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<focusModeProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.core.KotlinFocusModeProvider" />
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
@@ -1,21 +0,0 @@
|
||||
<idea-plugin>
|
||||
<application-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.JvmPluginStartupComponent</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.compiler.KotlinCompilerManager</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.scratch.ScratchFileModuleInfoProvider</implementation-class>
|
||||
</component>
|
||||
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.configuration.ui.KotlinConfigurationCheckerComponent</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
</idea-plugin>
|
||||
@@ -1,13 +0,0 @@
|
||||
<idea-plugin>
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.maven.MavenImportListener</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<module-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.maven.KotlinImporterComponent</implementation-class>
|
||||
</component>
|
||||
</module-components>
|
||||
</idea-plugin>
|
||||
@@ -1,19 +0,0 @@
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<application-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.kotlin.ide.konan.KotlinNativeABICompatibilityChecker</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<fileTypeFactory implementation="org.jetbrains.kotlin.ide.konan.KotlinNativeFileTypeFactory"/>
|
||||
</extensions>
|
||||
|
||||
<depends optional="true" config-file="native-run-configuration.xml">org.jetbrains.plugins.gradle</depends>
|
||||
</idea-plugin>
|
||||
@@ -1,386 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonIOException
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.intellij.ide.actions.ShowFilePathAction
|
||||
import com.intellij.ide.plugins.*
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.notification.NotificationDisplayType
|
||||
import com.intellij.notification.NotificationGroup
|
||||
import com.intellij.notification.NotificationListener
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.*
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.updateSettings.impl.PluginDownloader
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.Alarm
|
||||
import com.intellij.util.io.HttpRequests
|
||||
import com.intellij.util.text.VersionComparatorUtil
|
||||
import org.jetbrains.kotlin.idea.update.verify
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.net.URLEncoder
|
||||
import java.time.DateTimeException
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneOffset
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
sealed class PluginUpdateStatus {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
|
||||
object LatestVersionInstalled : PluginUpdateStatus()
|
||||
|
||||
class Update(
|
||||
val pluginDescriptor: IdeaPluginDescriptor,
|
||||
val hostToInstallFrom: String?
|
||||
) : PluginUpdateStatus()
|
||||
|
||||
class CheckFailed(val message: String, val detail: String? = null) : PluginUpdateStatus()
|
||||
|
||||
class Unverified(val verifierName: String, val reason: String?, val updateStatus: Update) : PluginUpdateStatus()
|
||||
|
||||
fun mergeWith(other: PluginUpdateStatus): PluginUpdateStatus {
|
||||
if (other is Update) {
|
||||
when (this) {
|
||||
is LatestVersionInstalled -> {
|
||||
return other
|
||||
}
|
||||
is Update -> {
|
||||
if (VersionComparatorUtil.compare(other.pluginDescriptor.version, pluginDescriptor.version) > 0) {
|
||||
return other
|
||||
}
|
||||
}
|
||||
is CheckFailed, is Unverified -> {
|
||||
// proceed to return this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromException(message: String, e: Exception): PluginUpdateStatus {
|
||||
val writer = StringWriter()
|
||||
e.printStackTrace(PrintWriter(writer))
|
||||
return CheckFailed(message, writer.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinPluginUpdater : Disposable {
|
||||
private var updateDelay = INITIAL_UPDATE_DELAY
|
||||
private val alarm = Alarm(Alarm.ThreadToUse.POOLED_THREAD, this)
|
||||
private val notificationGroup = NotificationGroup(
|
||||
KotlinBundle.message("plugin.updater.notification.group"),
|
||||
NotificationDisplayType.STICKY_BALLOON, true
|
||||
)
|
||||
|
||||
@Volatile
|
||||
private var checkQueued = false
|
||||
|
||||
@Volatile
|
||||
private var lastUpdateStatus: PluginUpdateStatus? = null
|
||||
|
||||
fun kotlinFileEdited(file: VirtualFile) {
|
||||
if (!file.isInLocalFileSystem) return
|
||||
if (ApplicationManager.getApplication().isUnitTestMode || ApplicationManager.getApplication().isHeadlessEnvironment) return
|
||||
if (!UpdateSettings.getInstance().isCheckNeeded) return
|
||||
|
||||
val lastUpdateTime = java.lang.Long.parseLong(PropertiesComponent.getInstance().getValue(PROPERTY_NAME, "0"))
|
||||
if (lastUpdateTime == 0L || System.currentTimeMillis() - lastUpdateTime > CACHED_REQUEST_DELAY) {
|
||||
queueUpdateCheck { updateStatus ->
|
||||
when (updateStatus) {
|
||||
is PluginUpdateStatus.Update -> notifyPluginUpdateAvailable(updateStatus)
|
||||
is PluginUpdateStatus.CheckFailed -> LOG.info("Plugin update check failed: ${updateStatus.message}, details: ${updateStatus.detail}")
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun queueUpdateCheck(callback: (PluginUpdateStatus) -> Boolean) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread()
|
||||
if (!checkQueued) {
|
||||
checkQueued = true
|
||||
alarm.addRequest({ updateCheck(callback) }, updateDelay)
|
||||
updateDelay *= 2 // exponential backoff
|
||||
}
|
||||
}
|
||||
|
||||
fun runUpdateCheck(callback: (PluginUpdateStatus) -> Boolean) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
updateCheck(callback)
|
||||
}
|
||||
}
|
||||
|
||||
fun runCachedUpdate(callback: (PluginUpdateStatus) -> Boolean) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread()
|
||||
val cachedStatus = lastUpdateStatus
|
||||
if (cachedStatus != null && System.currentTimeMillis() - cachedStatus.timestamp < CACHED_REQUEST_DELAY) {
|
||||
if (cachedStatus !is PluginUpdateStatus.CheckFailed) {
|
||||
callback(cachedStatus)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
queueUpdateCheck(callback)
|
||||
}
|
||||
|
||||
private fun updateCheck(callback: (PluginUpdateStatus) -> Boolean) {
|
||||
var updateStatus: PluginUpdateStatus
|
||||
if (KotlinPluginUtil.isSnapshotVersion() || KotlinPluginUtil.isPatched()) {
|
||||
updateStatus = PluginUpdateStatus.LatestVersionInstalled
|
||||
} else {
|
||||
try {
|
||||
updateStatus = checkUpdatesInMainRepository()
|
||||
|
||||
for (host in RepositoryHelper.getPluginHosts().filterNotNull()) {
|
||||
val customUpdateStatus = checkUpdatesInCustomRepository(host)
|
||||
updateStatus = updateStatus.mergeWith(customUpdateStatus)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
updateStatus = PluginUpdateStatus.fromException(KotlinBundle.message("plugin.updater.error.check.failed"), e)
|
||||
}
|
||||
}
|
||||
|
||||
lastUpdateStatus = updateStatus
|
||||
checkQueued = false
|
||||
|
||||
if (updateStatus is PluginUpdateStatus.Update) {
|
||||
updateStatus = verify(updateStatus)
|
||||
}
|
||||
|
||||
if (updateStatus !is PluginUpdateStatus.CheckFailed) {
|
||||
recordSuccessfulUpdateCheck()
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater({
|
||||
callback(updateStatus)
|
||||
}, ModalityState.any())
|
||||
}
|
||||
|
||||
private fun initPluginDescriptor(newVersion: String): IdeaPluginDescriptor {
|
||||
val originalPlugin = PluginManager.getPlugin(KotlinPluginUtil.KOTLIN_PLUGIN_ID)!!
|
||||
return PluginNode(KotlinPluginUtil.KOTLIN_PLUGIN_ID).apply {
|
||||
version = newVersion
|
||||
name = originalPlugin.name
|
||||
description = originalPlugin.description
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkUpdatesInMainRepository(): PluginUpdateStatus {
|
||||
val buildNumber = ApplicationInfo.getInstance().apiVersion
|
||||
val currentVersion = KotlinPluginUtil.getPluginVersion()
|
||||
val os = URLEncoder.encode(SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION, CharsetToolkit.UTF8)
|
||||
val uid = PermanentInstallationID.get()
|
||||
val pluginId = KotlinPluginUtil.KOTLIN_PLUGIN_ID.idString
|
||||
val url =
|
||||
"https://plugins.jetbrains.com/plugins/list?pluginId=$pluginId&build=$buildNumber&pluginVersion=$currentVersion&os=$os&uuid=$uid"
|
||||
val responseDoc = HttpRequests.request(url).connect {
|
||||
JDOMUtil.load(it.inputStream)
|
||||
}
|
||||
if (responseDoc.name != "plugin-repository") {
|
||||
return PluginUpdateStatus.CheckFailed(
|
||||
KotlinBundle.message("plugin.updater.error.unexpected.repository.response"),
|
||||
JDOMUtil.writeElement(responseDoc, "\n")
|
||||
)
|
||||
}
|
||||
if (responseDoc.children.isEmpty()) {
|
||||
// No plugin version compatible with current IDEA build; don't retry updates
|
||||
return PluginUpdateStatus.LatestVersionInstalled
|
||||
}
|
||||
val newVersion = responseDoc.getChild("category")?.getChild("idea-plugin")?.getChild("version")?.text
|
||||
?: return PluginUpdateStatus.CheckFailed(
|
||||
KotlinBundle.message("plugin.updater.error.cant.find.plugin.version"),
|
||||
JDOMUtil.writeElement(responseDoc, "\n")
|
||||
)
|
||||
val pluginDescriptor = initPluginDescriptor(newVersion)
|
||||
return updateIfNotLatest(pluginDescriptor, null)
|
||||
}
|
||||
|
||||
private fun checkUpdatesInCustomRepository(host: String): PluginUpdateStatus {
|
||||
val plugins = try {
|
||||
RepositoryHelper.loadPlugins(host, null)
|
||||
} catch (e: Exception) {
|
||||
return PluginUpdateStatus.fromException(KotlinBundle.message("plugin.updater.error.custom.repository", host), e)
|
||||
}
|
||||
|
||||
val kotlinPlugin = plugins.find { pluginDescriptor ->
|
||||
pluginDescriptor.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID && PluginManagerCore.isCompatible(pluginDescriptor)
|
||||
} ?: return PluginUpdateStatus.LatestVersionInstalled
|
||||
|
||||
return updateIfNotLatest(kotlinPlugin, host)
|
||||
}
|
||||
|
||||
private fun updateIfNotLatest(kotlinPlugin: IdeaPluginDescriptor, host: String?): PluginUpdateStatus {
|
||||
if (VersionComparatorUtil.compare(kotlinPlugin.version, KotlinPluginUtil.getPluginVersion()) <= 0) {
|
||||
return PluginUpdateStatus.LatestVersionInstalled
|
||||
}
|
||||
|
||||
return PluginUpdateStatus.Update(kotlinPlugin, host)
|
||||
}
|
||||
|
||||
private fun recordSuccessfulUpdateCheck() {
|
||||
PropertiesComponent.getInstance().setValue(PROPERTY_NAME, System.currentTimeMillis().toString())
|
||||
updateDelay = INITIAL_UPDATE_DELAY
|
||||
}
|
||||
|
||||
private fun notifyPluginUpdateAvailable(update: PluginUpdateStatus.Update) {
|
||||
val notification = notificationGroup.createNotification(
|
||||
KotlinBundle.message("plugin.updater.notification.title"),
|
||||
KotlinBundle.message("plugin.updater.notification.message", update.pluginDescriptor.version),
|
||||
NotificationType.INFORMATION,
|
||||
NotificationListener { notification, _ ->
|
||||
notification.expire()
|
||||
installPluginUpdate(update) {
|
||||
notifyPluginUpdateAvailable(update)
|
||||
}
|
||||
})
|
||||
|
||||
notification.notify(null)
|
||||
}
|
||||
|
||||
fun installPluginUpdate(
|
||||
update: PluginUpdateStatus.Update,
|
||||
successCallback: () -> Unit = {}, cancelCallback: () -> Unit = {}, errorCallback: () -> Unit = {}
|
||||
) {
|
||||
val descriptor = update.pluginDescriptor
|
||||
val pluginDownloader = PluginDownloader.createDownloader(descriptor, update.hostToInstallFrom, null)
|
||||
ProgressManager.getInstance().run(object : Task.Backgroundable(
|
||||
null, KotlinBundle.message("plugin.updater.downloading"), true, PluginManagerUISettings.getInstance()
|
||||
) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
var installed = false
|
||||
var message: String? = null
|
||||
val prepareResult = try {
|
||||
pluginDownloader.prepareToInstall(indicator)
|
||||
} catch (e: IOException) {
|
||||
LOG.info(e)
|
||||
message = e.message
|
||||
false
|
||||
}
|
||||
|
||||
if (prepareResult) {
|
||||
installed = true
|
||||
pluginDownloader.install()
|
||||
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
PluginManagerMain.notifyPluginsUpdated(null)
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
if (!installed) {
|
||||
errorCallback()
|
||||
notifyNotInstalled(message)
|
||||
} else {
|
||||
successCallback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
cancelCallback()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun notifyNotInstalled(message: String?) {
|
||||
val notification = notificationGroup.createNotification(
|
||||
KotlinBundle.message("plugin.updater.notification.title"),
|
||||
when (message) {
|
||||
null -> KotlinBundle.message("plugin.updater.not.installed")
|
||||
else -> KotlinBundle.message("plugin.updater.not.installed.misc", message)
|
||||
},
|
||||
NotificationType.INFORMATION,
|
||||
NotificationListener { notification, _ ->
|
||||
val logFile = File(PathManager.getLogPath(), "idea.log")
|
||||
ShowFilePathAction.openFile(logFile)
|
||||
|
||||
notification.expire()
|
||||
}
|
||||
)
|
||||
|
||||
notification.notify(null)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INITIAL_UPDATE_DELAY = 2000L
|
||||
private val CACHED_REQUEST_DELAY = TimeUnit.DAYS.toMillis(1)
|
||||
|
||||
private const val PROPERTY_NAME = "kotlin.lastUpdateCheck"
|
||||
private val LOG = Logger.getInstance(KotlinPluginUpdater::class.java)
|
||||
|
||||
fun getInstance(): KotlinPluginUpdater = ServiceManager.getService(KotlinPluginUpdater::class.java)
|
||||
|
||||
class ResponseParseException(message: String, cause: Exception? = null) : IllegalStateException(message, cause)
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private class PluginDTO {
|
||||
var cdate: String? = null
|
||||
var channel: String? = null
|
||||
|
||||
// `true` if the version is seen in plugin site and available for download.
|
||||
// Maybe be `false` if author requested version deletion.
|
||||
var listed: Boolean = true
|
||||
|
||||
// `true` if version is approved and verified
|
||||
var approve: Boolean = true
|
||||
}
|
||||
|
||||
@Throws(IOException::class, ResponseParseException::class)
|
||||
fun fetchPluginReleaseDate(pluginId: PluginId, version: String, channel: String?): LocalDate? {
|
||||
val url = "https://plugins.jetbrains.com/api/plugins/${pluginId.idString}/updates?version=$version"
|
||||
|
||||
val pluginDTOs: Array<PluginDTO> = try {
|
||||
HttpRequests.request(url).connect {
|
||||
GsonBuilder().create().fromJson(it.inputStream.reader(), Array<PluginDTO>::class.java)
|
||||
}
|
||||
} catch (ioException: JsonIOException) {
|
||||
throw IOException(ioException)
|
||||
} catch (syntaxException: JsonSyntaxException) {
|
||||
throw ResponseParseException("Can't parse json response", syntaxException)
|
||||
}
|
||||
|
||||
val selectedPluginDTO = pluginDTOs
|
||||
.firstOrNull {
|
||||
it.listed && it.approve && (it.channel == channel || (it.channel == "" && channel == null))
|
||||
}
|
||||
?: return null
|
||||
|
||||
val dateString = selectedPluginDTO.cdate ?: throw ResponseParseException("Empty cdate")
|
||||
|
||||
return try {
|
||||
val dateLong = dateString.toLong()
|
||||
Instant.ofEpochMilli(dateLong).atZone(ZoneOffset.UTC).toLocalDate()
|
||||
} catch (e: NumberFormatException) {
|
||||
throw ResponseParseException("Can't parse long date", e)
|
||||
} catch (e: DateTimeException) {
|
||||
throw ResponseParseException("Can't convert to date", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.kotlin.idea;
|
||||
|
||||
|
||||
public class PluginStartupActivity {
|
||||
|
||||
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathMacros;
|
||||
import com.intellij.openapi.components.BaseComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.event.DocumentListener;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateChecker;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.search.searches.IndexPatternSearch;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter;
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher;
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
|
||||
import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative;
|
||||
import org.jetbrains.kotlin.utils.PathUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.jetbrains.kotlin.idea.TestResourceBundleKt.registerAdditionalResourceBundleInTests;
|
||||
|
||||
public class PluginStartupComponent implements BaseComponent {
|
||||
private static final Logger LOG = Logger.getInstance(PluginStartupComponent.class);
|
||||
|
||||
private static final String KOTLIN_BUNDLED = "KOTLIN_BUNDLED";
|
||||
|
||||
public static PluginStartupComponent getInstance() {
|
||||
return ApplicationManager.getApplication().getComponent(PluginStartupComponent.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getComponentName() {
|
||||
return PluginStartupComponent.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initComponent() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
registerAdditionalResourceBundleInTests();
|
||||
}
|
||||
|
||||
registerPathVariable();
|
||||
initializeDiagnostics();
|
||||
|
||||
try {
|
||||
// API added in 15.0.2
|
||||
UpdateChecker.INSTANCE.getExcludedFromUpdateCheckPlugins().add("org.jetbrains.kotlin");
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
LOG.debug("Excluding Kotlin plugin updates using old API", throwable);
|
||||
UpdateChecker.getDisabledToUpdatePlugins().add("org.jetbrains.kotlin");
|
||||
}
|
||||
EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void documentChanged(@NotNull DocumentEvent e) {
|
||||
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(e.getDocument());
|
||||
if (virtualFile != null && virtualFile.getFileType() == KotlinFileType.INSTANCE) {
|
||||
KotlinPluginUpdater.Companion.getInstance().kotlinFileEdited(virtualFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ServiceManager.getService(IndexPatternSearch.class).registerExecutor(new KotlinTodoSearcher());
|
||||
|
||||
KotlinPluginCompatibilityVerifier.checkCompatibility();
|
||||
|
||||
KotlinReportSubmitter.Companion.setupReportingFromRelease();
|
||||
|
||||
//todo[Sedunov]: wait for fix in platform to avoid misunderstood from Java newbies (also ConfigureKotlinInTempDirTest)
|
||||
//KotlinSdkType.Companion.setUpIfNeeded();
|
||||
}
|
||||
|
||||
/*
|
||||
Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors.
|
||||
As a work-around, all Error classes are initialized beforehand.
|
||||
It doesn't matter what exact diagnostic factories are used here.
|
||||
*/
|
||||
private static void initializeDiagnostics() {
|
||||
consumeFactory(Errors.DEPRECATION);
|
||||
consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE);
|
||||
consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE);
|
||||
consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED);
|
||||
}
|
||||
|
||||
private static void consumeFactory(DiagnosticFactory<?> factory) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
factory.getClass();
|
||||
}
|
||||
|
||||
private static void registerPathVariable() {
|
||||
PathMacros macros = PathMacros.getInstance();
|
||||
macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath());
|
||||
}
|
||||
|
||||
private String aliveFlagPath;
|
||||
|
||||
public synchronized String getAliveFlagPath() {
|
||||
if (this.aliveFlagPath == null) {
|
||||
try {
|
||||
File flagFile = File.createTempFile("kotlin-idea-", "-is-running");
|
||||
flagFile.deleteOnExit();
|
||||
this.aliveFlagPath = flagFile.getAbsolutePath();
|
||||
}
|
||||
catch (IOException e) {
|
||||
this.aliveFlagPath = "";
|
||||
}
|
||||
}
|
||||
return this.aliveFlagPath;
|
||||
}
|
||||
|
||||
public synchronized void resetAliveFlag() {
|
||||
if (this.aliveFlagPath != null) {
|
||||
File flagFile = new File(this.aliveFlagPath);
|
||||
if (flagFile.exists()) {
|
||||
if (flagFile.delete()) {
|
||||
this.aliveFlagPath = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.kotlin.idea;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class PluginStartupService {
|
||||
|
||||
|
||||
}
|
||||
-221
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.kotlin.idea.actions.internal.benchmark
|
||||
|
||||
import com.intellij.codeInsight.AutoPopupController
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.codeInsight.navigation.NavigationUtil
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.ScrollType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.MessageType
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||
import com.intellij.psi.search.FileTypeIndex
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.uiDesigner.core.GridConstraints
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleOrigin
|
||||
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
|
||||
import org.jetbrains.kotlin.idea.completion.CompletionBenchmarkSink
|
||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||
import org.jetbrains.kotlin.idea.core.util.getLineCount
|
||||
import org.jetbrains.kotlin.idea.core.util.toPsiFile
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.*
|
||||
import javax.swing.JFileChooser
|
||||
import javax.swing.JPanel
|
||||
|
||||
abstract class AbstractCompletionBenchmarkAction : AnAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
|
||||
val benchmarkSink = CompletionBenchmarkSink.enableAndGet()
|
||||
val scenario = createBenchmarkScenario(project, benchmarkSink) ?: return
|
||||
|
||||
GlobalScope.launch(EDT) {
|
||||
scenario.doBenchmark()
|
||||
CompletionBenchmarkSink.disable()
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract fun createBenchmarkScenario(
|
||||
project: Project,
|
||||
benchmarkSink: CompletionBenchmarkSink.Impl
|
||||
): AbstractCompletionBenchmarkScenario?
|
||||
|
||||
companion object {
|
||||
fun showPopup(project: Project, text: String) {
|
||||
val statusBar = WindowManager.getInstance().getStatusBar(project)
|
||||
JBPopupFactory.getInstance()
|
||||
.createHtmlTextBalloonBuilder(text, MessageType.ERROR, null)
|
||||
.setFadeoutTime(5000)
|
||||
.createBalloon().showInCenterOf(statusBar.component)
|
||||
}
|
||||
|
||||
internal fun <T> List<T>.randomElement(random: Random): T? = if (this.isNotEmpty()) this[random.nextInt(this.size)] else null
|
||||
internal fun <T : Any> List<T>.shuffledSequence(random: Random): Sequence<T> =
|
||||
generateSequence { this.randomElement(random) }.distinct()
|
||||
|
||||
internal fun collectSuitableKotlinFiles(project: Project, filePredicate: (KtFile) -> Boolean): MutableList<KtFile> {
|
||||
val scope = object : DelegatingGlobalSearchScope(GlobalSearchScope.allScope(project)) {
|
||||
override fun isSearchOutsideRootModel(): Boolean = false
|
||||
}
|
||||
|
||||
fun KtFile.isUsableForBenchmark(): Boolean {
|
||||
val moduleInfo = this.getNullableModuleInfo() ?: return false
|
||||
if (this.isCompiled || !this.isWritable || this.isScript()) return false
|
||||
return moduleInfo.moduleOrigin == ModuleOrigin.MODULE
|
||||
}
|
||||
|
||||
val kotlinVFiles = FileTypeIndex.getFiles(KotlinFileType.INSTANCE, scope)
|
||||
|
||||
return kotlinVFiles
|
||||
.asSequence()
|
||||
.mapNotNull { vfile -> (vfile.toPsiFile(project) as? KtFile) }
|
||||
.filterTo(mutableListOf()) { it.isUsableForBenchmark() && filePredicate(it) }
|
||||
}
|
||||
|
||||
internal fun JPanel.addBoxWithLabel(tooltip: String, label: String = "$tooltip:", default: String, i: Int): JBTextField {
|
||||
this.add(JBLabel(label), GridConstraints().apply { row = i; column = 0 })
|
||||
val textField = JBTextField().apply {
|
||||
text = default
|
||||
toolTipText = tooltip
|
||||
}
|
||||
this.add(textField, GridConstraints().apply { row = i; column = 1; fill = GridConstraints.FILL_HORIZONTAL })
|
||||
return textField
|
||||
}
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
e.presentation.isEnabledAndVisible = ApplicationManager.getApplication().isInternal
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class AbstractCompletionBenchmarkScenario(
|
||||
val project: Project, private val benchmarkSink: CompletionBenchmarkSink.Impl,
|
||||
val random: Random = Random(), private val timeout: Long = 15000
|
||||
) {
|
||||
|
||||
|
||||
sealed class Result {
|
||||
abstract fun toCSV(stringBuilder: StringBuilder)
|
||||
|
||||
open class SuccessResult(val lines: Int, val filePath: String, val first: Long, val full: Long) : Result() {
|
||||
override fun toCSV(stringBuilder: StringBuilder): Unit = with(stringBuilder) {
|
||||
append(filePath)
|
||||
append(", ")
|
||||
append(lines)
|
||||
append(", ")
|
||||
append(first)
|
||||
append(", ")
|
||||
append(full)
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorResult(val filePath: String) : Result() {
|
||||
override fun toCSV(stringBuilder: StringBuilder): Unit = with(stringBuilder) {
|
||||
append(filePath)
|
||||
append(", ")
|
||||
append(", ")
|
||||
append(", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected suspend fun typeAtOffsetAndGetResult(text: String, offset: Int, file: KtFile): Result {
|
||||
NavigationUtil.openFileWithPsiElement(file.navigationElement, false, true)
|
||||
|
||||
val document =
|
||||
PsiDocumentManager.getInstance(project).getDocument(file) ?: return Result.ErrorResult("${file.virtualFile.path}:O$offset")
|
||||
|
||||
val location = "${file.virtualFile.path}:${document.getLineNumber(offset)}"
|
||||
|
||||
val editor = EditorFactory.getInstance().getEditors(document, project).firstOrNull() ?: return Result.ErrorResult(location)
|
||||
|
||||
|
||||
delay(500)
|
||||
|
||||
editor.moveCaret(offset, scrollType = ScrollType.CENTER)
|
||||
|
||||
delay(500)
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(project, {
|
||||
runWriteAction {
|
||||
document.insertString(editor.caretModel.offset, "\n$text\n")
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
}
|
||||
editor.moveCaret(editor.caretModel.offset + text.length + 1)
|
||||
AutoPopupController.getInstance(project).scheduleAutoPopup(editor, CompletionType.BASIC, null)
|
||||
}, "insertTextAndInvokeCompletion", "completionBenchmark")
|
||||
|
||||
val result = try {
|
||||
withTimeout(timeout) { collectResult(file, location) }
|
||||
} catch (_: CancellationException) {
|
||||
Result.ErrorResult(location)
|
||||
}
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(project, {
|
||||
runWriteAction {
|
||||
document.deleteString(offset, offset + text.length + 2)
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
}
|
||||
}, "revertToOriginal", "completionBenchmark")
|
||||
|
||||
delay(100)
|
||||
return result
|
||||
}
|
||||
|
||||
private suspend fun collectResult(file: KtFile, location: String): Result {
|
||||
val results = benchmarkSink.channel.receive()
|
||||
return Result.SuccessResult(file.getLineCount(), location, results.firstFlush, results.full)
|
||||
}
|
||||
|
||||
protected fun saveResults(allResults: List<Result>) {
|
||||
val jfc = JFileChooser()
|
||||
val result = jfc.showSaveDialog(null)
|
||||
if (result == JFileChooser.APPROVE_OPTION) {
|
||||
val file = jfc.selectedFile
|
||||
file.writeText(buildString {
|
||||
appendLine("n, file, lines, ff, full")
|
||||
var i = 0
|
||||
allResults.forEach {
|
||||
append(i++)
|
||||
append(", ")
|
||||
it.toCSV(this)
|
||||
appendLine()
|
||||
}
|
||||
})
|
||||
}
|
||||
AbstractCompletionBenchmarkAction.showPopup(project, KotlinBundle.message("title.done"))
|
||||
}
|
||||
|
||||
abstract suspend fun doBenchmark()
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.actions.internal.refactoringTesting
|
||||
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.gradle.getMethodOrNull
|
||||
|
||||
internal fun <T> lazyPub(initializer: () -> T) = lazy(LazyThreadSafetyMode.PUBLICATION, initializer)
|
||||
|
||||
internal fun gitReset(project: Project, projectRoot: VirtualFile) {
|
||||
|
||||
fun ClassLoader.loadClassOrThrow(name: String) =
|
||||
loadClass(name) ?: error("$name not loaded")
|
||||
|
||||
fun Class<*>.loadMethodOrThrow(name: String, vararg arguments: Class<*>) =
|
||||
getMethodOrNull(name, *arguments) ?: error("${this.name}::$name not loaded")
|
||||
|
||||
val loader = PluginManager.getPlugin(PluginId.getId("Git4Idea"))?.pluginClassLoader ?: error("Git plugin is not found")
|
||||
|
||||
val gitCls = loader.loadClassOrThrow("git4idea.commands.Git")
|
||||
val gitLineHandlerCls = loader.loadClassOrThrow("git4idea.commands.GitLineHandler")
|
||||
val gitCommandCls = loader.loadClassOrThrow("git4idea.commands.GitCommand")
|
||||
val gitCommandResultCls = loader.loadClassOrThrow("git4idea.commands.GitCommandResult")
|
||||
val gitLineHandlerCtor = gitLineHandlerCls.getConstructor(Project::class.java, VirtualFile::class.java, gitCommandCls) ?: error(
|
||||
"git4idea.commands.GitLineHandler::ctor not loaded"
|
||||
)
|
||||
val runCommand = gitCls.loadMethodOrThrow("runCommand", gitLineHandlerCls)
|
||||
val getExitCode = gitCommandResultCls.loadMethodOrThrow("getExitCode")
|
||||
val gitLineHandlerAddParameters = gitLineHandlerCls.loadMethodOrThrow("addParameters", List::class.java)
|
||||
|
||||
val gitCommandReset = gitCommandCls.getField("RESET")?.get(null) ?: error("git4idea.commands.GitCommand.RESET not loaded")
|
||||
|
||||
val resetLineHandler = gitLineHandlerCtor.newInstance(project, projectRoot, gitCommandReset)
|
||||
gitLineHandlerAddParameters.invoke(resetLineHandler, listOf("--hard", "HEAD"))
|
||||
|
||||
val gitService = ServiceManager.getService(gitCls)
|
||||
val runCommandResult = runCommand.invoke(gitService, resetLineHandler)
|
||||
|
||||
val gitResetResultCode = getExitCode.invoke(runCommandResult) as Int
|
||||
if (gitResetResultCode == 0) {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, false, projectRoot)
|
||||
//GitRepositoryManager.getInstance(project).updateRepository(d.getGitRoot())
|
||||
} else {
|
||||
error("Git reset failed")
|
||||
}
|
||||
}
|
||||
|
||||
inline fun edtExecute(crossinline body: () -> Unit) {
|
||||
ApplicationManager.getApplication().invokeAndWait {
|
||||
body()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun readAction(crossinline body: () -> Unit) {
|
||||
ApplicationManager.getApplication().runReadAction {
|
||||
body()
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle
|
||||
import com.intellij.codeInsight.CodeInsightSettings
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.codeInsight.hint.HintManagerImpl
|
||||
import com.intellij.codeInsight.hint.HintUtil
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.ReadAction.nonBlocking
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.LightweightHint
|
||||
import com.intellij.util.ArrayUtil
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.concurrency.CancellablePromise
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.imports.KotlinImportOptimizer
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import java.util.*
|
||||
import javax.swing.event.HyperlinkEvent
|
||||
import javax.swing.event.HyperlinkListener
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
object ReviewAddedImports {
|
||||
@get:TestOnly
|
||||
var importsToBeReviewed: Collection<String> = emptyList()
|
||||
|
||||
@get:TestOnly
|
||||
var importsToBeDeleted: Collection<String> = emptyList()
|
||||
|
||||
fun reviewAddedImports(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
file: KtFile,
|
||||
imported: TreeSet<String>
|
||||
) {
|
||||
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.YES &&
|
||||
!imported.isEmpty()
|
||||
) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
importsToBeReviewed = imported
|
||||
removeImports(project, file, importsToBeDeleted)
|
||||
return
|
||||
}
|
||||
// there is actual no such functionality in 192
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeImports(
|
||||
project: Project,
|
||||
file: KtFile,
|
||||
importsToRemove: Collection<String>
|
||||
) {
|
||||
if (importsToRemove.isEmpty()) return
|
||||
|
||||
WriteCommandAction.runWriteCommandAction(project, KotlinBundle.message("revert.applied.imports"), null, Runnable {
|
||||
val newImports = file.importDirectives.mapNotNull {
|
||||
val importedFqName = it.importedFqName ?: return@mapNotNull null
|
||||
if (importsToRemove.contains(importedFqName.asString())) return@mapNotNull null
|
||||
ImportPath(importedFqName, it.isAllUnder, it.aliasName?.let { alias -> Name.identifier(alias) })
|
||||
}
|
||||
KotlinImportOptimizer.replaceImports(file, newImports)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> submitNonBlocking(project: Project, indicator: ProgressIndicator, block: () -> T): CancellablePromise<T> =
|
||||
nonBlocking<T> {
|
||||
return@nonBlocking block()
|
||||
}
|
||||
.withDocumentsCommitted(project)
|
||||
.submit(AppExecutorUtil.getAppExecutorService())
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight.codevision
|
||||
|
||||
import com.intellij.codeInsight.hints.ChangeListener
|
||||
import com.intellij.codeInsight.hints.ImmediateConfigurable
|
||||
import com.intellij.codeInsight.hints.config.InlayHintsConfigurable
|
||||
import com.intellij.internal.statistic.eventLog.FeatureUsageData
|
||||
import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.layout.panel
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import javax.swing.JPanel
|
||||
|
||||
|
||||
typealias CodeVisionInlayHintsConfigurable = InlayHintsConfigurable
|
||||
|
||||
fun logUsageStatistics(project: Project?, groupId: String, eventId: String) {
|
||||
project?.let { FUCounterUsageLogger.getInstance().logEvent(project, groupId, eventId) }
|
||||
}
|
||||
|
||||
fun logUsageStatistics(project: Project?, groupId: String, eventId: String, data: FeatureUsageData) {
|
||||
project?.let { FUCounterUsageLogger.getInstance().logEvent(project, groupId, eventId, data) }
|
||||
}
|
||||
|
||||
fun createImmediateConfigurable(): ImmediateConfigurable {
|
||||
return object : ImmediateConfigurable {
|
||||
override fun createComponent(listener: ChangeListener): JPanel = panel {}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight.hints
|
||||
|
||||
import com.intellij.codeInsight.hints.ChangeListener
|
||||
import com.intellij.codeInsight.hints.ImmediateConfigurable
|
||||
import com.intellij.codeInsight.hints.config.InlayHintsConfigurable
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.layout.panel
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import javax.swing.JComponent
|
||||
|
||||
|
||||
typealias CompatibleInlayHintsConfigurable = InlayHintsConfigurable
|
||||
|
||||
fun createLambdaHintsImmediateConfigurable(settings: KotlinLambdasHintsProvider.Settings): ImmediateConfigurable {
|
||||
return object : ImmediateConfigurable {
|
||||
|
||||
private val returnExprField = JBCheckBox(KotlinBundle.message("hints.settings.lambda.return"), settings.returnExpressions)
|
||||
|
||||
private val receiversAndParamsField = JBCheckBox(
|
||||
KotlinBundle.message("hints.settings.lambda.receivers.parameters"),
|
||||
settings.implicitReceiversAndParams
|
||||
)
|
||||
|
||||
override fun createComponent(listener: ChangeListener): JComponent {
|
||||
returnExprField.isSelected = settings.returnExpressions
|
||||
returnExprField.addActionListener { settings.returnExpressions = returnExprField.isSelected }
|
||||
|
||||
receiversAndParamsField.isSelected = settings.implicitReceiversAndParams
|
||||
receiversAndParamsField.addActionListener { settings.implicitReceiversAndParams = receiversAndParamsField.isSelected }
|
||||
|
||||
return panel {
|
||||
row { returnExprField(pushX) }
|
||||
row { receiversAndParamsField(pushX) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createTypeHintsImmediateConfigurable(settings: KotlinReferencesTypeHintsProvider.Settings): ImmediateConfigurable {
|
||||
return object : ImmediateConfigurable {
|
||||
|
||||
private val propertyTypeField = JBCheckBox(KotlinBundle.message("hints.settings.types.property"), settings.propertyType)
|
||||
private val variableTypeField = JBCheckBox(KotlinBundle.message("hints.settings.types.variable"), settings.localVariableType)
|
||||
private val funReturnTypeField = JBCheckBox(KotlinBundle.message("hints.settings.types.return"), settings.functionReturnType)
|
||||
private val paramTypeField = JBCheckBox(KotlinBundle.message("hints.settings.types.parameter"), settings.parameterType)
|
||||
|
||||
override fun createComponent(listener: ChangeListener): JComponent {
|
||||
propertyTypeField.isSelected = settings.propertyType
|
||||
propertyTypeField.addActionListener { settings.propertyType = propertyTypeField.isSelected }
|
||||
|
||||
variableTypeField.isSelected = settings.localVariableType
|
||||
variableTypeField.addActionListener { settings.localVariableType = variableTypeField.isSelected }
|
||||
|
||||
funReturnTypeField.isSelected = settings.functionReturnType
|
||||
funReturnTypeField.addActionListener { settings.functionReturnType = funReturnTypeField.isSelected }
|
||||
|
||||
paramTypeField.isSelected = settings.parameterType
|
||||
paramTypeField.addActionListener { settings.parameterType = paramTypeField.isSelected }
|
||||
|
||||
return panel {
|
||||
row { propertyTypeField(pushX) }
|
||||
row { variableTypeField(pushX) }
|
||||
row { funReturnTypeField(pushX) }
|
||||
row { paramTypeField(pushX) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-752
@@ -1,752 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.compiler.configuration;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.ui.TextComponentAccessor;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.ListCellRendererWrapper;
|
||||
import com.intellij.ui.RawCommandLineEditor;
|
||||
import com.intellij.util.text.VersionComparatorUtil;
|
||||
import com.intellij.util.ui.ThreeStateCheckBox;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import kotlin.collections.ArraysKt;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants;
|
||||
import org.jetbrains.kotlin.config.*;
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle;
|
||||
import org.jetbrains.kotlin.idea.PluginStartupComponent;
|
||||
import org.jetbrains.kotlin.idea.facet.DescriptionListCellRenderer;
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet;
|
||||
import org.jetbrains.kotlin.idea.roots.RootUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.util.CidrUtil;
|
||||
import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt;
|
||||
import org.jetbrains.kotlin.platform.IdePlatformKind;
|
||||
import org.jetbrains.kotlin.platform.PlatformUtilKt;
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform;
|
||||
import org.jetbrains.kotlin.platform.impl.JsIdePlatformUtil;
|
||||
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind;
|
||||
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformUtil;
|
||||
import org.jetbrains.kotlin.platform.jvm.JdkPlatform;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
|
||||
public class KotlinCompilerConfigurableTab implements SearchableConfigurable {
|
||||
private static final Map<String, String> moduleKindDescriptions = new LinkedHashMap<>();
|
||||
private static final Map<String, String> soruceMapSourceEmbeddingDescriptions = new LinkedHashMap<>();
|
||||
private static final List<LanguageFeature.State> languageFeatureStates = Arrays.asList(
|
||||
LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_WARNING, LanguageFeature.State.ENABLED_WITH_ERROR
|
||||
);
|
||||
private static final int MAX_WARNING_SIZE = 75;
|
||||
|
||||
static {
|
||||
moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_PLAIN, KotlinBundle.message("configuration.description.plain.put.to.global.scope"));
|
||||
moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_AMD, KotlinBundle.message("configuration.description.amd"));
|
||||
moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_COMMONJS, KotlinBundle.message("configuration.description.commonjs"));
|
||||
moduleKindDescriptions.put(K2JsArgumentConstants.MODULE_UMD, KotlinBundle.message("configuration.description.umd.detect.amd.or.commonjs.if.available.fallback.to.plain"));
|
||||
|
||||
soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_NEVER, KotlinBundle.message("configuration.description.never"));
|
||||
soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_ALWAYS, KotlinBundle.message("configuration.description.always"));
|
||||
soruceMapSourceEmbeddingDescriptions.put(K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_INLINING, KotlinBundle.message("configuration.description.when.inlining.a.function.from.other.module.with.embedded.sources"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final KotlinCompilerWorkspaceSettings compilerWorkspaceSettings;
|
||||
private final Project project;
|
||||
private final boolean isProjectSettings;
|
||||
private CommonCompilerArguments commonCompilerArguments;
|
||||
private K2JSCompilerArguments k2jsCompilerArguments;
|
||||
private K2JVMCompilerArguments k2jvmCompilerArguments;
|
||||
private CompilerSettings compilerSettings;
|
||||
private JPanel contentPane;
|
||||
private ThreeStateCheckBox reportWarningsCheckBox;
|
||||
private RawCommandLineEditor additionalArgsOptionsField;
|
||||
private JLabel additionalArgsLabel;
|
||||
private ThreeStateCheckBox generateSourceMapsCheckBox;
|
||||
private TextFieldWithBrowseButton outputPrefixFile;
|
||||
private TextFieldWithBrowseButton outputPostfixFile;
|
||||
private JLabel labelForOutputDirectory;
|
||||
private TextFieldWithBrowseButton outputDirectory;
|
||||
private ThreeStateCheckBox copyRuntimeFilesCheckBox;
|
||||
private ThreeStateCheckBox keepAliveCheckBox;
|
||||
private JCheckBox enableIncrementalCompilationForJvmCheckBox;
|
||||
private JCheckBox enableIncrementalCompilationForJsCheckBox;
|
||||
private JComboBox moduleKindComboBox;
|
||||
private JTextField scriptTemplatesField;
|
||||
private JTextField scriptTemplatesClasspathField;
|
||||
private JLabel scriptTemplatesLabel;
|
||||
private JLabel scriptTemplatesClasspathLabel;
|
||||
private JPanel k2jvmPanel;
|
||||
private JPanel k2jsPanel;
|
||||
private JComboBox jvmVersionComboBox;
|
||||
private JComboBox<VersionView> languageVersionComboBox;
|
||||
private JComboBox coroutineSupportComboBox;
|
||||
private JComboBox<VersionView> apiVersionComboBox;
|
||||
private JPanel scriptPanel;
|
||||
private JLabel labelForOutputPrefixFile;
|
||||
private JLabel labelForOutputPostfixFile;
|
||||
private JLabel warningLabel;
|
||||
private JTextField sourceMapPrefix;
|
||||
private JLabel labelForSourceMapPrefix;
|
||||
private JComboBox sourceMapEmbedSources;
|
||||
private JPanel coroutinesPanel;
|
||||
private boolean isEnabled = true;
|
||||
|
||||
public KotlinCompilerConfigurableTab(
|
||||
Project project,
|
||||
@NotNull CommonCompilerArguments commonCompilerArguments,
|
||||
@NotNull K2JSCompilerArguments k2jsCompilerArguments,
|
||||
@NotNull K2JVMCompilerArguments k2jvmCompilerArguments, CompilerSettings compilerSettings,
|
||||
@Nullable KotlinCompilerWorkspaceSettings compilerWorkspaceSettings,
|
||||
boolean isProjectSettings,
|
||||
boolean isMultiEditor
|
||||
) {
|
||||
this.project = project;
|
||||
this.commonCompilerArguments = commonCompilerArguments;
|
||||
this.k2jsCompilerArguments = k2jsCompilerArguments;
|
||||
this.compilerSettings = compilerSettings;
|
||||
this.compilerWorkspaceSettings = compilerWorkspaceSettings;
|
||||
this.k2jvmCompilerArguments = k2jvmCompilerArguments;
|
||||
this.isProjectSettings = isProjectSettings;
|
||||
|
||||
warningLabel.setIcon(AllIcons.General.WarningDialog);
|
||||
|
||||
if (isProjectSettings) {
|
||||
languageVersionComboBox.addActionListener(e -> onLanguageLevelChanged(getSelectedLanguageVersionView()));
|
||||
}
|
||||
|
||||
additionalArgsOptionsField.attachLabel(additionalArgsLabel);
|
||||
|
||||
fillLanguageAndAPIVersionList();
|
||||
fillCoroutineSupportList();
|
||||
|
||||
if (CidrUtil.isRunningInCidrIde()) {
|
||||
keepAliveCheckBox.setVisible(false);
|
||||
k2jvmPanel.setVisible(false);
|
||||
k2jsPanel.setVisible(false);
|
||||
}
|
||||
else {
|
||||
initializeNonCidrSettings(isMultiEditor);
|
||||
}
|
||||
|
||||
reportWarningsCheckBox.setThirdStateEnabled(isMultiEditor);
|
||||
|
||||
if (isProjectSettings) {
|
||||
List<String> modulesOverridingProjectSettings = ArraysKt.mapNotNull(
|
||||
ModuleManager.getInstance(project).getModules(),
|
||||
module -> {
|
||||
KotlinFacet facet = KotlinFacet.Companion.get(module);
|
||||
if (facet == null) return null;
|
||||
KotlinFacetSettings facetSettings = facet.getConfiguration().getSettings();
|
||||
if (facetSettings.getUseProjectSettings()) return null;
|
||||
return module.getName();
|
||||
}
|
||||
);
|
||||
CollectionsKt.sort(modulesOverridingProjectSettings);
|
||||
if (!modulesOverridingProjectSettings.isEmpty()) {
|
||||
warningLabel.setVisible(true);
|
||||
warningLabel.setText(buildOverridingModulesWarning(modulesOverridingProjectSettings));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public KotlinCompilerConfigurableTab(Project project) {
|
||||
this(project,
|
||||
(CommonCompilerArguments) KotlinCommonCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(),
|
||||
(K2JSCompilerArguments) Kotlin2JsCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(),
|
||||
(K2JVMCompilerArguments) Kotlin2JvmCompilerArgumentsHolder.Companion.getInstance(project).getSettings().unfrozen(),
|
||||
(CompilerSettings) KotlinCompilerSettings.Companion.getInstance(project).getSettings().unfrozen(),
|
||||
KotlinCompilerWorkspaceSettings.getInstance(project),
|
||||
true,
|
||||
false);
|
||||
}
|
||||
|
||||
private void initializeNonCidrSettings(boolean isMultiEditor) {
|
||||
setupFileChooser(labelForOutputPrefixFile, outputPrefixFile,
|
||||
KotlinBundle.message("configuration.title.kotlin.compiler.js.option.output.prefix.browse.title"),
|
||||
true);
|
||||
setupFileChooser(labelForOutputPostfixFile, outputPostfixFile,
|
||||
KotlinBundle.message("configuration.title.kotlin.compiler.js.option.output.postfix.browse.title"),
|
||||
true);
|
||||
setupFileChooser(labelForOutputDirectory, outputDirectory,
|
||||
KotlinBundle.message("configuration.title.choose.output.directory"),
|
||||
false);
|
||||
|
||||
fillModuleKindList();
|
||||
fillSourceMapSourceEmbeddingList();
|
||||
fillJvmVersionList();
|
||||
|
||||
generateSourceMapsCheckBox.setThirdStateEnabled(isMultiEditor);
|
||||
generateSourceMapsCheckBox.addActionListener(event -> sourceMapPrefix.setEnabled(generateSourceMapsCheckBox.isSelected()));
|
||||
|
||||
copyRuntimeFilesCheckBox.setThirdStateEnabled(isMultiEditor);
|
||||
keepAliveCheckBox.setThirdStateEnabled(isMultiEditor);
|
||||
|
||||
if (compilerWorkspaceSettings == null) {
|
||||
keepAliveCheckBox.setVisible(false);
|
||||
k2jvmPanel.setVisible(false);
|
||||
enableIncrementalCompilationForJsCheckBox.setVisible(false);
|
||||
}
|
||||
|
||||
updateOutputDirEnabled();
|
||||
}
|
||||
|
||||
private static int calculateNameCountToShowInWarning(List<String> allNames) {
|
||||
int lengthSoFar = 0;
|
||||
int size = allNames.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
lengthSoFar = (i > 0 ? lengthSoFar + 2 : 0) + allNames.get(i).length();
|
||||
if (lengthSoFar > MAX_WARNING_SIZE) return i;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String buildOverridingModulesWarning(List<String> modulesOverridingProjectSettings) {
|
||||
int nameCountToShow = calculateNameCountToShowInWarning(modulesOverridingProjectSettings);
|
||||
int allNamesCount = modulesOverridingProjectSettings.size();
|
||||
if (nameCountToShow == 0) {
|
||||
return KotlinBundle.message("configuration.warning.text.modules.override.project.settings", String.valueOf(allNamesCount));
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<html>");
|
||||
builder.append(KotlinBundle.message("configuration.warning.text.following.modules.override.project.settings")).append(" ");
|
||||
CollectionsKt.joinTo(
|
||||
modulesOverridingProjectSettings.subList(0, nameCountToShow),
|
||||
builder,
|
||||
", ",
|
||||
"",
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
new Function1<String, CharSequence>() {
|
||||
@Override
|
||||
public CharSequence invoke(String s) {
|
||||
return "<strong>" + s + "</strong>";
|
||||
}
|
||||
}
|
||||
);
|
||||
if (nameCountToShow < allNamesCount) {
|
||||
builder.append(" ").append(KotlinBundle.message("configuration.text.and")).append(" ").append(allNamesCount - nameCountToShow).append(" ").append(KotlinBundle.message("configuration.text.other.s"));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getModuleKindDescription(@Nullable String moduleKind) {
|
||||
if (moduleKind == null) return "";
|
||||
String result = moduleKindDescriptions.get(moduleKind);
|
||||
assert result != null : "Module kind " + moduleKind + " was not added to combobox, therefore it should not be here";
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getSourceMapSourceEmbeddingDescription(@Nullable String sourceMapSourceEmbeddingId) {
|
||||
if (sourceMapSourceEmbeddingId == null) return "";
|
||||
String result = soruceMapSourceEmbeddingDescriptions.get(sourceMapSourceEmbeddingId);
|
||||
assert result != null : "Source map source embedding mode " + sourceMapSourceEmbeddingId +
|
||||
" was not added to combobox, therefore it should not be here";
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getModuleKindOrDefault(@Nullable String moduleKindId) {
|
||||
if (moduleKindId == null) {
|
||||
moduleKindId = K2JsArgumentConstants.MODULE_PLAIN;
|
||||
}
|
||||
return moduleKindId;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getSourceMapSourceEmbeddingOrDefault(@Nullable String sourceMapSourceEmbeddingId) {
|
||||
if (sourceMapSourceEmbeddingId == null) {
|
||||
sourceMapSourceEmbeddingId = K2JsArgumentConstants.SOURCE_MAP_SOURCE_CONTENT_INLINING;
|
||||
}
|
||||
return sourceMapSourceEmbeddingId;
|
||||
}
|
||||
|
||||
private static String getJvmVersionOrDefault(@Nullable String jvmVersion) {
|
||||
return jvmVersion != null ? jvmVersion : JvmTarget.DEFAULT.getDescription();
|
||||
}
|
||||
|
||||
private static void setupFileChooser(
|
||||
@NotNull JLabel label,
|
||||
@NotNull TextFieldWithBrowseButton fileChooser,
|
||||
@NotNull String title,
|
||||
boolean forFiles
|
||||
) {
|
||||
label.setLabelFor(fileChooser);
|
||||
|
||||
fileChooser.addBrowseFolderListener(title, null, null,
|
||||
new FileChooserDescriptor(forFiles, !forFiles, false, false, false, false),
|
||||
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
|
||||
}
|
||||
|
||||
private static boolean isModifiedWithNullize(@NotNull TextFieldWithBrowseButton chooser, @Nullable String currentValue) {
|
||||
return !StringUtil.equals(
|
||||
StringUtil.nullize(chooser.getText(), true),
|
||||
StringUtil.nullize(currentValue, true));
|
||||
}
|
||||
|
||||
private static boolean isModified(@NotNull TextFieldWithBrowseButton chooser, @NotNull String currentValue) {
|
||||
return !StringUtil.equals(chooser.getText(), currentValue);
|
||||
}
|
||||
|
||||
private void updateOutputDirEnabled() {
|
||||
if (isEnabled && copyRuntimeFilesCheckBox != null) {
|
||||
outputDirectory.setEnabled(copyRuntimeFilesCheckBox.isSelected());
|
||||
labelForOutputDirectory.setEnabled(copyRuntimeFilesCheckBox.isSelected());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLessOrEqual(LanguageVersion version, LanguageVersion upperBound) {
|
||||
return VersionComparatorUtil.compare(version.getVersionString(), upperBound.getVersionString()) <= 0;
|
||||
}
|
||||
|
||||
public void onLanguageLevelChanged(@Nullable VersionView languageLevel) {
|
||||
if (languageLevel == null) return;
|
||||
restrictAPIVersions(languageLevel);
|
||||
coroutinesPanel.setVisible(languageLevel.getVersion().compareTo(LanguageVersion.KOTLIN_1_3) < 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void restrictAPIVersions(VersionView upperBoundView) {
|
||||
VersionView selectedAPIView = getSelectedAPIVersionView();
|
||||
LanguageVersion selectedAPIVersion = selectedAPIView.getVersion();
|
||||
LanguageVersion upperBound = upperBoundView.getVersion();
|
||||
List<VersionView> permittedAPIVersions = new ArrayList<>(LanguageVersion.values().length + 1);
|
||||
if (isLessOrEqual(VersionView.LatestStable.INSTANCE.getVersion(), upperBound)) {
|
||||
permittedAPIVersions.add(VersionView.LatestStable.INSTANCE);
|
||||
}
|
||||
ArraysKt.mapNotNullTo(
|
||||
LanguageVersion.values(),
|
||||
permittedAPIVersions,
|
||||
version -> isLessOrEqual(version, upperBound) && !version.isUnsupported() ? new VersionView.Specific(version) : null
|
||||
);
|
||||
apiVersionComboBox.setModel(
|
||||
new DefaultComboBoxModel(permittedAPIVersions.toArray())
|
||||
);
|
||||
apiVersionComboBox.setSelectedItem(
|
||||
VersionComparatorUtil.compare(selectedAPIVersion.getVersionString(), upperBound.getVersionString()) <= 0
|
||||
? selectedAPIView
|
||||
: upperBoundView
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void fillJvmVersionList() {
|
||||
for (TargetPlatform jvm : JvmIdePlatformKind.INSTANCE.getPlatforms()) {
|
||||
jvmVersionComboBox.addItem(PlatformUtilKt.subplatformsOfType(jvm, JdkPlatform.class).get(0).getTargetVersion().getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
private void fillLanguageAndAPIVersionList() {
|
||||
languageVersionComboBox.addItem(VersionView.LatestStable.INSTANCE);
|
||||
apiVersionComboBox.addItem(VersionView.LatestStable.INSTANCE);
|
||||
|
||||
for (LanguageVersion version : LanguageVersion.values()) {
|
||||
if (version.isUnsupported() || !version.isStable() && !ApplicationManager.getApplication().isInternal()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VersionView.Specific specificVersion = new VersionView.Specific(version);
|
||||
languageVersionComboBox.addItem(specificVersion);
|
||||
apiVersionComboBox.addItem(specificVersion);
|
||||
}
|
||||
languageVersionComboBox.setRenderer(new DescriptionListCellRenderer());
|
||||
apiVersionComboBox.setRenderer(new DescriptionListCellRenderer());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void fillCoroutineSupportList() {
|
||||
for (LanguageFeature.State coroutineSupport : languageFeatureStates) {
|
||||
coroutineSupportComboBox.addItem(coroutineSupport);
|
||||
}
|
||||
coroutineSupportComboBox.setRenderer(new DescriptionListCellRenderer());
|
||||
}
|
||||
|
||||
public void setTargetPlatform(@Nullable IdePlatformKind<?> targetPlatform) {
|
||||
k2jsPanel.setVisible(JsIdePlatformUtil.isJavaScript(targetPlatform));
|
||||
scriptPanel.setVisible(JvmIdePlatformUtil.isJvm(targetPlatform));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void fillModuleKindList() {
|
||||
for (String moduleKind : moduleKindDescriptions.keySet()) {
|
||||
moduleKindComboBox.addItem(moduleKind);
|
||||
}
|
||||
moduleKindComboBox.setRenderer(new ListCellRendererWrapper<String>() {
|
||||
@Override
|
||||
public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) {
|
||||
setText(getModuleKindDescription(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void fillSourceMapSourceEmbeddingList() {
|
||||
for (String moduleKind : soruceMapSourceEmbeddingDescriptions.keySet()) {
|
||||
sourceMapEmbedSources.addItem(moduleKind);
|
||||
}
|
||||
sourceMapEmbedSources.setRenderer(new ListCellRendererWrapper<String>() {
|
||||
@Override
|
||||
public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) {
|
||||
setText(value != null ? getSourceMapSourceEmbeddingDescription(value) : "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getId() {
|
||||
return "project.kotlinCompiler";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Runnable enableSearch(String option) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createComponent() {
|
||||
return contentPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
return isModified(reportWarningsCheckBox, !commonCompilerArguments.getSuppressWarnings()) ||
|
||||
!getSelectedLanguageVersionView().equals(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)) ||
|
||||
!getSelectedAPIVersionView().equals(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)) ||
|
||||
!getSelectedCoroutineState().equals(commonCompilerArguments.getCoroutinesState()) ||
|
||||
!additionalArgsOptionsField.getText().equals(compilerSettings.getAdditionalArguments()) ||
|
||||
isModified(scriptTemplatesField, compilerSettings.getScriptTemplates()) ||
|
||||
isModified(scriptTemplatesClasspathField, compilerSettings.getScriptTemplatesClasspath()) ||
|
||||
isModified(copyRuntimeFilesCheckBox, compilerSettings.getCopyJsLibraryFiles()) ||
|
||||
isModified(outputDirectory, compilerSettings.getOutputDirectoryForJsLibraryFiles()) ||
|
||||
|
||||
(compilerWorkspaceSettings != null &&
|
||||
(isModified(enableIncrementalCompilationForJvmCheckBox, compilerWorkspaceSettings.getPreciseIncrementalEnabled()) ||
|
||||
isModified(enableIncrementalCompilationForJsCheckBox, compilerWorkspaceSettings.getIncrementalCompilationForJsEnabled()) ||
|
||||
isModified(keepAliveCheckBox, compilerWorkspaceSettings.getEnableDaemon()))) ||
|
||||
|
||||
isModified(generateSourceMapsCheckBox, k2jsCompilerArguments.getSourceMap()) ||
|
||||
isModifiedWithNullize(outputPrefixFile, k2jsCompilerArguments.getOutputPrefix()) ||
|
||||
isModifiedWithNullize(outputPostfixFile, k2jsCompilerArguments.getOutputPostfix()) ||
|
||||
!getSelectedModuleKind().equals(getModuleKindOrDefault(k2jsCompilerArguments.getModuleKind())) ||
|
||||
isModified(sourceMapPrefix, StringUtil.notNullize(k2jsCompilerArguments.getSourceMapPrefix())) ||
|
||||
!getSelectedSourceMapSourceEmbedding().equals(
|
||||
getSourceMapSourceEmbeddingOrDefault(k2jsCompilerArguments.getSourceMapEmbedSources())) ||
|
||||
!getSelectedJvmVersion().equals(getJvmVersionOrDefault(k2jvmCompilerArguments.getJvmTarget()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getSelectedModuleKind() {
|
||||
return getModuleKindOrDefault((String) moduleKindComboBox.getSelectedItem());
|
||||
}
|
||||
|
||||
private String getSelectedSourceMapSourceEmbedding() {
|
||||
return getSourceMapSourceEmbeddingOrDefault((String) sourceMapEmbedSources.getSelectedItem());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getSelectedJvmVersion() {
|
||||
return getJvmVersionOrDefault((String) jvmVersionComboBox.getSelectedItem());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VersionView getSelectedLanguageVersionView() {
|
||||
Object item = languageVersionComboBox.getSelectedItem();
|
||||
return item != null ? (VersionView) item : VersionView.LatestStable.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private VersionView getSelectedAPIVersionView() {
|
||||
Object item = apiVersionComboBox.getSelectedItem();
|
||||
return item != null ? (VersionView) item : VersionView.LatestStable.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getSelectedCoroutineState() {
|
||||
if (getSelectedLanguageVersionView().getVersion().compareTo(LanguageVersion.KOTLIN_1_3) >= 0) {
|
||||
return CommonCompilerArguments.DEFAULT;
|
||||
}
|
||||
|
||||
LanguageFeature.State state = (LanguageFeature.State) coroutineSupportComboBox.getSelectedItem();
|
||||
if (state == null) return CommonCompilerArguments.DEFAULT;
|
||||
switch (state) {
|
||||
case ENABLED: return CommonCompilerArguments.ENABLE;
|
||||
case ENABLED_WITH_WARNING: return CommonCompilerArguments.WARN;
|
||||
case ENABLED_WITH_ERROR: return CommonCompilerArguments.ERROR;
|
||||
default: return CommonCompilerArguments.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
public void applyTo(
|
||||
CommonCompilerArguments commonCompilerArguments,
|
||||
K2JVMCompilerArguments k2jvmCompilerArguments,
|
||||
K2JSCompilerArguments k2jsCompilerArguments,
|
||||
CompilerSettings compilerSettings
|
||||
) throws ConfigurationException {
|
||||
if (isProjectSettings) {
|
||||
boolean shouldInvalidateCaches =
|
||||
!getSelectedLanguageVersionView().equals(KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments)) ||
|
||||
!getSelectedAPIVersionView().equals(KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments)) ||
|
||||
!getSelectedCoroutineState().equals(commonCompilerArguments.getCoroutinesState()) ||
|
||||
!additionalArgsOptionsField.getText().equals(compilerSettings.getAdditionalArguments());
|
||||
|
||||
if (shouldInvalidateCaches) {
|
||||
ApplicationUtilsKt.runWriteAction(
|
||||
new Function0<Object>() {
|
||||
@Override
|
||||
public Object invoke() {
|
||||
RootUtilsKt.invalidateProjectRoots(project);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
commonCompilerArguments.setSuppressWarnings(!reportWarningsCheckBox.isSelected());
|
||||
KotlinFacetSettingsKt.setLanguageVersionView(commonCompilerArguments, getSelectedLanguageVersionView());
|
||||
KotlinFacetSettingsKt.setApiVersionView(commonCompilerArguments, getSelectedAPIVersionView());
|
||||
|
||||
commonCompilerArguments.setCoroutinesState(getSelectedCoroutineState());
|
||||
|
||||
compilerSettings.setAdditionalArguments(additionalArgsOptionsField.getText());
|
||||
compilerSettings.setScriptTemplates(scriptTemplatesField.getText());
|
||||
compilerSettings.setScriptTemplatesClasspath(scriptTemplatesClasspathField.getText());
|
||||
compilerSettings.setCopyJsLibraryFiles(copyRuntimeFilesCheckBox.isSelected());
|
||||
compilerSettings.setOutputDirectoryForJsLibraryFiles(outputDirectory.getText());
|
||||
|
||||
if (compilerWorkspaceSettings != null) {
|
||||
compilerWorkspaceSettings.setPreciseIncrementalEnabled(enableIncrementalCompilationForJvmCheckBox.isSelected());
|
||||
compilerWorkspaceSettings.setIncrementalCompilationForJsEnabled(enableIncrementalCompilationForJsCheckBox.isSelected());
|
||||
|
||||
boolean oldEnableDaemon = compilerWorkspaceSettings.getEnableDaemon();
|
||||
compilerWorkspaceSettings.setEnableDaemon(keepAliveCheckBox.isSelected());
|
||||
if (keepAliveCheckBox.isSelected() != oldEnableDaemon) {
|
||||
PluginStartupComponent.getInstance().resetAliveFlag();
|
||||
}
|
||||
}
|
||||
|
||||
k2jsCompilerArguments.setSourceMap(generateSourceMapsCheckBox.isSelected());
|
||||
k2jsCompilerArguments.setOutputPrefix(StringUtil.nullize(outputPrefixFile.getText(), true));
|
||||
k2jsCompilerArguments.setOutputPostfix(StringUtil.nullize(outputPostfixFile.getText(), true));
|
||||
k2jsCompilerArguments.setModuleKind(getSelectedModuleKind());
|
||||
|
||||
k2jsCompilerArguments.setSourceMapPrefix(sourceMapPrefix.getText());
|
||||
k2jsCompilerArguments.setSourceMapEmbedSources(generateSourceMapsCheckBox.isSelected() ? getSelectedSourceMapSourceEmbedding() : null);
|
||||
|
||||
k2jvmCompilerArguments.setJvmTarget(getSelectedJvmVersion());
|
||||
|
||||
if (isProjectSettings) {
|
||||
KotlinCommonCompilerArgumentsHolder.Companion.getInstance(project).setSettings(commonCompilerArguments);
|
||||
Kotlin2JvmCompilerArgumentsHolder.Companion.getInstance(project).setSettings(k2jvmCompilerArguments);
|
||||
Kotlin2JsCompilerArgumentsHolder.Companion.getInstance(project).setSettings(k2jsCompilerArguments);
|
||||
KotlinCompilerSettings.Companion.getInstance(project).setSettings(compilerSettings);
|
||||
}
|
||||
|
||||
for (ClearBuildStateExtension extension : ClearBuildStateExtension.getExtensions()) {
|
||||
extension.clearState(project);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
applyTo(commonCompilerArguments, k2jvmCompilerArguments, k2jsCompilerArguments, compilerSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
reportWarningsCheckBox.setSelected(!commonCompilerArguments.getSuppressWarnings());
|
||||
setSelectedItem(languageVersionComboBox, KotlinFacetSettingsKt.getLanguageVersionView(commonCompilerArguments));
|
||||
onLanguageLevelChanged((VersionView) languageVersionComboBox.getSelectedItem()); // getSelectedLanguageVersionView() replaces null
|
||||
setSelectedItem(apiVersionComboBox, KotlinFacetSettingsKt.getApiVersionView(commonCompilerArguments));
|
||||
coroutineSupportComboBox.setSelectedItem(CoroutineSupport.byCompilerArguments(commonCompilerArguments));
|
||||
additionalArgsOptionsField.setText(compilerSettings.getAdditionalArguments());
|
||||
scriptTemplatesField.setText(compilerSettings.getScriptTemplates());
|
||||
scriptTemplatesClasspathField.setText(compilerSettings.getScriptTemplatesClasspath());
|
||||
copyRuntimeFilesCheckBox.setSelected(compilerSettings.getCopyJsLibraryFiles());
|
||||
outputDirectory.setText(compilerSettings.getOutputDirectoryForJsLibraryFiles());
|
||||
|
||||
if (compilerWorkspaceSettings != null) {
|
||||
enableIncrementalCompilationForJvmCheckBox.setSelected(compilerWorkspaceSettings.getPreciseIncrementalEnabled());
|
||||
enableIncrementalCompilationForJsCheckBox.setSelected(compilerWorkspaceSettings.getIncrementalCompilationForJsEnabled());
|
||||
keepAliveCheckBox.setSelected(compilerWorkspaceSettings.getEnableDaemon());
|
||||
}
|
||||
|
||||
generateSourceMapsCheckBox.setSelected(k2jsCompilerArguments.getSourceMap());
|
||||
outputPrefixFile.setText(k2jsCompilerArguments.getOutputPrefix());
|
||||
outputPostfixFile.setText(k2jsCompilerArguments.getOutputPostfix());
|
||||
|
||||
moduleKindComboBox.setSelectedItem(getModuleKindOrDefault(k2jsCompilerArguments.getModuleKind()));
|
||||
sourceMapPrefix.setText(k2jsCompilerArguments.getSourceMapPrefix());
|
||||
sourceMapPrefix.setEnabled(k2jsCompilerArguments.getSourceMap());
|
||||
sourceMapEmbedSources.setSelectedItem(getSourceMapSourceEmbeddingOrDefault(k2jsCompilerArguments.getSourceMapEmbedSources()));
|
||||
|
||||
jvmVersionComboBox.setSelectedItem(getJvmVersionOrDefault(k2jvmCompilerArguments.getJvmTarget()));
|
||||
}
|
||||
|
||||
private static void setSelectedItem(JComboBox<VersionView> comboBox, VersionView versionView) {
|
||||
// Imported projects might have outdated language/api versions - we display them as well (see createVersionValidator() for details)
|
||||
int index = ((DefaultComboBoxModel<VersionView>) comboBox.getModel()).getIndexOf(versionView);
|
||||
if (index == -1)
|
||||
comboBox.addItem(versionView);
|
||||
|
||||
comboBox.setSelectedItem(versionView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
}
|
||||
|
||||
@Nls
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return KotlinBundle.message("configuration.name.kotlin.compiler");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getHelpTopic() {
|
||||
return "reference.compiler.kotlin";
|
||||
}
|
||||
|
||||
public JPanel getContentPane() {
|
||||
return contentPane;
|
||||
}
|
||||
|
||||
public ThreeStateCheckBox getReportWarningsCheckBox() {
|
||||
return reportWarningsCheckBox;
|
||||
}
|
||||
|
||||
public RawCommandLineEditor getAdditionalArgsOptionsField() {
|
||||
return additionalArgsOptionsField;
|
||||
}
|
||||
|
||||
public ThreeStateCheckBox getGenerateSourceMapsCheckBox() {
|
||||
return generateSourceMapsCheckBox;
|
||||
}
|
||||
|
||||
public TextFieldWithBrowseButton getOutputPrefixFile() {
|
||||
return outputPrefixFile;
|
||||
}
|
||||
|
||||
public TextFieldWithBrowseButton getOutputPostfixFile() {
|
||||
return outputPostfixFile;
|
||||
}
|
||||
|
||||
public TextFieldWithBrowseButton getOutputDirectory() {
|
||||
return outputDirectory;
|
||||
}
|
||||
|
||||
public ThreeStateCheckBox getCopyRuntimeFilesCheckBox() {
|
||||
return copyRuntimeFilesCheckBox;
|
||||
}
|
||||
|
||||
public ThreeStateCheckBox getKeepAliveCheckBox() {
|
||||
return keepAliveCheckBox;
|
||||
}
|
||||
|
||||
public JComboBox getModuleKindComboBox() {
|
||||
return moduleKindComboBox;
|
||||
}
|
||||
|
||||
public JTextField getScriptTemplatesField() {
|
||||
return scriptTemplatesField;
|
||||
}
|
||||
|
||||
public JTextField getScriptTemplatesClasspathField() {
|
||||
return scriptTemplatesClasspathField;
|
||||
}
|
||||
|
||||
public JComboBox getLanguageVersionComboBox() {
|
||||
return languageVersionComboBox;
|
||||
}
|
||||
|
||||
public JComboBox getApiVersionComboBox() {
|
||||
return apiVersionComboBox;
|
||||
}
|
||||
|
||||
public JComboBox getCoroutineSupportComboBox() {
|
||||
return coroutineSupportComboBox;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean value) {
|
||||
isEnabled = value;
|
||||
UIUtil.setEnabled(getContentPane(), value, true);
|
||||
}
|
||||
|
||||
public CommonCompilerArguments getCommonCompilerArguments() {
|
||||
return commonCompilerArguments;
|
||||
}
|
||||
|
||||
public void setCommonCompilerArguments(CommonCompilerArguments commonCompilerArguments) {
|
||||
this.commonCompilerArguments = commonCompilerArguments;
|
||||
}
|
||||
|
||||
public K2JSCompilerArguments getK2jsCompilerArguments() {
|
||||
return k2jsCompilerArguments;
|
||||
}
|
||||
|
||||
public void setK2jsCompilerArguments(K2JSCompilerArguments k2jsCompilerArguments) {
|
||||
this.k2jsCompilerArguments = k2jsCompilerArguments;
|
||||
}
|
||||
|
||||
public K2JVMCompilerArguments getK2jvmCompilerArguments() {
|
||||
return k2jvmCompilerArguments;
|
||||
}
|
||||
|
||||
public void setK2jvmCompilerArguments(K2JVMCompilerArguments k2jvmCompilerArguments) {
|
||||
this.k2jvmCompilerArguments = k2jvmCompilerArguments;
|
||||
}
|
||||
|
||||
public CompilerSettings getCompilerSettings() {
|
||||
return compilerSettings;
|
||||
}
|
||||
|
||||
public void setCompilerSettings(CompilerSettings compilerSettings) {
|
||||
this.compilerSettings = compilerSettings;
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
// Explicit use of DefaultComboBoxModel guarantees that setSelectedItem() can make safe cast.
|
||||
languageVersionComboBox = new ComboBox<>(new DefaultComboBoxModel<>());
|
||||
apiVersionComboBox = new ComboBox<>(new DefaultComboBoxModel<>());
|
||||
|
||||
// Workaround: ThreeStateCheckBox doesn't send suitable notification on state change
|
||||
// TODO: replace with PropertyChangerListener after fix is available in IDEA
|
||||
copyRuntimeFilesCheckBox = new ThreeStateCheckBox() {
|
||||
@Override
|
||||
public void setState(State state) {
|
||||
super.setState(state);
|
||||
updateOutputDirEnabled();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
-319
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager
|
||||
import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx
|
||||
import com.intellij.util.CommonProcessors
|
||||
import com.intellij.util.text.VersionComparatorUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.idea.configuration.ui.showMigrationNotification
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||
import org.jetbrains.kotlin.idea.framework.MAVEN_SYSTEM_ID
|
||||
import org.jetbrains.kotlin.idea.migration.CodeMigrationToggleAction
|
||||
import org.jetbrains.kotlin.idea.migration.applicableMigrationTools
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.runReadActionInSmartMode
|
||||
import org.jetbrains.kotlin.idea.versions.LibInfo
|
||||
import java.io.File
|
||||
|
||||
class KotlinMigrationProjectComponent(val project: Project) {
|
||||
@Volatile
|
||||
private var old: MigrationState? = null
|
||||
|
||||
@Volatile
|
||||
private var importFinishListener: ((MigrationTestState?) -> Unit)? = null
|
||||
|
||||
init {
|
||||
val connection = project.messageBus.connect(project)
|
||||
connection.subscribe(ProjectDataImportListener.TOPIC, ProjectDataImportListener {
|
||||
getInstanceIfNotDisposed(project)?.onImportFinished()
|
||||
})
|
||||
}
|
||||
|
||||
class MigrationTestState(val migrationInfo: MigrationInfo?, val hasApplicableTools: Boolean)
|
||||
|
||||
@TestOnly
|
||||
fun setImportFinishListener(newListener: ((MigrationTestState?) -> Unit)?) {
|
||||
synchronized(this) {
|
||||
if (newListener != null && importFinishListener != null) {
|
||||
importFinishListener!!.invoke(null)
|
||||
}
|
||||
|
||||
importFinishListener = newListener
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyFinish(migrationInfo: MigrationInfo?, hasApplicableTools: Boolean) {
|
||||
importFinishListener?.invoke(MigrationTestState(migrationInfo, hasApplicableTools))
|
||||
}
|
||||
|
||||
fun onImportAboutToStart() {
|
||||
if (!CodeMigrationToggleAction.isEnabled(project) || !hasChangesInProjectFiles(project)) {
|
||||
old = null
|
||||
return
|
||||
}
|
||||
|
||||
old = MigrationState.build(project)
|
||||
}
|
||||
|
||||
fun onImportFinished() {
|
||||
if (!CodeMigrationToggleAction.isEnabled(project) || old == null) {
|
||||
notifyFinish(null, false)
|
||||
return
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
var migrationInfo: MigrationInfo? = null
|
||||
var hasApplicableTools = false
|
||||
|
||||
try {
|
||||
val new = project.runReadActionInSmartMode {
|
||||
MigrationState.build(project)
|
||||
}
|
||||
|
||||
val localOld = old.also {
|
||||
old = null
|
||||
} ?: return@executeOnPooledThread
|
||||
|
||||
migrationInfo = prepareMigrationInfo(localOld, new) ?: return@executeOnPooledThread
|
||||
|
||||
if (applicableMigrationTools(migrationInfo).isEmpty()) {
|
||||
hasApplicableTools = false
|
||||
return@executeOnPooledThread
|
||||
} else {
|
||||
hasApplicableTools = true
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
return@executeOnPooledThread
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
showMigrationNotification(project, migrationInfo)
|
||||
}
|
||||
} finally {
|
||||
notifyFinish(migrationInfo, hasApplicableTools)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): KotlinMigrationProjectComponent =
|
||||
project.getComponent(KotlinMigrationProjectComponent::class.java)
|
||||
?: error("Can't find ${KotlinMigrationProjectComponent::class.qualifiedName} component")
|
||||
|
||||
fun getInstanceIfNotDisposed(project: Project): KotlinMigrationProjectComponent? {
|
||||
return runReadAction {
|
||||
if (!project.isDisposed) getInstance(project) else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareMigrationInfo(old: MigrationState?, new: MigrationState?): MigrationInfo? {
|
||||
if (old == null || new == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val oldLibraryVersion = old.stdlibInfo?.version
|
||||
val newLibraryVersion = new.stdlibInfo?.version
|
||||
|
||||
if (oldLibraryVersion == null || newLibraryVersion == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (VersionComparatorUtil.COMPARATOR.compare(newLibraryVersion, oldLibraryVersion) > 0 ||
|
||||
old.apiVersion < new.apiVersion || old.languageVersion < new.languageVersion
|
||||
) {
|
||||
return MigrationInfo(
|
||||
oldLibraryVersion, newLibraryVersion,
|
||||
old.apiVersion, new.apiVersion,
|
||||
old.languageVersion, new.languageVersion
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun hasChangesInProjectFiles(project: Project): Boolean {
|
||||
if (ProjectLevelVcsManagerEx.getInstance(project).allVcsRoots.isEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
val checkedFiles = HashSet<File>()
|
||||
|
||||
project.basePath?.let { projectBasePath ->
|
||||
checkedFiles.add(File(projectBasePath))
|
||||
}
|
||||
|
||||
val changedFiles = ChangeListManager.getInstance(project).affectedPaths
|
||||
for (changedFile in changedFiles) {
|
||||
when (changedFile.extension) {
|
||||
"gradle" -> return true
|
||||
"properties" -> return true
|
||||
"kts" -> return true
|
||||
"iml" -> return true
|
||||
"xml" -> {
|
||||
if (changedFile.name == "pom.xml") return true
|
||||
val parentDir = changedFile.parentFile
|
||||
if (parentDir.isDirectory && parentDir.name == Project.DIRECTORY_STORE_FOLDER) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
"kt", "java", "groovy" -> {
|
||||
val dirs: Sequence<File> = generateSequence(changedFile) { it.parentFile }
|
||||
.drop(1) // Drop original file
|
||||
.takeWhile { it.isDirectory }
|
||||
|
||||
val isInBuildSrc = dirs
|
||||
.takeWhile { checkedFiles.add(it) }
|
||||
.any { it.name == BUILD_SRC_FOLDER_NAME }
|
||||
|
||||
if (isInBuildSrc) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MigrationState(
|
||||
var stdlibInfo: LibInfo?,
|
||||
var apiVersion: ApiVersion,
|
||||
var languageVersion: LanguageVersion
|
||||
) {
|
||||
companion object {
|
||||
fun build(project: Project): MigrationState {
|
||||
val libraries = maxKotlinLibVersion(project)
|
||||
val languageVersionSettings = collectMaxCompilerSettings(project)
|
||||
return MigrationState(libraries, languageVersionSettings.apiVersion, languageVersionSettings.languageVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class MigrationInfo(
|
||||
val oldStdlibVersion: String,
|
||||
val newStdlibVersion: String,
|
||||
val oldApiVersion: ApiVersion,
|
||||
val newApiVersion: ApiVersion,
|
||||
val oldLanguageVersion: LanguageVersion,
|
||||
val newLanguageVersion: LanguageVersion
|
||||
) {
|
||||
fun oldVersionsToMap(): Map<String, String> = mapOf(
|
||||
"old_stdlib_version" to oldStdlibVersion,
|
||||
"old_api_version" to oldApiVersion.versionString,
|
||||
"old_language_version" to oldLanguageVersion.versionString
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun create(
|
||||
oldStdlibVersion: String,
|
||||
oldApiVersion: ApiVersion,
|
||||
oldLanguageVersion: LanguageVersion,
|
||||
newStdlibVersion: String = oldStdlibVersion,
|
||||
newApiVersion: ApiVersion = oldApiVersion,
|
||||
newLanguageVersion: LanguageVersion = oldLanguageVersion
|
||||
): MigrationInfo {
|
||||
return MigrationInfo(
|
||||
oldStdlibVersion, newStdlibVersion,
|
||||
oldApiVersion, newApiVersion,
|
||||
oldLanguageVersion, newLanguageVersion
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun MigrationInfo.isLanguageVersionUpdate(old: LanguageVersion, new: LanguageVersion): Boolean {
|
||||
return oldLanguageVersion <= old && newLanguageVersion >= new
|
||||
}
|
||||
|
||||
|
||||
private const val BUILD_SRC_FOLDER_NAME = "buildSrc"
|
||||
private const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
|
||||
|
||||
private fun maxKotlinLibVersion(project: Project): LibInfo? {
|
||||
return runReadAction {
|
||||
var maxStdlibInfo: LibInfo? = null
|
||||
|
||||
val allLibProcessor = CommonProcessors.CollectUniquesProcessor<Library>()
|
||||
ProjectRootManager.getInstance(project).orderEntries().forEachLibrary(allLibProcessor)
|
||||
|
||||
for (library in allLibProcessor.results) {
|
||||
if (!ExternalSystemApiUtil.isExternalSystemLibrary(library, GRADLE_SYSTEM_ID) &&
|
||||
!ExternalSystemApiUtil.isExternalSystemLibrary(library, MAVEN_SYSTEM_ID)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (library.name?.contains(" $KOTLIN_GROUP_ID:kotlin-stdlib") != true) {
|
||||
continue
|
||||
}
|
||||
|
||||
val libraryInfo = parseExternalLibraryName(library) ?: continue
|
||||
|
||||
if (maxStdlibInfo == null || VersionComparatorUtil.COMPARATOR.compare(libraryInfo.version, maxStdlibInfo.version) > 0) {
|
||||
maxStdlibInfo = LibInfo(KOTLIN_GROUP_ID, libraryInfo.artifactId, libraryInfo.version)
|
||||
}
|
||||
}
|
||||
|
||||
maxStdlibInfo
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectMaxCompilerSettings(project: Project): LanguageVersionSettings {
|
||||
return runReadAction {
|
||||
var maxApiVersion: ApiVersion? = null
|
||||
var maxLanguageVersion: LanguageVersion? = null
|
||||
|
||||
for (module in ModuleManager.getInstance(project).modules) {
|
||||
if (!module.isKotlinModule()) {
|
||||
// Otherwise project compiler settings will give unreliable maximum for compiler settings
|
||||
continue
|
||||
}
|
||||
|
||||
val languageVersionSettings = module.languageVersionSettings
|
||||
|
||||
if (maxApiVersion == null || languageVersionSettings.apiVersion > maxApiVersion) {
|
||||
maxApiVersion = languageVersionSettings.apiVersion
|
||||
}
|
||||
|
||||
if (maxLanguageVersion == null || languageVersionSettings.languageVersion > maxLanguageVersion) {
|
||||
maxLanguageVersion = languageVersionSettings.languageVersion
|
||||
}
|
||||
}
|
||||
|
||||
LanguageVersionSettingsImpl(maxLanguageVersion ?: LanguageVersion.LATEST_STABLE, maxApiVersion ?: ApiVersion.LATEST_STABLE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Module.isKotlinModule(): Boolean {
|
||||
if (isDisposed) return false
|
||||
|
||||
if (KotlinFacet.get(this) != null) {
|
||||
return true
|
||||
}
|
||||
|
||||
// This code works only for Maven and Gradle import, and it's expected that Kotlin facets are configured for
|
||||
// all modules with external system.
|
||||
return false
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
typealias KotlinMigrationProjectService = KotlinMigrationProjectComponent
|
||||
typealias MigrationTestState = KotlinMigrationProjectComponent.MigrationTestState
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
internal object MLCompletionForKotlin {
|
||||
const val isAvailable: Boolean = false
|
||||
|
||||
var isEnabled: Boolean
|
||||
get() = false
|
||||
set(value) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.framework
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.projectRoots.*
|
||||
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
|
||||
import com.intellij.util.Consumer
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import javax.swing.JComponent
|
||||
|
||||
class KotlinSdkType : SdkType("KotlinSDK") {
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = KotlinSdkType()
|
||||
|
||||
val defaultHomePath: String
|
||||
get() = PathUtil.kotlinPathsForIdeaPlugin.homePath.absolutePath
|
||||
|
||||
@JvmOverloads
|
||||
fun setUpIfNeeded(disposable: Disposable? = null, checkIfNeeded: () -> Boolean = { true }) {
|
||||
val projectSdks: Array<Sdk> = ProjectJdkTable.getInstance().allJdks
|
||||
if (projectSdks.any { it.sdkType is KotlinSdkType }) return
|
||||
if (!checkIfNeeded()) return // do not create Kotlin SDK
|
||||
|
||||
val newSdkName = SdkConfigurationUtil.createUniqueSdkName(INSTANCE, defaultHomePath, projectSdks.toList())
|
||||
val newJdk = ProjectJdkImpl(newSdkName, INSTANCE)
|
||||
newJdk.homePath = defaultHomePath
|
||||
INSTANCE.setupSdkPaths(newJdk)
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait {
|
||||
runWriteAction {
|
||||
if (ProjectJdkTable.getInstance().allJdks.any { it.sdkType is KotlinSdkType }) return@runWriteAction
|
||||
if (disposable != null) {
|
||||
ProjectJdkTable.getInstance().addJdk(newJdk, disposable)
|
||||
} else {
|
||||
ProjectJdkTable.getInstance().addJdk(newJdk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPresentableName() = KotlinBundle.message("framework.name.kotlin.sdk")
|
||||
|
||||
override fun getIcon() = KotlinIcons.SMALL_LOGO
|
||||
|
||||
override fun isValidSdkHome(path: String?) = true
|
||||
|
||||
override fun suggestSdkName(currentSdkName: String?, sdkHome: String?) = "Kotlin SDK"
|
||||
|
||||
override fun suggestHomePath() = null
|
||||
|
||||
override fun sdkHasValidPath(sdk: Sdk) = true
|
||||
|
||||
override fun getVersionString(sdk: Sdk) = bundledRuntimeVersion()
|
||||
|
||||
override fun supportsCustomCreateUI() = true
|
||||
|
||||
override fun showCustomCreateUI(sdkModel: SdkModel, parentComponent: JComponent, selectedSdk: Sdk?, sdkCreatedCallback: Consumer<Sdk>) {
|
||||
sdkCreatedCallback.consume(createSdkWithUniqueName(sdkModel.sdks.toList()))
|
||||
}
|
||||
|
||||
fun createSdkWithUniqueName(existingSdks: Collection<Sdk>): ProjectJdkImpl {
|
||||
val sdkName = suggestSdkName(SdkConfigurationUtil.createUniqueSdkName(this, "", existingSdks), "")
|
||||
return ProjectJdkImpl(sdkName, this).apply {
|
||||
homePath = defaultHomePath
|
||||
}
|
||||
}
|
||||
|
||||
override fun createAdditionalDataConfigurable(sdkModel: SdkModel, sdkModificator: SdkModificator) = null
|
||||
|
||||
override fun saveAdditionalData(additionalData: SdkAdditionalData, additional: Element) {
|
||||
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.hierarchy.calls
|
||||
|
||||
import com.intellij.ide.hierarchy.call.CallHierarchyNodeDescriptor
|
||||
import com.intellij.psi.PsiMethod
|
||||
|
||||
fun extractMemberFromDescriptor(nodeDescriptor: CallHierarchyNodeDescriptor): PsiMethod? {
|
||||
return nodeDescriptor.enclosingElement as? PsiMethod
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.kotlin.idea.js
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.CompilerModuleExtension
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.idea.framework.isGradleModule
|
||||
import org.jetbrains.kotlin.idea.project.platform
|
||||
import org.jetbrains.kotlin.platform.js.isJs
|
||||
import org.jetbrains.plugins.gradle.settings.GradleSystemRunningSettings
|
||||
|
||||
val Module.jsTestOutputFilePath: String?
|
||||
get() {
|
||||
KotlinFacet.get(this)?.configuration?.settings?.testOutputPath?.let { return it }
|
||||
|
||||
if (!shouldUseJpsOutput) return null
|
||||
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(this)
|
||||
val outputDir = compilerExtension?.compilerOutputUrlForTests ?: return null
|
||||
return JpsPathUtil.urlToPath("$outputDir/${name}_test.js")
|
||||
}
|
||||
|
||||
val Module.jsProductionOutputFilePath: String?
|
||||
get() {
|
||||
KotlinFacet.get(this)?.configuration?.settings?.productionOutputPath?.let { return it }
|
||||
|
||||
if (!shouldUseJpsOutput) return null
|
||||
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(this)
|
||||
val outputDir = compilerExtension?.compilerOutputUrl ?: return null
|
||||
return JpsPathUtil.urlToPath("$outputDir/$name.js")
|
||||
}
|
||||
|
||||
fun Module.asJsModule(): Module? = takeIf { it.platform.isJs() }
|
||||
|
||||
val Module.shouldUseJpsOutput: Boolean
|
||||
get() = !(isGradleModule() && GradleSystemRunningSettings.getInstance().isUseGradleAwareMake)
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.migration
|
||||
|
||||
import com.intellij.codeInspection.InspectionEP
|
||||
import com.intellij.codeInspection.InspectionProfileEntry
|
||||
import com.intellij.codeInspection.ex.InspectionManagerEx
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper
|
||||
import com.intellij.codeInspection.ex.createSimple
|
||||
import com.intellij.openapi.util.InvalidDataException
|
||||
import com.intellij.openapi.util.WriteExternalException
|
||||
import com.intellij.profile.codeInspection.InspectionProfileManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.configuration.MigrationInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.migration.MigrationFix
|
||||
import java.util.*
|
||||
|
||||
fun createMigrationProfile(
|
||||
managerEx: InspectionManagerEx,
|
||||
psiElement: PsiElement?,
|
||||
migrationInfo: MigrationInfo? = null
|
||||
): InspectionProfileImpl {
|
||||
val rootProfile = InspectionProfileManager.getInstance().currentProfile
|
||||
|
||||
val migrationFixWrappers = applicableMigrationToolsImpl(migrationInfo)
|
||||
|
||||
val allWrappers = LinkedHashSet<InspectionToolWrapper<*, *>>()
|
||||
for (toolWrapper in migrationFixWrappers) {
|
||||
allWrappers.add(toolWrapper)
|
||||
rootProfile.collectDependentInspections(toolWrapper, allWrappers, managerEx.project)
|
||||
}
|
||||
|
||||
val model = createSimple(KotlinBundle.message("inspection.migration.profile.name"), managerEx.project, migrationFixWrappers)
|
||||
try {
|
||||
val element = Element("toCopy")
|
||||
for (wrapper in migrationFixWrappers) {
|
||||
wrapper.tool.writeSettings(element)
|
||||
val tw = (if (psiElement == null)
|
||||
model.getInspectionTool(wrapper.shortName, managerEx.project)
|
||||
else
|
||||
model.getInspectionTool(wrapper.shortName, psiElement))!!
|
||||
|
||||
tw.tool.readSettings(element)
|
||||
}
|
||||
} catch (ignored: WriteExternalException) {
|
||||
} catch (ignored: InvalidDataException) {
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
|
||||
fun applicableMigrationTools(migrationInfo: MigrationInfo) = applicableMigrationToolsImpl(migrationInfo)
|
||||
|
||||
private fun applicableMigrationToolsImpl(migrationInfo: MigrationInfo?): List<InspectionToolWrapper<InspectionProfileEntry, InspectionEP>> {
|
||||
val rootProfile = InspectionProfileManager.getInstance().currentProfile
|
||||
|
||||
return rootProfile.allTools.asSequence()
|
||||
.map { it.tool }
|
||||
.filter { toolWrapper: InspectionToolWrapper<*, *> ->
|
||||
val tool = toolWrapper.tool
|
||||
tool is MigrationFix && (migrationInfo == null || tool.isApplicable(migrationInfo))
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
-512
@@ -1,512 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.changeSignature.ui
|
||||
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager
|
||||
import com.intellij.openapi.editor.colors.EditorFontType
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.openapi.options.ConfigurationException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.ui.VerticalFlowLayout
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiCodeFragment
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.changeSignature.ChangeSignatureDialogBase
|
||||
import com.intellij.refactoring.changeSignature.MethodDescriptor
|
||||
import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase
|
||||
import com.intellij.refactoring.ui.ComboBoxVisibilityPanel
|
||||
import com.intellij.ui.DottedBorder
|
||||
import com.intellij.ui.EditorTextField
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.ui.treeStructure.Tree
|
||||
import com.intellij.util.Consumer
|
||||
import com.intellij.util.IJSwingUtilities
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import com.intellij.util.ui.table.JBTableRow
|
||||
import com.intellij.util.ui.table.JBTableRowEditor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor.Kind
|
||||
import org.jetbrains.kotlin.idea.refactoring.validateElement
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Font
|
||||
import java.awt.Toolkit
|
||||
import java.awt.event.ItemEvent
|
||||
import java.util.*
|
||||
import javax.swing.*
|
||||
|
||||
class KotlinChangeSignatureDialog(
|
||||
project: Project,
|
||||
methodDescriptor: KotlinMethodDescriptor,
|
||||
context: PsiElement,
|
||||
private val commandName: String?
|
||||
) : ChangeSignatureDialogBase<
|
||||
KotlinParameterInfo,
|
||||
PsiElement,
|
||||
Visibility,
|
||||
KotlinMethodDescriptor,
|
||||
ParameterTableModelItemBase<KotlinParameterInfo>,
|
||||
KotlinCallableParameterTableModel>(project, methodDescriptor, false, context) {
|
||||
override fun getFileType(): KotlinFileType = KotlinFileType.INSTANCE
|
||||
|
||||
override fun createParametersInfoModel(descriptor: KotlinMethodDescriptor) =
|
||||
createParametersInfoModel(descriptor, myDefaultValueContext)
|
||||
|
||||
override fun createReturnTypeCodeFragment() = createReturnTypeCodeFragment(myProject, myMethod)
|
||||
|
||||
private val parametersTableModel: KotlinCallableParameterTableModel get() = super.myParametersTableModel
|
||||
|
||||
override fun getRowPresentation(
|
||||
item: ParameterTableModelItemBase<KotlinParameterInfo>,
|
||||
selected: Boolean,
|
||||
focused: Boolean
|
||||
): JComponent? {
|
||||
val panel = JPanel(BorderLayout())
|
||||
|
||||
val valOrVar = if (myMethod.kind === Kind.PRIMARY_CONSTRUCTOR) {
|
||||
when (item.parameter.valOrVar) {
|
||||
KotlinValVar.None -> " "
|
||||
KotlinValVar.Val -> "val "
|
||||
KotlinValVar.Var -> "var "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
val parameterName = getPresentationName(item)
|
||||
val typeText = item.typeCodeFragment.text
|
||||
val defaultValue = item.defaultValueCodeFragment.text
|
||||
val separator = StringUtil.repeatSymbol(' ', getParamNamesMaxLength() - parameterName.length + 1)
|
||||
val text = "$valOrVar$parameterName:$separator$typeText" + if (StringUtil.isNotEmpty(defaultValue)) {
|
||||
KotlinBundle.message("text.default.value", defaultValue)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
val field = object : EditorTextField(" $text", project, fileType) {
|
||||
override fun shouldHaveBorder() = false
|
||||
}
|
||||
|
||||
val plainFont = EditorColorsManager.getInstance().globalScheme.getFont(EditorFontType.PLAIN)
|
||||
field.font = Font(plainFont.fontName, plainFont.style, 12)
|
||||
|
||||
if (selected && focused) {
|
||||
panel.background = UIUtil.getTableSelectionBackground()
|
||||
field.setAsRendererWithSelection(UIUtil.getTableSelectionBackground(), UIUtil.getTableSelectionForeground())
|
||||
} else {
|
||||
panel.background = UIUtil.getTableBackground()
|
||||
if (selected && !focused) {
|
||||
panel.border = DottedBorder(UIUtil.getTableForeground())
|
||||
}
|
||||
}
|
||||
panel.add(field, BorderLayout.WEST)
|
||||
|
||||
return panel
|
||||
}
|
||||
|
||||
private fun getPresentationName(item: ParameterTableModelItemBase<KotlinParameterInfo>): String {
|
||||
val parameter = item.parameter
|
||||
return if (parameter == parametersTableModel.receiver) "<receiver>" else parameter.name
|
||||
}
|
||||
|
||||
private fun getColumnTextMaxLength(nameFunction: Function1<ParameterTableModelItemBase<KotlinParameterInfo>, String?>) =
|
||||
parametersTableModel.items.asSequence().map { nameFunction(it)?.length ?: 0 }.max() ?: 0
|
||||
|
||||
private fun getParamNamesMaxLength() = getColumnTextMaxLength { getPresentationName(it) }
|
||||
|
||||
private fun getTypesMaxLength() = getColumnTextMaxLength { it.typeCodeFragment?.text }
|
||||
|
||||
private fun getDefaultValuesMaxLength() = getColumnTextMaxLength { it.defaultValueCodeFragment?.text }
|
||||
|
||||
override fun isListTableViewSupported() = true
|
||||
|
||||
override fun isEmptyRow(row: ParameterTableModelItemBase<KotlinParameterInfo>): Boolean {
|
||||
if (row.parameter.name.isNotEmpty()) return false
|
||||
if (row.parameter.typeText.isNotEmpty()) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createCallerChooser(title: String, treeToReuse: Tree?, callback: Consumer<Set<PsiElement>>) =
|
||||
KotlinCallerChooser(myMethod.method, myProject, title, treeToReuse, callback)
|
||||
|
||||
// Forbid receiver propagation
|
||||
override fun mayPropagateParameters() =
|
||||
parameters.any { it.isNewParameter && it != parametersTableModel.receiver }
|
||||
|
||||
override fun getTableEditor(table: JTable, item: ParameterTableModelItemBase<KotlinParameterInfo>): JBTableRowEditor? {
|
||||
return object : JBTableRowEditor() {
|
||||
private val components = ArrayList<JComponent>()
|
||||
private val nameEditor = EditorTextField(item.parameter.name, project, fileType)
|
||||
|
||||
private fun updateNameEditor() {
|
||||
nameEditor.isEnabled = item.parameter != parametersTableModel.receiver
|
||||
}
|
||||
|
||||
private fun isDefaultColumnEnabled() =
|
||||
item.parameter.isNewParameter && item.parameter != myMethod.receiver
|
||||
|
||||
override fun prepareEditor(table: JTable, row: Int) {
|
||||
layout = BoxLayout(this, BoxLayout.X_AXIS)
|
||||
var column = 0
|
||||
|
||||
for (columnInfo in parametersTableModel.columnInfos) {
|
||||
val panel = JPanel(VerticalFlowLayout(VerticalFlowLayout.TOP, 4, 2, true, false))
|
||||
val editor: EditorTextField?
|
||||
val component: JComponent
|
||||
val columnFinal = column
|
||||
|
||||
if (KotlinCallableParameterTableModel.isTypeColumn(columnInfo)) {
|
||||
val document = PsiDocumentManager.getInstance(project).getDocument(item.typeCodeFragment)
|
||||
editor = EditorTextField(document, project, fileType)
|
||||
component = editor
|
||||
} else if (KotlinCallableParameterTableModel.isNameColumn(columnInfo)) {
|
||||
editor = nameEditor
|
||||
component = editor
|
||||
updateNameEditor()
|
||||
} else if (KotlinCallableParameterTableModel.isDefaultValueColumn(columnInfo) && isDefaultColumnEnabled()) {
|
||||
val document = PsiDocumentManager.getInstance(project).getDocument(item.defaultValueCodeFragment)
|
||||
editor = EditorTextField(document, project, fileType)
|
||||
component = editor
|
||||
} else if (KotlinPrimaryConstructorParameterTableModel.isValVarColumn(columnInfo)) {
|
||||
val comboBox = JComboBox(KotlinValVar.values())
|
||||
comboBox.selectedItem = item.parameter.valOrVar
|
||||
comboBox.addItemListener {
|
||||
parametersTableModel.setValueAtWithoutUpdate(it.item, row, columnFinal)
|
||||
updateSignature()
|
||||
}
|
||||
component = comboBox
|
||||
editor = null
|
||||
} else if (KotlinFunctionParameterTableModel.isReceiverColumn(columnInfo)) {
|
||||
val checkBox = JCheckBox()
|
||||
checkBox.isSelected = parametersTableModel.receiver == item.parameter
|
||||
checkBox.addItemListener {
|
||||
val newReceiver = if (it.stateChange == ItemEvent.SELECTED) item.parameter else null
|
||||
(parametersTableModel as KotlinFunctionParameterTableModel).receiver = newReceiver
|
||||
updateSignature()
|
||||
updateNameEditor()
|
||||
}
|
||||
component = checkBox
|
||||
editor = null
|
||||
} else
|
||||
continue
|
||||
|
||||
val label = JBLabel(columnInfo.name, UIUtil.ComponentStyle.SMALL)
|
||||
panel.add(label)
|
||||
|
||||
if (editor != null) {
|
||||
editor.addDocumentListener(
|
||||
object : DocumentListener {
|
||||
override fun documentChanged(e: DocumentEvent) {
|
||||
fireDocumentChanged(e, columnFinal)
|
||||
}
|
||||
}
|
||||
)
|
||||
editor.setPreferredWidth(table.width / parametersTableModel.columnCount)
|
||||
}
|
||||
|
||||
components.add(component)
|
||||
panel.add(component)
|
||||
add(panel)
|
||||
IJSwingUtilities.adjustComponentsOnMac(label, component)
|
||||
column++
|
||||
}
|
||||
}
|
||||
|
||||
override fun getValue(): JBTableRow {
|
||||
return JBTableRow { column ->
|
||||
val columnInfo = parametersTableModel.columnInfos[column]
|
||||
|
||||
when {
|
||||
KotlinPrimaryConstructorParameterTableModel.isValVarColumn(columnInfo) ->
|
||||
(components[column] as @Suppress("NO_TYPE_ARGUMENTS_ON_RHS") JComboBox).selectedItem
|
||||
KotlinCallableParameterTableModel.isTypeColumn(columnInfo) ->
|
||||
item.typeCodeFragment
|
||||
KotlinCallableParameterTableModel.isNameColumn(columnInfo) ->
|
||||
(components[column] as EditorTextField).text
|
||||
KotlinCallableParameterTableModel.isDefaultValueColumn(columnInfo) ->
|
||||
item.defaultValueCodeFragment
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColumnWidth(letters: Int): Int {
|
||||
var font = EditorColorsManager.getInstance().globalScheme.getFont(EditorFontType.PLAIN)
|
||||
font = Font(font.fontName, font.style, 12)
|
||||
return letters * Toolkit.getDefaultToolkit().getFontMetrics(font).stringWidth("W")
|
||||
}
|
||||
|
||||
private fun getEditorIndex(x: Int): Int {
|
||||
@Suppress("NAME_SHADOWING") var x = x
|
||||
|
||||
val columnLetters = if (isDefaultColumnEnabled())
|
||||
intArrayOf(4, getParamNamesMaxLength(), getTypesMaxLength(), getDefaultValuesMaxLength())
|
||||
else
|
||||
intArrayOf(4, getParamNamesMaxLength(), getTypesMaxLength())
|
||||
|
||||
var columnIndex = 0
|
||||
for (i in (if (myMethod.kind === Kind.PRIMARY_CONSTRUCTOR) 0 else 1) until columnLetters.size) {
|
||||
val width = getColumnWidth(columnLetters[i])
|
||||
|
||||
if (x <= width)
|
||||
return columnIndex
|
||||
|
||||
columnIndex++
|
||||
x -= width
|
||||
}
|
||||
|
||||
return columnIndex - 1
|
||||
}
|
||||
|
||||
override fun getPreferredFocusedComponent(): JComponent {
|
||||
val me = mouseEvent
|
||||
val index = when {
|
||||
me != null -> getEditorIndex(me.point.getX().toInt())
|
||||
myMethod.kind === Kind.PRIMARY_CONSTRUCTOR -> 1
|
||||
else -> 0
|
||||
}
|
||||
val component = components[index]
|
||||
return if (component is EditorTextField) component.focusTarget else component
|
||||
}
|
||||
|
||||
override fun getFocusableComponents(): Array<JComponent> {
|
||||
return Array(components.size) {
|
||||
val component = components[it]
|
||||
(component as? EditorTextField)?.focusTarget ?: component
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun calculateSignature(): String {
|
||||
val changeInfo = evaluateChangeInfo(
|
||||
parametersTableModel,
|
||||
myReturnTypeCodeFragment,
|
||||
getMethodDescriptor(),
|
||||
visibility,
|
||||
methodName,
|
||||
myDefaultValueContext,
|
||||
true
|
||||
)
|
||||
return changeInfo.getNewSignature(getMethodDescriptor().originalPrimaryCallable)
|
||||
}
|
||||
|
||||
override fun createVisibilityControl() = ComboBoxVisibilityPanel(
|
||||
arrayOf(Visibilities.INTERNAL, Visibilities.PRIVATE, Visibilities.PROTECTED, Visibilities.PUBLIC)
|
||||
)
|
||||
|
||||
override fun updateSignatureAlarmFired() {
|
||||
super.updateSignatureAlarmFired()
|
||||
validateButtons()
|
||||
}
|
||||
|
||||
override fun validateAndCommitData(): String? {
|
||||
if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite &&
|
||||
myReturnTypeCodeFragment.getTypeInfo(isCovariant = true, forPreview = false).type == null
|
||||
) {
|
||||
if (showOkCancelDialog(
|
||||
myProject,
|
||||
KotlinBundle.message("message.text.return.type.cannot.be.resolved",
|
||||
myReturnTypeCodeFragment?.text.toString()
|
||||
),
|
||||
RefactoringBundle.message("changeSignature.refactoring.name"),
|
||||
Messages.getWarningIcon()
|
||||
) != Messages.OK
|
||||
) {
|
||||
return EXIT_SILENTLY
|
||||
}
|
||||
}
|
||||
|
||||
for (item in parametersTableModel.items) {
|
||||
if (item.typeCodeFragment.getTypeInfo(isCovariant = true, forPreview = false).type == null) {
|
||||
val paramText = if (item.parameter != parametersTableModel.receiver)
|
||||
KotlinBundle.message("text.parameter.0", item.parameter.name)
|
||||
else
|
||||
KotlinBundle.message("text.receiver")
|
||||
if (showOkCancelDialog(
|
||||
myProject,
|
||||
KotlinBundle.message("message.type.for.cannot.be.resolved",
|
||||
item.typeCodeFragment.text,
|
||||
paramText
|
||||
),
|
||||
RefactoringBundle.message("changeSignature.refactoring.name"),
|
||||
Messages.getWarningIcon()
|
||||
) != Messages.OK
|
||||
) {
|
||||
return EXIT_SILENTLY
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun canRun() {
|
||||
if (myNamePanel.isVisible && myMethod.canChangeName() && !methodName.isIdentifier()) {
|
||||
throw ConfigurationException(KotlinBundle.message("function.name.is.invalid"))
|
||||
}
|
||||
|
||||
if (myMethod.canChangeReturnType() === MethodDescriptor.ReadWriteOption.ReadWrite) {
|
||||
(myReturnTypeCodeFragment as? KtTypeCodeFragment)
|
||||
?.validateElement(KotlinBundle.message("return.type.is.invalid"))
|
||||
}
|
||||
|
||||
for (item in parametersTableModel.items) {
|
||||
val parameterName = item.parameter.name
|
||||
|
||||
if (item.parameter != parametersTableModel.receiver && !parameterName.isIdentifier()) {
|
||||
throw ConfigurationException(KotlinBundle.message("parameter.name.is.invalid", parameterName))
|
||||
}
|
||||
|
||||
(item.typeCodeFragment as? KtTypeCodeFragment)
|
||||
?.validateElement(KotlinBundle.message("parameter.type.is.invalid", item.typeCodeFragment.text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun createRefactoringProcessor(): BaseRefactoringProcessor {
|
||||
val changeInfo = evaluateChangeInfo(
|
||||
parametersTableModel,
|
||||
myReturnTypeCodeFragment,
|
||||
getMethodDescriptor(),
|
||||
visibility,
|
||||
methodName,
|
||||
myDefaultValueContext,
|
||||
false
|
||||
)
|
||||
changeInfo.primaryPropagationTargets = myMethodsToPropagateParameters ?: emptyList()
|
||||
return KotlinChangeSignatureProcessor(myProject, changeInfo, commandName ?: title)
|
||||
}
|
||||
|
||||
private fun getMethodDescriptor(): KotlinMethodDescriptor = myMethod
|
||||
|
||||
override fun getSelectedIdx(): Int {
|
||||
return myMethod.parameters.withIndex().firstOrNull { it.value.isNewParameter }?.index
|
||||
?: super.getSelectedIdx()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun createParametersInfoModel(
|
||||
descriptor: KotlinMethodDescriptor,
|
||||
defaultValueContext: PsiElement
|
||||
): KotlinCallableParameterTableModel {
|
||||
val typeContext = getTypeCodeFragmentContext(descriptor.baseDeclaration)
|
||||
return when (descriptor.kind) {
|
||||
Kind.FUNCTION -> KotlinFunctionParameterTableModel(descriptor, typeContext, defaultValueContext)
|
||||
Kind.PRIMARY_CONSTRUCTOR -> KotlinPrimaryConstructorParameterTableModel(descriptor, typeContext, defaultValueContext)
|
||||
Kind.SECONDARY_CONSTRUCTOR -> KotlinSecondaryConstructorParameterTableModel(descriptor, typeContext, defaultValueContext)
|
||||
}
|
||||
}
|
||||
|
||||
fun getTypeCodeFragmentContext(startFrom: PsiElement): KtElement {
|
||||
return startFrom.parentsWithSelf.mapNotNull {
|
||||
when {
|
||||
it is KtNamedFunction -> it.bodyExpression ?: it.valueParameterList
|
||||
it is KtPropertyAccessor -> it.bodyExpression
|
||||
it is KtDeclaration && KtPsiUtil.isLocal(it) -> null
|
||||
it is KtConstructor<*> -> it
|
||||
it is KtClassOrObject -> it
|
||||
it is KtFile -> it
|
||||
else -> null
|
||||
}
|
||||
}.first()
|
||||
}
|
||||
|
||||
private fun createReturnTypeCodeFragment(project: Project, method: KotlinMethodDescriptor) =
|
||||
KtPsiFactory(project).createTypeCodeFragment(method.returnTypeInfo.render(), getTypeCodeFragmentContext(method.baseDeclaration))
|
||||
|
||||
fun createRefactoringProcessorForSilentChangeSignature(
|
||||
project: Project,
|
||||
commandName: String,
|
||||
method: KotlinMethodDescriptor,
|
||||
defaultValueContext: PsiElement
|
||||
): BaseRefactoringProcessor {
|
||||
val parameterTableModel = createParametersInfoModel(method, defaultValueContext)
|
||||
parameterTableModel.setParameterInfos(method.parameters)
|
||||
val changeInfo = evaluateChangeInfo(
|
||||
parameterTableModel,
|
||||
createReturnTypeCodeFragment(project, method),
|
||||
method,
|
||||
method.visibility,
|
||||
method.name,
|
||||
defaultValueContext,
|
||||
false
|
||||
)
|
||||
return KotlinChangeSignatureProcessor(project, changeInfo, commandName)
|
||||
}
|
||||
|
||||
fun PsiCodeFragment?.getTypeInfo(isCovariant: Boolean, forPreview: Boolean): KotlinTypeInfo {
|
||||
if (this !is KtTypeCodeFragment) return KotlinTypeInfo(isCovariant)
|
||||
|
||||
val typeRef = getContentElement()
|
||||
val type = typeRef?.analyze(BodyResolveMode.PARTIAL)?.get(BindingContext.TYPE, typeRef)
|
||||
return when {
|
||||
type != null && !type.isError -> KotlinTypeInfo(isCovariant, type, if (forPreview) typeRef.text else null)
|
||||
typeRef != null -> KotlinTypeInfo(isCovariant, null, typeRef.text)
|
||||
else -> KotlinTypeInfo(isCovariant)
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluateChangeInfo(
|
||||
parametersModel: KotlinCallableParameterTableModel,
|
||||
returnTypeCodeFragment: PsiCodeFragment?,
|
||||
methodDescriptor: KotlinMethodDescriptor,
|
||||
visibility: Visibility?,
|
||||
methodName: String,
|
||||
defaultValueContext: PsiElement,
|
||||
forPreview: Boolean
|
||||
): KotlinChangeInfo {
|
||||
val parameters = parametersModel.items.map { parameter ->
|
||||
val parameterInfo = parameter.parameter
|
||||
|
||||
parameterInfo.currentTypeInfo = parameter.typeCodeFragment.getTypeInfo(false, forPreview)
|
||||
|
||||
val codeFragment = parameter.defaultValueCodeFragment as KtExpressionCodeFragment
|
||||
val oldDefaultValue = parameterInfo.defaultValueForCall
|
||||
if (codeFragment.text != (if (oldDefaultValue != null) oldDefaultValue.text else "")) {
|
||||
parameterInfo.defaultValueForCall = codeFragment.getContentElement()
|
||||
}
|
||||
|
||||
parameterInfo
|
||||
}
|
||||
|
||||
return KotlinChangeInfo(
|
||||
methodDescriptor.original,
|
||||
methodName,
|
||||
returnTypeCodeFragment.getTypeInfo(true, forPreview),
|
||||
visibility ?: Visibilities.DEFAULT_VISIBILITY,
|
||||
parameters,
|
||||
parametersModel.receiver,
|
||||
defaultValueContext
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.cutPaste
|
||||
|
||||
import com.intellij.codeHighlighting.Pass
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPass
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
|
||||
import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.kotlin.idea.core.util.range
|
||||
|
||||
class MoveDeclarationsPassFactory(highlightingPassRegistrar: TextEditorHighlightingPassRegistrar) : ProjectComponent,
|
||||
TextEditorHighlightingPassFactory {
|
||||
|
||||
init {
|
||||
highlightingPassRegistrar.registerTextEditorHighlightingPass(
|
||||
this,
|
||||
TextEditorHighlightingPassRegistrar.Anchor.BEFORE,
|
||||
Pass.POPUP_HINTS,
|
||||
true,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
|
||||
return MyPass(file.project, file, editor)
|
||||
}
|
||||
|
||||
private class MyPass(
|
||||
private val project: Project,
|
||||
private val file: PsiFile,
|
||||
private val editor: Editor
|
||||
) : TextEditorHighlightingPass(project, editor.document, true) {
|
||||
|
||||
override fun doCollectInformation(progress: ProgressIndicator) {}
|
||||
|
||||
override fun doApplyInformationToEditor() {
|
||||
val info = buildHighlightingInfo()
|
||||
UpdateHighlightersUtil.setHighlightersToEditor(project, myDocument!!, 0, file.textLength, listOfNotNull(info), colorsScheme, id)
|
||||
}
|
||||
|
||||
private fun buildHighlightingInfo(): HighlightInfo? {
|
||||
val cookie = editor.getUserData(MoveDeclarationsEditorCookie.KEY) ?: return null
|
||||
|
||||
if (cookie.modificationCount != PsiModificationTracker.SERVICE.getInstance(project).modificationCount) return null
|
||||
|
||||
val processor = MoveDeclarationsProcessor.build(editor, cookie)
|
||||
|
||||
if (processor == null) {
|
||||
editor.putUserData(MoveDeclarationsEditorCookie.KEY, null)
|
||||
return null
|
||||
}
|
||||
|
||||
val info = HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION)
|
||||
.range(cookie.bounds.range!!)
|
||||
.createUnconditionally()
|
||||
QuickFixAction.registerQuickFixAction(info, MoveDeclarationsIntentionAction(processor, cookie.bounds, cookie.modificationCount))
|
||||
|
||||
return info
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.roots
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.roots.SourceFolder
|
||||
import com.intellij.openapi.vfs.NonPhysicalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiCodeFragment
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.jps.model.JpsElement
|
||||
import org.jetbrains.jps.model.ex.JpsElementBase
|
||||
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes
|
||||
import org.jetbrains.jps.model.java.JavaResourceRootType
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootProperties
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRoot
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
import java.util.*
|
||||
|
||||
private fun JpsModuleSourceRoot.getOrCreateProperties() =
|
||||
getProperties(rootType)?.also { (it as? JpsElementBase<*>)?.setParent(null) } ?: rootType.createDefaultProperties()
|
||||
|
||||
fun JpsModuleSourceRoot.getMigratedSourceRootTypeWithProperties(): Pair<JpsModuleSourceRootType<JpsElement>, JpsElement>? {
|
||||
val currentRootType = rootType
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val newSourceRootType: JpsModuleSourceRootType<JpsElement> = when (currentRootType) {
|
||||
JavaSourceRootType.SOURCE -> SourceKotlinRootType as JpsModuleSourceRootType<JpsElement>
|
||||
JavaSourceRootType.TEST_SOURCE -> TestSourceKotlinRootType
|
||||
JavaResourceRootType.RESOURCE -> ResourceKotlinRootType
|
||||
JavaResourceRootType.TEST_RESOURCE -> TestResourceKotlinRootType
|
||||
else -> return null
|
||||
} as JpsModuleSourceRootType<JpsElement>
|
||||
return newSourceRootType to getOrCreateProperties()
|
||||
}
|
||||
|
||||
fun migrateNonJvmSourceFolders(modifiableRootModel: ModifiableRootModel) {
|
||||
for (contentEntry in modifiableRootModel.contentEntries) {
|
||||
for (sourceFolder in contentEntry.sourceFolders) {
|
||||
val (newSourceRootType, properties) = sourceFolder.jpsElement.getMigratedSourceRootTypeWithProperties() ?: continue
|
||||
val url = sourceFolder.url
|
||||
contentEntry.removeSourceFolder(sourceFolder)
|
||||
contentEntry.addSourceFolder(url, newSourceRootType, properties)
|
||||
}
|
||||
}
|
||||
KotlinSdkType.setUpIfNeeded()
|
||||
}
|
||||
|
||||
fun populateNonJvmSourceRootTypes(sourceSetNode: DataNode<GradleSourceSetData>, module: Module) = Unit
|
||||
|
||||
fun getKotlinAwareDestinationSourceRoots(project: Project): List<VirtualFile> {
|
||||
return ModuleManager.getInstance(project).modules.flatMap { it.collectKotlinAwareDestinationSourceRoots() }
|
||||
}
|
||||
|
||||
private val KOTLIN_AWARE_SOURCE_ROOT_TYPES: Set<JpsModuleSourceRootType<JavaSourceRootProperties>> =
|
||||
JavaModuleSourceRootTypes.SOURCES + ALL_KOTLIN_SOURCE_ROOT_TYPES
|
||||
|
||||
private fun Module.collectKotlinAwareDestinationSourceRoots(): List<VirtualFile> {
|
||||
return rootManager
|
||||
.contentEntries
|
||||
.asSequence()
|
||||
.flatMap { it.getSourceFolders(KOTLIN_AWARE_SOURCE_ROOT_TYPES).asSequence() }
|
||||
.filterNot { isForGeneratedSources(it) }
|
||||
.mapNotNull { it.file }
|
||||
.toList()
|
||||
}
|
||||
|
||||
fun isOutsideSourceRootSet(psiFile: PsiFile?, sourceRootTypes: Set<JpsModuleSourceRootType<*>>): Boolean {
|
||||
if (psiFile == null || psiFile is PsiCodeFragment) return false
|
||||
val file = psiFile.virtualFile ?: return false
|
||||
if (file.fileSystem is NonPhysicalFileSystem) return false
|
||||
val projectFileIndex = ProjectRootManager.getInstance(psiFile.project).fileIndex
|
||||
return !projectFileIndex.isUnderSourceRootOfType(file, sourceRootTypes) && !projectFileIndex.isInLibrary(file)
|
||||
}
|
||||
|
||||
fun isOutsideKotlinAwareSourceRoot(psiFile: PsiFile?) = isOutsideSourceRootSet(psiFile, KOTLIN_AWARE_SOURCE_ROOT_TYPES)
|
||||
|
||||
/**
|
||||
* @return list of all java source roots in the project which can be suggested as a target directory for a class created by user
|
||||
*/
|
||||
fun getSuitableDestinationSourceRoots(project: Project): List<VirtualFile> {
|
||||
val roots = ArrayList<VirtualFile>()
|
||||
for (module in ModuleManager.getInstance(project).modules) {
|
||||
collectSuitableDestinationSourceRoots(module, roots)
|
||||
}
|
||||
return roots
|
||||
}
|
||||
|
||||
fun collectSuitableDestinationSourceRoots(module: Module, result: MutableList<VirtualFile>) {
|
||||
for (entry in ModuleRootManager.getInstance(module).contentEntries) {
|
||||
for (sourceFolder in entry.getSourceFolders(KOTLIN_AWARE_SOURCE_ROOT_TYPES)) {
|
||||
if (!isForGeneratedSources(sourceFolder)) {
|
||||
ContainerUtil.addIfNotNull(result, sourceFolder.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isForGeneratedSources(sourceFolder: SourceFolder): Boolean {
|
||||
val properties = sourceFolder.jpsElement.getProperties(KOTLIN_AWARE_SOURCE_ROOT_TYPES)
|
||||
val javaResourceProperties = sourceFolder.jpsElement.getProperties(JavaModuleSourceRootTypes.RESOURCES)
|
||||
val kotlinResourceProperties = sourceFolder.jpsElement.getProperties(ALL_KOTLIN_RESOURCE_ROOT_TYPES)
|
||||
return properties != null && properties.isForGeneratedSources
|
||||
|| (javaResourceProperties != null && javaResourceProperties.isForGeneratedSources)
|
||||
|| (kotlinResourceProperties != null && kotlinResourceProperties.isForGeneratedSources)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.intellij.openapi.util.ThrowableComputable
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
object ProgressIndicatorUtils {
|
||||
private val LOG = Logger.getInstance(ProgressIndicatorUtils::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun <T> underModalProgress(
|
||||
project: Project,
|
||||
@Nls progressTitle: String,
|
||||
computable: () -> T
|
||||
): T {
|
||||
val dumbService = DumbService.getInstance(project)
|
||||
val useAlternativeResolve = dumbService.isAlternativeResolveEnabled
|
||||
val inReadAction =
|
||||
ThrowableComputable<T, RuntimeException> { runReadAction { return@runReadAction computable() } }
|
||||
val prioritizedRunnable =
|
||||
ThrowableComputable<T, RuntimeException> { ProgressManager.getInstance().computePrioritized(inReadAction) }
|
||||
val process =
|
||||
if (useAlternativeResolve) ThrowableComputable { dumbService.computeWithAlternativeResolveEnabled(prioritizedRunnable) } else prioritizedRunnable
|
||||
return ProgressManager.getInstance().runProcessWithProgressSynchronously(process, progressTitle, true, project)
|
||||
}
|
||||
|
||||
fun <T> runUnderDisposeAwareIndicator(
|
||||
parent: Disposable,
|
||||
computable: () -> T
|
||||
): T = BackgroundTaskUtil.runUnderDisposeAwareIndicator(parent, Computable { computable() })
|
||||
|
||||
@JvmStatic
|
||||
fun <T> awaitWithCheckCanceled(future: Future<T>): T {
|
||||
while (true) {
|
||||
ProgressManager.checkCanceled()
|
||||
try {
|
||||
return future.get(50, TimeUnit.MILLISECONDS)
|
||||
} catch (e: TimeoutException) {
|
||||
// ignore
|
||||
} catch (e: Exception) {
|
||||
LOG.warn(e)
|
||||
throw ProcessCanceledException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.versions
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.BaseComponent
|
||||
import com.intellij.openapi.vfs.JarFileSystem
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||
import java.io.File
|
||||
|
||||
private val INSTALLED_KOTLIN_VERSION = "installed.kotlin.plugin.version"
|
||||
|
||||
/**
|
||||
* Component forces update for built-in libraries in plugin directory. They are ignored because of
|
||||
* com.intellij.util.indexing.FileBasedIndex.isUnderConfigOrSystem()
|
||||
*/
|
||||
// FIX ME WHEN BUNCH 192 REMOVED
|
||||
class KotlinUpdatePluginComponent : BaseComponent {
|
||||
override fun initComponent() {
|
||||
if (ApplicationManager.getApplication()?.isUnitTestMode == true) {
|
||||
return
|
||||
}
|
||||
|
||||
val installedKotlinVersion = PropertiesComponent.getInstance()?.getValue(INSTALLED_KOTLIN_VERSION)
|
||||
|
||||
if (installedKotlinVersion == null || KotlinPluginUtil.getPluginVersion() != installedKotlinVersion) {
|
||||
// Force refresh jar handlers
|
||||
for (libraryJarDescriptor in LibraryJarDescriptor.values()) {
|
||||
requestFullJarUpdate(libraryJarDescriptor.getPathInPlugin())
|
||||
}
|
||||
|
||||
PropertiesComponent.getInstance()?.setValue(INSTALLED_KOTLIN_VERSION, KotlinPluginUtil.getPluginVersion())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getComponentName(): String {
|
||||
return "ReindexBundledRuntimeComponent"
|
||||
}
|
||||
|
||||
override fun disposeComponent() {
|
||||
}
|
||||
|
||||
private fun requestFullJarUpdate(jarFilePath: File) {
|
||||
val localVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(jarFilePath) ?: return
|
||||
|
||||
// Build and update JarHandler
|
||||
val jarFile = JarFileSystem.getInstance().getJarRootForLocalFile(localVirtualFile) ?: return
|
||||
VfsUtilCore.visitChildrenRecursively(jarFile, object : VirtualFileVisitor<Any?>() {})
|
||||
((jarFile as NewVirtualFile)).markDirtyRecursively()
|
||||
}
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
Actual data differs from file content: ClassAndConstuctors.source.expected expected:< [SomeClassWithConstructors.class
|
||||
public final class <1><2><3><4>SomeClassWithConstructors public constructor(arg: kotlin.String)] {
|
||||
> but was:< [classAndConstructors.kt
|
||||
class <1><2><3><4>SomeClassWithConstructors(private val arg: String) ] {
|
||||
>
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
Actual data differs from file content: OverloadedFun.source.expected expected:<...d from a class file
|
||||
[// Implementation of methods is not available
|
||||
|
||||
package testData.libraries
|
||||
|
||||
@kotlin.jvm.JvmOverloads public fun <T> kotlin.String.<2><4><6>overloadedFun(vararg specs: kotlin.String, allowExisting: kotlin.Boolean /* = compiled code */, x: kotlin.Int, y: kotlin.Int /* = compiled code */, z: T): kotlin.String { /* compiled code */ }]
|
||||
> but was:<...d from a class file
|
||||
[ overloadedFun.kt
|
||||
fun <T> String.<2><4><6>overloadedFun(vararg specs: String, allowExisting: Boolean = false, x: Int, y: Int = 2, z: T): String {]
|
||||
>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
Actual data differs from file content: RenamedElements.source.expected expected:<[RenamedElementsKt.class
|
||||
<1>// IntelliJ API Decompiler stub source generated from a class file
|
||||
// Implementation of methods is not available
|
||||
|
||||
package testData.libraries
|
||||
|
||||
@kotlin.jvm.JvmName public fun <2>funToRename(x: kotlin.Int): kotlin.Unit { /* compiled code */ }]
|
||||
> but was:<[ RenamedElementsKt.class
|
||||
<1>// IntelliJ API Decompiler stub source generated from a class file
|
||||
renamedElements.kt
|
||||
fun <2>funToRename(x: Int) {]
|
||||
>
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
Actual data differs from file content: LibraryNestedClassSecondaryConstructorUsages.results.txt expected:<...3 class Y(): A.T()
|
||||
[[LibraryNestedClassSecondaryConstructorUsages.1.java] New instance creation 14 A.T a = new A.T();
|
||||
[LibraryNestedClassSecondaryConstructorUsages.1.java] Unclassified usage 10 super();
|
||||
[LibraryNestedClassSecondaryConstructorUsages.1.java] Unclassified usage 6 public J() {
|
||||
[library.kt] New instance creation 64 val tt = A.T()
|
||||
[library.kt] Supertype 40 class VV(): A.T()
|
||||
]> but was:<...3 class Y(): A.T()
|
||||
[[library.kt] New instance creation 64 val tt = A.T()
|
||||
[library.kt] Supertype 40 class VV(): A.T()]>
|
||||
idea/testData/findUsages/libraryUsages/kotlinLibrary/LibrarySecondaryConstructorUsages.0.kt.fail.192
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
Actual data differs from file content: LibrarySecondaryConstructorUsages.results.txt expected:<... 13 class Y(): A()
|
||||
[[LibrarySecondaryConstructorUsages.1.java] New instance creation 14 A a = new A();
|
||||
[LibrarySecondaryConstructorUsages.1.java] Unclassified usage 10 super();
|
||||
[LibrarySecondaryConstructorUsages.1.java] Unclassified usage 6 public J() {
|
||||
[]library.kt] New inst...> but was:<... 13 class Y(): A()
|
||||
[[]library.kt] New inst...>
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.2.60-dev-286'
|
||||
}
|
||||
group 'testgroup'
|
||||
version '1.0-SNAPSHOT'
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Compiler),number:1.2.60-dev-286,branch:(default:any)/artifacts/content/maven'
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
<node text="KA ()" base="true">
|
||||
<node text="JA ()"/>
|
||||
<node text="JA.newKA() ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient.bar ()"/>
|
||||
<node text="KClient.bar() ()"/>
|
||||
<node text="KClient.bar.localFun() ()"/>
|
||||
<node text="KClientObj ()"/>
|
||||
<node text="main0.kt ()"/>
|
||||
<node text="packageFun(String) ()"/>
|
||||
</node>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
<node text="KA.foo(String) ()" base="true">
|
||||
<node text="JA(2 usages) ()"/>
|
||||
<node text="JA.foo()(2 usages) ()"/>
|
||||
<node text="KClient(2 usages) ()"/>
|
||||
<node text="KClient(2 usages) ()"/>
|
||||
<node text="KClient.bar()(2 usages) ()"/>
|
||||
<node text="KClient.bar(2 usages) ()"/>
|
||||
<node text="KClient.bar.localFun()(2 usages) ()"/>
|
||||
<node text="KClientObj(2 usages) ()"/>
|
||||
<node text="main0.kt(2 usages) ()"/>
|
||||
<node text="packageFun(String)(2 usages) ()"/>
|
||||
</node>
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
<node text="T.KA ()" base="true">
|
||||
<node text="JA ()"/>
|
||||
<node text="JA.newKA() ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient.bar ()"/>
|
||||
<node text="KClient.bar() ()"/>
|
||||
<node text="KClient.bar.localFun() ()"/>
|
||||
<node text="KClientObj ()"/>
|
||||
<node text="main0.kt ()"/>
|
||||
<node text="packageFun(String) ()"/>
|
||||
</node>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
<node text="T.KA ()" base="true">
|
||||
<node text="JA ()"/>
|
||||
<node text="JA.newKA() ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient.bar ()"/>
|
||||
<node text="KClient.bar() ()"/>
|
||||
<node text="KClient.bar.localFun() ()"/>
|
||||
<node text="KClientObj ()"/>
|
||||
<node text="main0.kt ()"/>
|
||||
<node text="packageFun(String) ()"/>
|
||||
</node>
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
<node text="packageFun(String) ()" base="true">
|
||||
<node text="JA ()"/>
|
||||
<node text="JA.foo() ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient.bar ()"/>
|
||||
<node text="KClient.bar() ()"/>
|
||||
<node text="KClient.bar.localFun() ()"/>
|
||||
<node text="KClientObj ()"/>
|
||||
<node text="main0.kt ()"/>
|
||||
</node>
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
<node text="packageVal ()" base="true">
|
||||
<node text="JA ()"/>
|
||||
<node text="JA.getName()(2 usages) ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient ()"/>
|
||||
<node text="KClient.bar() ()"/>
|
||||
<node text="KClient.bar(2 usages) ()"/>
|
||||
<node text="KClient.bar.localFun() ()"/>
|
||||
<node text="KClientObj(2 usages) ()"/>
|
||||
<node text="packageFun(String) ()"/>
|
||||
</node>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
<node text="KA.name ()" base="true">
|
||||
<node text="JA(2 usages) ()"/>
|
||||
<node text="JA.getName()(2 usages) ()"/>
|
||||
<node text="KClient(2 usages) ()"/>
|
||||
<node text="KClient(2 usages) ()"/>
|
||||
<node text="KClient.bar()(2 usages) ()"/>
|
||||
<node text="KClient.bar(4 usages) ()"/>
|
||||
<node text="KClient.bar.localFun()(2 usages) ()"/>
|
||||
<node text="KClientObj(4 usages) ()"/>
|
||||
<node text="main0.kt(2 usages) ()"/>
|
||||
<node text="packageFun(String)(2 usages) ()"/>
|
||||
</node>
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
<node text="J.foo() ()" base="true">
|
||||
<node text="A(2 usages) ()"/>
|
||||
<node text="Main1Kt.test(J) ()"/>
|
||||
<node text="Main1Kt ()"/>
|
||||
</node>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user