193: Fix tests compilation for 193 platform
This commit is contained in:
+332
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* 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()).reparseRange(
|
||||
file, file.getNode(), TextRange.allOf(fileText), fileText, new EmptyProgressIndicator(), fileText);
|
||||
diffLog.performActualPsiChange(file);
|
||||
|
||||
TestCase.assertEquals(psiToStringDefault, DebugUtil.psiToString(file, false, false));
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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();
|
||||
// FIXME: There is no `Extensions.cleanRootArea` in 193
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.confidence;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.LightCompletionTestCase;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.completion.test.CompletionTestUtilKt;
|
||||
import org.jetbrains.kotlin.idea.test.TestUtilsKt;
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner.class)
|
||||
public class KotlinConfidenceTest extends LightCompletionTestCase {
|
||||
private static final String TYPE_DIRECTIVE_PREFIX = "// TYPE:";
|
||||
private final ThreadLocal<Boolean> skipComplete = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
public void testCompleteOnDotOutOfRanges() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testImportAsConfidence() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInBlockOfFunctionLiteral() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInModifierList() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNoAutoCompletionForRangeOperator() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNoAutoPopupInString() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAutoPopupInStringTemplate() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAutoPopupInStringTemplateAfterDollar() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNoAutoPopupInStringTemplateAfterSpace() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNoAutoPopupInRawStringTemplateAfterNewLine() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
TestUtilsKt.invalidateLibraryCache(getProject());
|
||||
}
|
||||
|
||||
protected void doTest() {
|
||||
boolean completeByChars = CodeInsightSettings.getInstance().SELECT_AUTOPOPUP_SUGGESTIONS_BY_CHARS;
|
||||
|
||||
CodeInsightSettings.getInstance().SELECT_AUTOPOPUP_SUGGESTIONS_BY_CHARS = true;
|
||||
|
||||
try {
|
||||
skipComplete.set(true);
|
||||
try {
|
||||
configureByFile(getBeforeFileName());
|
||||
} finally {
|
||||
skipComplete.set(false);
|
||||
}
|
||||
|
||||
String text = getEditor().getDocument().getText();
|
||||
boolean noLookup = InTextDirectivesUtils.isDirectiveDefined(text, "// NO_LOOKUP");
|
||||
if (!noLookup) complete(); //This will cause NPE in case of absence of autopopup completion
|
||||
|
||||
List<String> expectedElements = InTextDirectivesUtils.findLinesWithPrefixesRemoved(text, "// ELEMENT:");
|
||||
assertFalse("Can't both expect lookup elements and no lookup", !expectedElements.isEmpty() && noLookup);
|
||||
|
||||
if (noLookup) {
|
||||
try {
|
||||
Method m = null; //Looking for shouldSkipAutoPopup method (note, we can't use name because of scrambling in Ultimate)
|
||||
for (Method method : CodeCompletionHandlerBase.class.getDeclaredMethods()) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
if (method.getReturnType().equals(Boolean.TYPE) &&
|
||||
parameterTypes.length == 2 &&
|
||||
parameterTypes[0].equals(Editor.class) &&
|
||||
parameterTypes[1].equals(PsiFile.class)) {
|
||||
assertNull("Only one method with such signature should exist", m);
|
||||
m = method;
|
||||
}
|
||||
}
|
||||
assertNotNull(m);
|
||||
m.setAccessible(true);
|
||||
Object o = m.invoke(null, getEditor(), getFile());
|
||||
assert o instanceof Boolean;
|
||||
assertTrue("Should skip autopopup completion", ((Boolean) o).booleanValue());
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String typeText = getTypeText(text);
|
||||
if (!expectedElements.isEmpty()) {
|
||||
assertContainsItems(ArrayUtil.toStringArray(expectedElements));
|
||||
return;
|
||||
}
|
||||
assertNotNull("You must type something, use // TYPE:", typeText);
|
||||
type(typeText);
|
||||
checkResultByFile(getAfterFileName());
|
||||
}
|
||||
finally {
|
||||
CodeInsightSettings.getInstance().SELECT_AUTOPOPUP_SUGGESTIONS_BY_CHARS = completeByChars;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTypeText(String text) {
|
||||
String[] directives = InTextDirectivesUtils.findArrayWithPrefixes(text, TYPE_DIRECTIVE_PREFIX);
|
||||
if (directives.length == 0) return null;
|
||||
assertEquals("One directive with \"" + TYPE_DIRECTIVE_PREFIX +"\" expected", 1, directives.length);
|
||||
|
||||
return StringUtil.unquoteString(directives[0]);
|
||||
}
|
||||
|
||||
private String getBeforeFileName() {
|
||||
return getTestName(false) + ".kt";
|
||||
}
|
||||
|
||||
private String getAfterFileName() {
|
||||
return getTestName(false) + ".kt.after";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return new File(CompletionTestUtilKt.getCOMPLETION_TEST_DATA_BASE_PATH(), "/confidence/").getPath() + File.separator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return JavaSdk.getInstance().createJdk("JDK", SystemUtils.getJavaHome().getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void complete() {
|
||||
if (skipComplete.get()) return;
|
||||
new CodeCompletionHandlerBase(CompletionType.BASIC, false, true, true).invokeCompletion(
|
||||
getProject(), getEditor(), 0, false);
|
||||
|
||||
LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(getEditor());
|
||||
myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY);
|
||||
myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0));
|
||||
}
|
||||
}
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2010-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.idea.codeInsight.gradle;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.StreamUtil;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
|
||||
import org.gradle.tooling.BuildActionExecuter;
|
||||
import org.gradle.tooling.GradleConnector;
|
||||
import org.gradle.tooling.ProjectConnection;
|
||||
import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
|
||||
import org.gradle.util.GradleVersion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.model.ClassSetProjectImportModelProvider;
|
||||
import org.jetbrains.plugins.gradle.model.ExternalProject;
|
||||
import org.jetbrains.plugins.gradle.model.ProjectImportAction;
|
||||
import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
|
||||
import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assume.assumeThat;
|
||||
|
||||
// part of org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest
|
||||
@RunWith(value = Parameterized.class)
|
||||
public abstract class AbstractModelBuilderTest {
|
||||
|
||||
public static final Object[][] SUPPORTED_GRADLE_VERSIONS = {{"3.5"}, {"4.9"}};
|
||||
|
||||
private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*: with Gradle-.*)\\]");
|
||||
|
||||
private static File ourTempDir;
|
||||
|
||||
@NotNull
|
||||
private final String gradleVersion;
|
||||
private File testDir;
|
||||
private ProjectImportAction.AllModels allModels;
|
||||
|
||||
@Rule public TestName name = new TestName();
|
||||
@Rule public VersionMatcherRule versionMatcherRule = new VersionMatcherRule();
|
||||
|
||||
public AbstractModelBuilderTest(@NotNull String gradleVersion) {
|
||||
this.gradleVersion = gradleVersion;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "{index}: with Gradle-{0}")
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(SUPPORTED_GRADLE_VERSIONS);
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
assumeThat(gradleVersion, versionMatcherRule.getMatcher());
|
||||
|
||||
ensureTempDirCreated();
|
||||
|
||||
String methodName = name.getMethodName();
|
||||
Matcher m = TEST_METHOD_NAME_PATTERN.matcher(methodName);
|
||||
if (m.matches()) {
|
||||
methodName = m.group(1);
|
||||
}
|
||||
|
||||
testDir = new File(ourTempDir, methodName);
|
||||
FileUtil.ensureExists(testDir);
|
||||
|
||||
InputStream buildScriptStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.DEFAULT_SCRIPT_NAME);
|
||||
try {
|
||||
FileUtil.writeToFile(
|
||||
new File(testDir, GradleConstants.DEFAULT_SCRIPT_NAME),
|
||||
FileUtil.loadTextAndClose(buildScriptStream)
|
||||
);
|
||||
}
|
||||
finally {
|
||||
StreamUtil.closeStream(buildScriptStream);
|
||||
}
|
||||
|
||||
InputStream settingsStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.SETTINGS_FILE_NAME);
|
||||
try {
|
||||
if (settingsStream != null) {
|
||||
FileUtil.writeToFile(
|
||||
new File(testDir, GradleConstants.SETTINGS_FILE_NAME),
|
||||
FileUtil.loadTextAndClose(settingsStream)
|
||||
);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
StreamUtil.closeStream(settingsStream);
|
||||
}
|
||||
|
||||
GradleConnector connector = GradleConnector.newConnector();
|
||||
|
||||
URI distributionUri = new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
|
||||
connector.useDistribution(distributionUri);
|
||||
connector.forProjectDirectory(testDir);
|
||||
int daemonMaxIdleTime = 10;
|
||||
try {
|
||||
daemonMaxIdleTime = Integer.parseInt(System.getProperty("gradleDaemonMaxIdleTime", "10"));
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
}
|
||||
|
||||
((DefaultGradleConnector) connector).daemonMaxIdleTime(daemonMaxIdleTime, TimeUnit.SECONDS);
|
||||
ProjectConnection connection = connector.connect();
|
||||
|
||||
try {
|
||||
ProjectImportAction projectImportAction = new ProjectImportAction(false);
|
||||
projectImportAction.addProjectImportModelProvider(new ClassSetProjectImportModelProvider(getModels()));
|
||||
BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
|
||||
File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
|
||||
assertNotNull(initScript);
|
||||
String jdkHome = IdeaTestUtil.requireRealJdkHome();
|
||||
buildActionExecutor.setJavaHome(new File(jdkHome));
|
||||
buildActionExecutor.setJvmArguments("-Xmx128m", "-XX:MaxPermSize=64m");
|
||||
buildActionExecutor
|
||||
.withArguments("--info", "--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath());
|
||||
allModels = buildActionExecutor.run();
|
||||
assertNotNull(allModels);
|
||||
}
|
||||
finally {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<Class> getToolingExtensionClasses() {
|
||||
Set<Class> classes = ContainerUtil.<Class>set(
|
||||
ExternalProject.class,
|
||||
// gradle-tooling-extension-api jar
|
||||
ProjectImportAction.class,
|
||||
// gradle-tooling-extension-impl jar
|
||||
ModelBuildScriptClasspathBuilderImpl.class,
|
||||
Multimap.class,
|
||||
ShortTypeHandling.class
|
||||
);
|
||||
|
||||
ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses());
|
||||
return classes;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<Class> doGetToolingExtensionClasses() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (testDir != null) {
|
||||
FileUtil.delete(testDir);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Set<Class> getModels();
|
||||
|
||||
|
||||
private static void ensureTempDirCreated() throws IOException {
|
||||
if (ourTempDir != null) return;
|
||||
|
||||
ourTempDir = new File(FileUtil.getTempDirectory(), "gradleTests");
|
||||
FileUtil.delete(ourTempDir);
|
||||
FileUtil.ensureExists(ourTempDir);
|
||||
}
|
||||
|
||||
public static class DistributionLocator {
|
||||
private static final String RELEASE_REPOSITORY_ENV = "GRADLE_RELEASE_REPOSITORY";
|
||||
private static final String SNAPSHOT_REPOSITORY_ENV = "GRADLE_SNAPSHOT_REPOSITORY";
|
||||
private static final String GRADLE_RELEASE_REPO = "https://services.gradle.org/distributions";
|
||||
private static final String GRADLE_SNAPSHOT_REPO = "https://services.gradle.org/distributions-snapshots";
|
||||
|
||||
@NotNull private final String myReleaseRepoUrl;
|
||||
@NotNull private final String mySnapshotRepoUrl;
|
||||
|
||||
public DistributionLocator() {
|
||||
this(DistributionLocator.getRepoUrl(false), DistributionLocator.getRepoUrl(true));
|
||||
}
|
||||
|
||||
public DistributionLocator(@NotNull String releaseRepoUrl, @NotNull String snapshotRepoUrl) {
|
||||
myReleaseRepoUrl = releaseRepoUrl;
|
||||
mySnapshotRepoUrl = snapshotRepoUrl;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public URI getDistributionFor(@NotNull GradleVersion version) throws URISyntaxException {
|
||||
return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getDistributionRepository(@NotNull GradleVersion version) {
|
||||
return version.isSnapshot() ? mySnapshotRepoUrl : myReleaseRepoUrl;
|
||||
}
|
||||
|
||||
private static URI getDistribution(
|
||||
@NotNull String repositoryUrl,
|
||||
@NotNull GradleVersion version,
|
||||
@NotNull String archiveName,
|
||||
@NotNull String archiveClassifier
|
||||
) throws URISyntaxException {
|
||||
return new URI(String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getRepoUrl(boolean isSnapshotUrl) {
|
||||
String envRepoUrl = System.getenv(isSnapshotUrl ? SNAPSHOT_REPOSITORY_ENV : RELEASE_REPOSITORY_ENV);
|
||||
if (envRepoUrl != null) return envRepoUrl;
|
||||
|
||||
return isSnapshotUrl ? GRADLE_SNAPSHOT_REPO : GRADLE_RELEASE_REPO;
|
||||
}
|
||||
}
|
||||
}
|
||||
+551
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* 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.perf
|
||||
|
||||
import com.intellij.codeInsight.daemon.*
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.ide.highlighter.ModuleFileType
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl
|
||||
import com.intellij.idea.IdeaTestApplication
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.module.ModuleTypeId
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.projectRoots.JavaSdk
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.testFramework.*
|
||||
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
|
||||
import com.intellij.util.ArrayUtilRt
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import com.intellij.util.indexing.UnindexedFilesUpdater
|
||||
import com.intellij.util.io.exists
|
||||
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
|
||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
||||
import org.jetbrains.kotlin.idea.testFramework.*
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFileInEditor
|
||||
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFixture
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
|
||||
|
||||
// myProject is not required for all potential perf test cases
|
||||
protected var myProject: Project? = null
|
||||
private lateinit var jdk18: Sdk
|
||||
private lateinit var myApplication: IdeaTestApplication
|
||||
|
||||
override fun isStressTest(): Boolean = true
|
||||
|
||||
override fun isPerformanceTest(): Boolean = false
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
myApplication = IdeaTestApplication.getInstance()
|
||||
runWriteAction {
|
||||
val jdkTableImpl = JavaAwareProjectJdkTableImpl.getInstanceEx()
|
||||
val homePath = if (jdkTableImpl.internalJdk.homeDirectory!!.name == "jre") {
|
||||
jdkTableImpl.internalJdk.homeDirectory!!.parent.path
|
||||
} else {
|
||||
jdkTableImpl.internalJdk.homePath!!
|
||||
}
|
||||
|
||||
val javaSdk = JavaSdk.getInstance()
|
||||
jdk18 = javaSdk.createJdk("1.8", homePath)
|
||||
val internal = javaSdk.createJdk("IDEA jdk", homePath)
|
||||
|
||||
val jdkTable = ProjectJdkTable.getInstance()
|
||||
jdkTable.addJdk(jdk18, testRootDisposable)
|
||||
jdkTable.addJdk(internal, testRootDisposable)
|
||||
KotlinSdkType.setUpIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun warmUpProject(stats: Stats) {
|
||||
val project = perfOpenHelloWorld(stats, WARM_UP)
|
||||
try {
|
||||
val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", stats, WARM_UP)
|
||||
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
|
||||
} finally {
|
||||
closeProject(project)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
commitAllDocuments()
|
||||
RunAll(
|
||||
ThrowableRunnable { super.tearDown() },
|
||||
ThrowableRunnable {
|
||||
if (myProject != null) {
|
||||
DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled = true // return default value to avoid unnecessary save
|
||||
(StartupManager.getInstance(myProject!!) as StartupManagerImpl).checkCleared()
|
||||
(DaemonCodeAnalyzer.getInstance(myProject!!) as DaemonCodeAnalyzerImpl).cleanupAfterTest()
|
||||
closeProject(myProject!!)
|
||||
myProject = null
|
||||
}
|
||||
}).run()
|
||||
}
|
||||
|
||||
fun simpleFilename(fileName: String): String {
|
||||
val lastIndexOf = fileName.lastIndexOf('/')
|
||||
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
|
||||
}
|
||||
|
||||
protected fun perfOpenKotlinProjectFast(stats: Stats) =
|
||||
perfOpenKotlinProject(stats, fast = true)
|
||||
|
||||
protected fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) {
|
||||
myProject = innerPerfOpenProject("kotlin", stats = stats, path = "../perfTestProject", note = "", fast = fast)
|
||||
}
|
||||
|
||||
protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project =
|
||||
innerPerfOpenProject("helloKotlin", stats, note, path = "idea/testData/perfTest/helloKotlin", simpleModule = true)
|
||||
|
||||
protected fun innerPerfOpenProject(
|
||||
name: String,
|
||||
stats: Stats,
|
||||
note: String,
|
||||
path: String,
|
||||
simpleModule: Boolean = false,
|
||||
fast: Boolean = false
|
||||
): Project {
|
||||
val projectPath = File(path).canonicalPath
|
||||
|
||||
assertTrue("path $path does not exist, check README.md", File(projectPath).exists())
|
||||
|
||||
val warmUpIterations = if (fast) 0 else 1
|
||||
val iterations = if (fast) 1 else 3
|
||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||
|
||||
var lastProject: Project? = null
|
||||
var counter = 0
|
||||
|
||||
stats.perfTest<Unit, Project>(
|
||||
warmUpIterations = warmUpIterations,
|
||||
iterations = iterations,
|
||||
testName = "open project${if (note.isNotEmpty()) " $note" else ""}",
|
||||
test = {
|
||||
val project = if (!simpleModule) {
|
||||
val project = projectManagerEx.loadProject(Paths.get(path), name)
|
||||
assertNotNull("project $name at $path is not loaded", project)
|
||||
val projectRootManager = ProjectRootManager.getInstance(project!!)
|
||||
|
||||
runWriteAction {
|
||||
with(projectRootManager) {
|
||||
projectSdk = jdk18
|
||||
}
|
||||
}
|
||||
assertTrue("project $name at $path is not opened", projectManagerEx.openProject(project))
|
||||
project
|
||||
} else {
|
||||
val project = projectManagerEx.loadAndOpenProject(projectPath)!!
|
||||
initKotlinProject(project, projectPath, name)
|
||||
project
|
||||
}
|
||||
|
||||
(project as ProjectImpl).registerComponentImplementation(
|
||||
FileEditorManager::class.java,
|
||||
FileEditorManagerImpl::class.java
|
||||
)
|
||||
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
with(StartupManager.getInstance(project) as StartupManagerImpl) {
|
||||
ProjectRootManagerEx.getInstanceEx(project).markRootsForRefresh()
|
||||
VirtualFileManager.getInstance().syncRefresh()
|
||||
|
||||
runStartupActivities()
|
||||
runPostStartupActivities()
|
||||
}
|
||||
|
||||
logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" }
|
||||
|
||||
with(ChangeListManager.getInstance(project) as ChangeListManagerImpl) {
|
||||
waitUntilRefreshed()
|
||||
}
|
||||
|
||||
it.value = project
|
||||
},
|
||||
tearDown = {
|
||||
it.value?.let { project ->
|
||||
|
||||
runAndMeasure("refresh gradle project $name") {
|
||||
refreshGradleProjectIfNeeded(projectPath, project)
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
DumbService.getInstance(project).waitForSmartMode()
|
||||
|
||||
for (module in getModulesWithKotlinFiles(project)) {
|
||||
module.getAndCacheLanguageLevelByDependencies()
|
||||
}
|
||||
}.get()
|
||||
|
||||
val modules = ModuleManager.getInstance(project).modules
|
||||
assertTrue("project has to have at least one module", modules.isNotEmpty())
|
||||
|
||||
logMessage { "modules of $name: ${modules.map { m -> m.name }}" }
|
||||
|
||||
lastProject = project
|
||||
VirtualFileManager.getInstance().syncRefresh()
|
||||
|
||||
runWriteAction {
|
||||
project.save()
|
||||
}
|
||||
|
||||
logMessage { "project '$name' successfully opened" }
|
||||
|
||||
// close all project but last - we're going to return and use it further
|
||||
if (counter < warmUpIterations + iterations - 1) {
|
||||
closeProject(project)
|
||||
}
|
||||
counter++
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// indexing
|
||||
lastProject?.let { project ->
|
||||
invalidateLibraryCache(project)
|
||||
|
||||
CodeInsightTestFixtureImpl.ensureIndexesUpToDate(project)
|
||||
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" }
|
||||
|
||||
with(DumbService.getInstance(project)) {
|
||||
queueTask(UnindexedFilesUpdater(project))
|
||||
completeJustSubmittedTasks()
|
||||
}
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
Fixture.enableAnnotatorsAndLoadDefinitions(project)
|
||||
}
|
||||
|
||||
return lastProject ?: error("unable to open project $name at $path")
|
||||
}
|
||||
|
||||
private fun refreshGradleProjectIfNeeded(projectPath: String, project: Project) {
|
||||
if (listOf("build.gradle.kts", "build.gradle").map { name -> Paths.get(projectPath, name).exists() }.find { e -> e } != true) return
|
||||
|
||||
ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(true)
|
||||
|
||||
refreshGradleProject(projectPath, project)
|
||||
|
||||
//ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(false)
|
||||
dispatchAllInvocationEvents()
|
||||
|
||||
// WARNING: [VD] DO NOT SAVE PROJECT AS IT COULD PERSIST WRONG MODULES INFO
|
||||
|
||||
// runInEdtAndWait {
|
||||
// PlatformTestUtil.saveProject(project)
|
||||
// }
|
||||
}
|
||||
|
||||
fun perfTypeAndAutocomplete(
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
lookupElements: List<String>,
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) = perfTypeAndAutocomplete(
|
||||
myProject!!, stats, fileName, marker, insertString, surroundItems,
|
||||
lookupElements = lookupElements, typeAfterMarker = typeAfterMarker,
|
||||
revertChangesAtTheEnd = revertChangesAtTheEnd, note = note
|
||||
)
|
||||
|
||||
fun perfTypeAndAutocomplete(
|
||||
project: Project,
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
lookupElements: List<String>,
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) {
|
||||
assertTrue("lookupElements has to be not empty", lookupElements.isNotEmpty())
|
||||
stats.perfTest<Pair<String, Fixture>, Array<LookupElement>>(
|
||||
warmUpIterations = 8,
|
||||
iterations = 15,
|
||||
testName = "typeAndAutocomplete ${notePrefix(note)}$fileName",
|
||||
setUp = {
|
||||
val fixture = openFixture(project, fileName)
|
||||
val editor = fixture.editor
|
||||
|
||||
val initialText = editor.document.text
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
|
||||
val tasksIdx = editor.document.text.indexOf(marker)
|
||||
assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0)
|
||||
if (typeAfterMarker) {
|
||||
editor.caretModel.moveToOffset(tasksIdx + marker.length + 1)
|
||||
} else {
|
||||
editor.caretModel.moveToOffset(tasksIdx - 1)
|
||||
}
|
||||
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - if (typeAfterMarker) 1 else 2)
|
||||
|
||||
if (!typeAfterMarker) {
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - 2)
|
||||
}
|
||||
|
||||
fixture.type(insertString)
|
||||
|
||||
it.setUpValue = Pair(initialText, fixture)
|
||||
},
|
||||
test = {
|
||||
val fixture = it.setUpValue!!.second
|
||||
it.value = fixture.complete()
|
||||
},
|
||||
tearDown = {
|
||||
val items = it.value?.map { e -> e.lookupString }?.toList() ?: emptyList()
|
||||
try {
|
||||
for (lookupElement in lookupElements) {
|
||||
assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement))
|
||||
}
|
||||
} finally {
|
||||
it.setUpValue?.let { pair ->
|
||||
pair.second.revertChanges(revertChangesAtTheEnd, pair.first)
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun perfTypeAndHighlight(
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) = perfTypeAndHighlight(
|
||||
myProject!!, stats, fileName, marker, insertString, surroundItems,
|
||||
typeAfterMarker = typeAfterMarker,
|
||||
revertChangesAtTheEnd = revertChangesAtTheEnd, note = note
|
||||
)
|
||||
|
||||
fun perfTypeAndHighlight(
|
||||
project: Project,
|
||||
stats: Stats,
|
||||
fileName: String,
|
||||
marker: String,
|
||||
insertString: String,
|
||||
surroundItems: String = "\n",
|
||||
typeAfterMarker: Boolean = true,
|
||||
revertChangesAtTheEnd: Boolean = true,
|
||||
note: String = ""
|
||||
) {
|
||||
stats.perfTest<Pair<String, Fixture>, List<HighlightInfo>>(
|
||||
warmUpIterations = 8,
|
||||
iterations = 15,
|
||||
testName = "typeAndHighlight ${notePrefix(note)}$fileName",
|
||||
setUp = {
|
||||
val fixture = openFixture(project, fileName)
|
||||
val editor = fixture.editor
|
||||
|
||||
val initialText = editor.document.text
|
||||
if (isAKotlinScriptFile(fileName)) {
|
||||
runAndMeasure("update script dependencies for $fileName") {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project)
|
||||
}
|
||||
}
|
||||
|
||||
val tasksIdx = editor.document.text.indexOf(marker)
|
||||
assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0)
|
||||
if (typeAfterMarker) {
|
||||
editor.caretModel.moveToOffset(tasksIdx + marker.length + 1)
|
||||
} else {
|
||||
editor.caretModel.moveToOffset(tasksIdx - 1)
|
||||
}
|
||||
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - if (typeAfterMarker) 1 else 2)
|
||||
|
||||
if (!typeAfterMarker) {
|
||||
for (surroundItem in surroundItems) {
|
||||
EditorTestUtil.performTypingAction(editor, surroundItem)
|
||||
}
|
||||
editor.caretModel.moveToOffset(editor.caretModel.offset - 2)
|
||||
}
|
||||
|
||||
fixture.type(insertString)
|
||||
|
||||
it.setUpValue = Pair(initialText, fixture)
|
||||
},
|
||||
test = {
|
||||
val fixture = it.setUpValue!!.second
|
||||
it.value = fixture.doHighlighting()
|
||||
},
|
||||
tearDown = {
|
||||
it.value?.let { list ->
|
||||
assertNotEmpty(list)
|
||||
}
|
||||
it.setUpValue?.let { pair ->
|
||||
pair.second.revertChanges(revertChangesAtTheEnd, pair.first)
|
||||
}
|
||||
commitAllDocuments()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun initKotlinProject(
|
||||
project: Project,
|
||||
projectPath: String,
|
||||
name: String
|
||||
) {
|
||||
val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}"
|
||||
val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!!
|
||||
val srcFile = projectFile.findChild("src")!!
|
||||
val module = runWriteAction {
|
||||
val projectRootManager = ProjectRootManager.getInstance(project)
|
||||
with(projectRootManager) {
|
||||
projectSdk = jdk18
|
||||
}
|
||||
val moduleManager = ModuleManager.getInstance(project)
|
||||
val module = moduleManager.newModule(modulePath, ModuleTypeId.JAVA_MODULE)
|
||||
PsiTestUtil.addSourceRoot(module, srcFile)
|
||||
module
|
||||
}
|
||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk18)
|
||||
}
|
||||
|
||||
protected fun perfHighlightFile(name: String, stats: Stats): List<HighlightInfo> =
|
||||
perfHighlightFile(myProject!!, name, stats)
|
||||
|
||||
protected fun perfHighlightFile(
|
||||
project: Project,
|
||||
fileName: String,
|
||||
stats: Stats,
|
||||
note: String = ""
|
||||
): List<HighlightInfo> {
|
||||
return highlightFile {
|
||||
val isWarmUp = note == WARM_UP
|
||||
var highlightInfos: List<HighlightInfo> = emptyList()
|
||||
stats.perfTest<EditorFile, List<HighlightInfo>>(
|
||||
warmUpIterations = if (isWarmUp) 1 else 3,
|
||||
iterations = if (isWarmUp) 2 else 10,
|
||||
testName = "highlighting ${notePrefix(note)}${simpleFilename(fileName)}",
|
||||
setUp = {
|
||||
it.setUpValue = openFileInEditor(project, fileName)
|
||||
},
|
||||
test = {
|
||||
val file = it.setUpValue
|
||||
it.value = highlightFile(project, file!!.psiFile)
|
||||
},
|
||||
tearDown = {
|
||||
highlightInfos = it.value ?: emptyList()
|
||||
commitAllDocuments()
|
||||
FileEditorManager.getInstance(project).closeFile(it.setUpValue!!.psiFile.virtualFile)
|
||||
PsiManager.getInstance(project).dropPsiCaches()
|
||||
}
|
||||
)
|
||||
highlightInfos
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> highlightFile(block: () -> T): T {
|
||||
var value: T? = null
|
||||
IdentifierHighlighterPassFactory.doWithHighlightingEnabled {
|
||||
value = block()
|
||||
}
|
||||
return value!!
|
||||
}
|
||||
|
||||
private fun highlightFile(project: Project, psiFile: PsiFile): List<HighlightInfo> {
|
||||
val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile)!!
|
||||
val editor = EditorFactory.getInstance().getEditors(document).first()
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
return CodeInsightTestFixtureImpl.instantiateAndRun(psiFile, editor, ArrayUtilRt.EMPTY_INT_ARRAY, true)
|
||||
}
|
||||
|
||||
protected fun perfScriptDependencies(name: String, stats: Stats, note: String = "") =
|
||||
perfScriptDependencies(myProject!!, name, stats, note = note)
|
||||
|
||||
private fun perfScriptDependencies(
|
||||
project: Project,
|
||||
fileName: String,
|
||||
stats: Stats,
|
||||
note: String = ""
|
||||
) {
|
||||
if (!isAKotlinScriptFile(fileName)) return
|
||||
stats.perfTest<EditorFile, EditorFile>(
|
||||
testName = "updateScriptDependencies ${notePrefix(note)}${simpleFilename(fileName)}",
|
||||
setUp = { it.setUpValue = openFileInEditor(project, fileName) },
|
||||
test = {
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(it.setUpValue!!.psiFile, project)
|
||||
it.value = it.setUpValue
|
||||
},
|
||||
tearDown = {
|
||||
it.setUpValue?.let { ef -> cleanupCaches(project, ef.psiFile.virtualFile) }
|
||||
it.value?.let { v -> assertNotNull(v) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun notePrefix(note: String) = if (note.isNotEmpty()) {
|
||||
if (note.endsWith("/")) note else "$note "
|
||||
} else ""
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.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.psi.PsiDocumentManager
|
||||
import com.intellij.psi.impl.PsiDocumentManagerBase
|
||||
import com.intellij.testFramework.ExtensionTestUtil
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.idea.parameterInfo.HintType
|
||||
|
||||
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 closeProject(project: Project) {
|
||||
dispatchAllInvocationEvents()
|
||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||
projectManagerEx.forceCloseProject(project, true)
|
||||
}
|
||||
|
||||
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) {
|
||||
ExtensionTestUtil.maskExtensions(pointName, filteredExtensions + listOf(point), parentDisposable)
|
||||
}
|
||||
}
|
||||
|
||||
fun logMessage(message: () -> String) {
|
||||
println("-- ${message()}")
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.formatter;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.testFramework.LightIdeaTestCase;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.SettingsConfigurator;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
// Based on from com.intellij.psi.formatter.java.AbstractJavaFormatterTest
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public abstract class AbstractFormatterTest extends LightIdeaTestCase {
|
||||
|
||||
protected enum Action {REFORMAT, INDENT}
|
||||
|
||||
private interface TestFormatAction {
|
||||
void run(PsiFile psiFile, int startOffset, int endOffset);
|
||||
}
|
||||
|
||||
private static final Map<Action, TestFormatAction> ACTIONS = new EnumMap<>(Action.class);
|
||||
static {
|
||||
ACTIONS.put(Action.REFORMAT,
|
||||
(psiFile, startOffset, endOffset) -> CodeStyleManager.getInstance(psiFile.getProject()).reformatText(psiFile, startOffset, endOffset));
|
||||
ACTIONS.put(Action.INDENT,
|
||||
(psiFile, startOffset, endOffset) -> CodeStyleManager.getInstance(psiFile.getProject()).adjustLineIndent(psiFile, startOffset));
|
||||
}
|
||||
|
||||
private static final String BASE_PATH =
|
||||
new File(PluginTestCaseBase.getTestDataPathBase(), "/formatter/").getAbsolutePath();
|
||||
|
||||
public TextRange myTextRange;
|
||||
public TextRange myLineRange;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.HIGHEST);
|
||||
}
|
||||
|
||||
public void doTextTest(@NonNls String text, File fileAfter, String extension) throws IncorrectOperationException {
|
||||
doTextTest(Action.REFORMAT, text, fileAfter, extension);
|
||||
}
|
||||
|
||||
public void doTextTest(final Action action, final String text, File fileAfter, String extension) throws IncorrectOperationException {
|
||||
final PsiFile file = createFile("A" + extension, text);
|
||||
|
||||
if (myLineRange != null) {
|
||||
DocumentImpl document = new DocumentImpl(text);
|
||||
myTextRange =
|
||||
new TextRange(document.getLineStartOffset(myLineRange.getStartOffset()), document.getLineEndOffset(myLineRange.getEndOffset()));
|
||||
}
|
||||
|
||||
final PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject());
|
||||
final Document document = manager.getDocument(file);
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
document.replaceString(0, document.getTextLength(), text);
|
||||
manager.commitDocument(document);
|
||||
try {
|
||||
TextRange rangeToUse = myTextRange;
|
||||
if (rangeToUse == null) {
|
||||
rangeToUse = file.getTextRange();
|
||||
}
|
||||
ACTIONS.get(action).run(file, rangeToUse.getStartOffset(), rangeToUse.getEndOffset());
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
assertTrue(e.getLocalizedMessage(), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "", "");
|
||||
|
||||
|
||||
if (document == null) {
|
||||
fail("Don't expect the document to be null");
|
||||
return;
|
||||
}
|
||||
KotlinTestUtils.assertEqualsToFile(fileAfter, document.getText());
|
||||
manager.commitDocument(document);
|
||||
KotlinTestUtils.assertEqualsToFile(fileAfter, file.getText());
|
||||
}
|
||||
|
||||
public void doTest(@NotNull String expectedFileNameWithExtension) throws Exception {
|
||||
doTest(expectedFileNameWithExtension, false);
|
||||
}
|
||||
|
||||
public void doTestInverted(@NotNull String expectedFileNameWithExtension) throws Exception {
|
||||
doTest(expectedFileNameWithExtension, true);
|
||||
}
|
||||
|
||||
public void doTest(@NotNull String expectedFileNameWithExtension, boolean inverted) throws Exception {
|
||||
String testFileName = expectedFileNameWithExtension.substring(0, expectedFileNameWithExtension.indexOf("."));
|
||||
String testFileExtension = expectedFileNameWithExtension.substring(expectedFileNameWithExtension.lastIndexOf("."));
|
||||
String originalFileText = FileUtil.loadFile(new File(testFileName + testFileExtension), true);
|
||||
|
||||
CodeStyleSettings codeStyleSettings = FormatSettingsUtil.getSettings(getProject());
|
||||
try {
|
||||
Integer rightMargin = InTextDirectivesUtils.getPrefixedInt(originalFileText, "// RIGHT_MARGIN: ");
|
||||
if (rightMargin != null) {
|
||||
codeStyleSettings.setRightMargin(KotlinLanguage.INSTANCE, rightMargin);
|
||||
}
|
||||
|
||||
SettingsConfigurator configurator = FormatSettingsUtil.createConfigurator(originalFileText, codeStyleSettings);
|
||||
if (!inverted) {
|
||||
configurator.configureSettings();
|
||||
}
|
||||
else {
|
||||
configurator.configureInvertedSettings();
|
||||
}
|
||||
|
||||
doTextTest(originalFileText, new File(expectedFileNameWithExtension), testFileExtension);
|
||||
} finally {
|
||||
codeStyleSettings.clearCodeStyleSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.formatter;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.testFramework.EditorTestUtil;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.SettingsConfigurator;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public abstract class AbstractTypingIndentationTestBase extends LightCodeInsightTestCase {
|
||||
public void doNewlineTest(String afterFilePath) throws Exception {
|
||||
doNewlineTest(afterFilePath, false);
|
||||
}
|
||||
|
||||
public void doNewlineTestWithInvert(String afterInvFilePath) throws Exception {
|
||||
doNewlineTest(afterInvFilePath, true);
|
||||
}
|
||||
|
||||
public void doNewlineTest(String afterFilePath, boolean inverted) throws Exception {
|
||||
String testFileName = afterFilePath.substring(0, afterFilePath.indexOf("."));
|
||||
String testFileExtension = afterFilePath.substring(afterFilePath.lastIndexOf("."));
|
||||
|
||||
String originFilePath = testFileName + testFileExtension;
|
||||
String originalFileText = FileUtil.loadFile(new File(originFilePath), true);
|
||||
|
||||
try {
|
||||
SettingsConfigurator configurator = FormatSettingsUtil.createConfigurator(originalFileText, getProject());
|
||||
if (!inverted) {
|
||||
configurator.configureSettings();
|
||||
}
|
||||
else {
|
||||
configurator.configureInvertedSettings();
|
||||
}
|
||||
|
||||
doNewlineTest(originFilePath, afterFilePath);
|
||||
}
|
||||
finally {
|
||||
CodeStyle.getSettings(getProject()).clearCodeStyleSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void doNewlineTest(String beforeFilePath, String afterFilePath) {
|
||||
configureByFile(beforeFilePath);
|
||||
type('\n');
|
||||
|
||||
CaretModel caretModel = getEditor().getCaretModel();
|
||||
int offset = caretModel.getOffset();
|
||||
String actualTextWithCaret = new StringBuilder(getEditor().getDocument().getText()).insert(offset, EditorTestUtil.CARET_TAG).toString();
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(new File(afterFilePath), actualTextWithCaret);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.ide.actions.CopyReferenceAction
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.*
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class QualifiedNamesTest : LightCodeInsightTestCase() {
|
||||
fun testClassRef() {
|
||||
configureFromFileText(
|
||||
"class.kt",
|
||||
"""
|
||||
package foo.bar
|
||||
|
||||
class Klass {
|
||||
class Nested
|
||||
|
||||
companion object {
|
||||
}
|
||||
}
|
||||
|
||||
object Object {
|
||||
}
|
||||
|
||||
val anonymous = object {
|
||||
}
|
||||
"""
|
||||
)
|
||||
assertEquals(listOf("foo.bar.Klass", "foo.bar.Klass.Nested", "foo.bar.Klass.Companion", "foo.bar.Object", "foo.bar.ClassKt#getAnonymous", null),
|
||||
getQualifiedNamesForDeclarations())
|
||||
}
|
||||
|
||||
fun testFunRef() {
|
||||
configureFromFileText(
|
||||
"fun.kt",
|
||||
"""
|
||||
package foo.bar
|
||||
|
||||
class Klass {
|
||||
fun memberFun() {
|
||||
}
|
||||
|
||||
val memberVal = ":)"
|
||||
}
|
||||
|
||||
fun topLevelFun()
|
||||
|
||||
val topLevelVal = ":)"
|
||||
"""
|
||||
)
|
||||
assertEquals(listOf("foo.bar.Klass", "foo.bar.Klass#memberFun", "foo.bar.Klass#getMemberVal", "foo.bar.FunKt#topLevelFun", "foo.bar.FunKt#getTopLevelVal"),
|
||||
getQualifiedNamesForDeclarations())
|
||||
}
|
||||
|
||||
private fun getQualifiedNamesForDeclarations(): List<String?> {
|
||||
val result = ArrayList<String?>()
|
||||
file.accept(object : KtVisitorVoid() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
|
||||
override fun visitNamedDeclaration(declaration: KtNamedDeclaration) {
|
||||
result.add(CopyReferenceAction.elementToFqn(declaration))
|
||||
super.visitNamedDeclaration(declaration)
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.codeInsight.moveUpDown
|
||||
|
||||
import com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementLeftAction
|
||||
import com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementRightAction
|
||||
import com.intellij.codeInsight.editorActions.moveUpDown.MoveStatementDownAction
|
||||
import com.intellij.codeInsight.editorActions.moveUpDown.MoveStatementUpAction
|
||||
import com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.editor.actionSystem.EditorAction
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase
|
||||
import junit.framework.ComparisonFailure
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.formatter.FormatSettingsUtil
|
||||
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinDeclarationMover
|
||||
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinExpressionMover
|
||||
import org.jetbrains.kotlin.idea.core.script.isScriptDependenciesUpdaterDisabled
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
|
||||
protected fun doTestClassBodyDeclaration(path: String) {
|
||||
doTest(path, KotlinDeclarationMover::class.java)
|
||||
}
|
||||
|
||||
protected fun doTestExpression(path: String) {
|
||||
doTest(path, KotlinExpressionMover::class.java)
|
||||
}
|
||||
|
||||
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>) {
|
||||
doTest(path) { isApplicableExpected, direction ->
|
||||
val movers = Extensions.getExtensions(StatementUpDownMover.STATEMENT_UP_DOWN_MOVER_EP)
|
||||
val info = StatementUpDownMover.MoveInfo()
|
||||
val actualMover = movers.firstOrNull {
|
||||
it.checkAvailable(editor, file, info, direction == "down")
|
||||
} ?: error("No mover found")
|
||||
|
||||
assertEquals("Unmatched movers", defaultMoverClass.name, actualMover::class.java.name)
|
||||
assertEquals("Invalid applicability", isApplicableExpected, info.toMove2 != null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractMoveLeftRightTest : AbstractCodeMoverTest() {
|
||||
protected fun doTest(path: String) {
|
||||
doTest(path) { _, _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractCodeMoverTest : LightCodeInsightTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
ApplicationManager.getApplication().isScriptDependenciesUpdaterDisabled = true
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
ApplicationManager.getApplication().isScriptDependenciesUpdaterDisabled = false
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
protected fun doTest(path: String, isApplicableChecker: (isApplicableExpected: Boolean, direction: String) -> Unit) {
|
||||
configureByFile(path)
|
||||
|
||||
val fileText = FileUtil.loadFile(File(path), true)
|
||||
val direction = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVE: ")
|
||||
?: error("No MOVE directive found")
|
||||
|
||||
val action = when (direction) {
|
||||
"up" -> MoveStatementUpAction()
|
||||
"down" -> MoveStatementDownAction()
|
||||
"left" -> MoveElementLeftAction()
|
||||
"right" -> MoveElementRightAction()
|
||||
else -> error("Unknown direction: $direction")
|
||||
}
|
||||
|
||||
val isApplicableString = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// IS_APPLICABLE: ")
|
||||
val isApplicableExpected = isApplicableString == null || isApplicableString == "true"
|
||||
|
||||
isApplicableChecker(isApplicableExpected, direction)
|
||||
|
||||
invokeAndCheck(fileText, path, action, isApplicableExpected)
|
||||
}
|
||||
|
||||
private fun invokeAndCheck(fileText: String, path: String, action: EditorAction, isApplicableExpected: Boolean) {
|
||||
val project = editor.project!!
|
||||
|
||||
val codeStyleSettings = FormatSettingsUtil.getSettings(project)
|
||||
val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
|
||||
configurator.configureSettings()
|
||||
|
||||
try {
|
||||
val dataContext = currentEditorDataContext
|
||||
|
||||
val before = editor.document.text
|
||||
runWriteAction { action.actionPerformed(editor, dataContext) }
|
||||
|
||||
val after = editor.document.text
|
||||
val actionDoesNothing = after == before
|
||||
|
||||
TestCase.assertEquals(isApplicableExpected, !actionDoesNothing)
|
||||
|
||||
if (isApplicableExpected) {
|
||||
val afterFilePath = path + ".after"
|
||||
try {
|
||||
checkResultByFile(afterFilePath)
|
||||
}
|
||||
catch (e: ComparisonFailure) {
|
||||
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
codeStyleSettings.clearCodeStyleSettings()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTestDataPath() = ""
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.debugger.sequence
|
||||
|
||||
import com.intellij.debugger.streams.test.StreamChainBuilderTestCase
|
||||
import com.intellij.debugger.streams.wrapper.StreamChain
|
||||
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.idea.caches.project.LibraryModificationTracker
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class KotlinPsiChainBuilderTestCase(private val relativePath: String) : StreamChainBuilderTestCase() {
|
||||
override fun getTestDataPath(): String =
|
||||
Paths.get(File("").absolutePath, "idea/testData/debugger/sequence/psi/$relativeTestPath/").toString()
|
||||
|
||||
override fun getFileExtension(): String = ".kt"
|
||||
abstract val kotlinChainBuilder: StreamChainBuilder
|
||||
override fun getChainBuilder(): StreamChainBuilder = kotlinChainBuilder
|
||||
private val stdLibName = "kotlin-stdlib"
|
||||
|
||||
protected abstract fun doTest()
|
||||
|
||||
final override fun getRelativeTestPath(): String = relativePath
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
ApplicationManager.getApplication().runWriteAction {
|
||||
if (ProjectLibraryTable.getInstance(project).getLibraryByName(stdLibName) == null) {
|
||||
val stdLibPath = ForTestCompileRuntime.runtimeJarForTests()
|
||||
PsiTestUtil.addLibrary(
|
||||
testRootDisposable,
|
||||
module,
|
||||
stdLibName,
|
||||
stdLibPath.parent,
|
||||
stdLibPath.name
|
||||
)
|
||||
}
|
||||
}
|
||||
LibraryModificationTracker.getInstance(project).incModificationCount()
|
||||
}
|
||||
|
||||
|
||||
override fun getProjectJDK(): Sdk {
|
||||
return PluginTestCaseBase.mockJdk9()
|
||||
}
|
||||
|
||||
abstract class Positive(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
|
||||
override fun doTest() {
|
||||
val chains = buildChains()
|
||||
checkChains(chains)
|
||||
}
|
||||
|
||||
private fun checkChains(chains: MutableList<StreamChain>) {
|
||||
TestCase.assertFalse(chains.isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Negative(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
|
||||
override fun doTest() {
|
||||
val elementAtCaret = configureAndGetElementAtCaret()
|
||||
TestCase.assertFalse(chainBuilder.isChainExists(elementAtCaret))
|
||||
TestCase.assertTrue(chainBuilder.build(elementAtCaret).isEmpty())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.editor;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.testFramework.EditorTestUtil;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import org.jetbrains.kotlin.formatter.FormatSettingsUtil;
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.SettingsConfigurator;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner.class)
|
||||
public class KotlinCommenterTest extends LightCodeInsightTestCase {
|
||||
private static final String BASE_PATH =
|
||||
new File(PluginTestCaseBase.getTestDataPathBase(), "/editor/commenter/").getAbsolutePath();
|
||||
|
||||
public void testGenerateDocComment() throws Exception {
|
||||
doNewLineTypingTest();
|
||||
}
|
||||
|
||||
public void testNewLineInComment() throws Exception {
|
||||
doNewLineTypingTest();
|
||||
}
|
||||
|
||||
public void testNewLineInTag() throws Exception {
|
||||
doNewLineTypingTest();
|
||||
}
|
||||
|
||||
public void testNotFirstColumnWithSpace() throws Exception {
|
||||
doLineCommentTest();
|
||||
}
|
||||
|
||||
public void testNotFirstColumnWithoutSpace() throws Exception {
|
||||
doLineCommentTest();
|
||||
}
|
||||
|
||||
private void doNewLineTypingTest() throws Exception {
|
||||
configure();
|
||||
EditorTestUtil.performTypingAction(getEditor(), '\n');
|
||||
check();
|
||||
}
|
||||
|
||||
private void doLineCommentTest() throws Exception {
|
||||
configure();
|
||||
|
||||
CodeStyleSettings codeStyleSettings = FormatSettingsUtil.getSettings(getProject());
|
||||
try {
|
||||
String text = getFile().getText();
|
||||
|
||||
SettingsConfigurator configurator = FormatSettingsUtil.createConfigurator(text, codeStyleSettings);
|
||||
configurator.configureSettings();
|
||||
|
||||
executeAction("CommentByLineComment");
|
||||
} finally {
|
||||
codeStyleSettings.clearCodeStyleSettings();
|
||||
}
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
private void configure() throws Exception {
|
||||
configureFromFileText("a.kt", loadFile(getTestName(true) + ".kt"));
|
||||
}
|
||||
|
||||
private void check() {
|
||||
File afterFile = getTestFile(getTestName(true) + "_after.kt");
|
||||
KotlinTestUtils.assertEqualsToFile(afterFile, getEditor(), false);
|
||||
}
|
||||
|
||||
private static File getTestFile(String name) {
|
||||
return new File(BASE_PATH, name);
|
||||
}
|
||||
|
||||
private static String loadFile(String name) throws Exception {
|
||||
File file = getTestFile(name);
|
||||
return FileUtil.loadFile(file, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,935 @@
|
||||
/*
|
||||
* 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.editor
|
||||
|
||||
import com.intellij.application.options.CodeStyle
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.testFramework.EditorTestUtil
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.formatter.KotlinStyleGuideCodeStyle
|
||||
import org.jetbrains.kotlin.idea.formatter.ktCodeStyleSettings
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class TypedHandlerTest : LightCodeInsightTestCase() {
|
||||
private val dollar = '$'
|
||||
|
||||
fun testTypeStringTemplateStart() = doTypeTest(
|
||||
'{',
|
||||
"""val x = "$<caret>" """,
|
||||
"""val x = "$dollar{}" """
|
||||
)
|
||||
|
||||
fun testAutoIndentRightOpenBrace() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun test() {\n" +
|
||||
"<caret>\n" +
|
||||
"}",
|
||||
|
||||
"fun test() {\n" +
|
||||
" {<caret>}\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testAutoIndentLeftOpenBrace() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun test() {\n" +
|
||||
" <caret>\n" +
|
||||
"}",
|
||||
|
||||
"fun test() {\n" +
|
||||
" {<caret>}\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateStartWithCloseBraceAfter() = doTypeTest(
|
||||
'{',
|
||||
"""fun foo() { "$<caret>" }""",
|
||||
"""fun foo() { "$dollar{}" }"""
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateStartBeforeStringWithExistingDollar() = doTypeTest(
|
||||
'{',
|
||||
"""fun foo() { "$<caret>something" }""",
|
||||
"""fun foo() { "$dollar{something" }"""
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateStartBeforeStringWithNoDollar() = doTypeTest(
|
||||
"$dollar{",
|
||||
"""fun foo() { "<caret>something" }""",
|
||||
"""fun foo() { "$dollar{<caret>}something" }"""
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateWithUnmatchedBrace() = doTypeTest(
|
||||
"$dollar{",
|
||||
"""val a = "<caret>bar}foo"""",
|
||||
"""val a = "$dollar{<caret>bar}foo""""
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateWithUnmatchedBraceComplex() = doTypeTest(
|
||||
"$dollar{",
|
||||
"""val a = "<caret>bar + more}foo"""",
|
||||
"""val a = "$dollar{<caret>}bar + more}foo""""
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateStartInStringWithBraceLiterals() = doTypeTest(
|
||||
"$dollar{",
|
||||
"""val test = "{ code <caret>other }"""",
|
||||
"""val test = "{ code $dollar{<caret>}other }""""
|
||||
)
|
||||
|
||||
fun testTypeStringTemplateStartInEmptyString() = doTypeTest(
|
||||
'{',
|
||||
"""fun foo() { "$<caret>" }""",
|
||||
"""fun foo() { "$dollar{<caret>}" }"""
|
||||
)
|
||||
|
||||
fun testKT3575() = doTypeTest(
|
||||
'{',
|
||||
"""val x = "$<caret>]" """,
|
||||
"""val x = "$dollar{}]" """
|
||||
)
|
||||
|
||||
fun testAutoCloseRawStringInEnd() = doTypeTest(
|
||||
'"',
|
||||
"""val x = ""<caret>""",
|
||||
"""val x = ""${'"'}<caret>""${'"'}"""
|
||||
)
|
||||
|
||||
fun testNoAutoCloseRawStringInEnd() = doTypeTest(
|
||||
'"',
|
||||
"""val x = ""${'"'}<caret>""",
|
||||
"""val x = ""${'"'}""""
|
||||
)
|
||||
|
||||
fun testAutoCloseRawStringInMiddle() = doTypeTest(
|
||||
'"',
|
||||
"""
|
||||
val x = ""<caret>
|
||||
val y = 12
|
||||
""".trimIndent(),
|
||||
"""
|
||||
val x = ""${'"'}<caret>""${'"'}
|
||||
val y = 12
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
fun testNoAutoCloseBetweenMultiQuotes() = doTypeTest(
|
||||
'"',
|
||||
"""val x = ""${'"'}<caret>${'"'}""/**/""",
|
||||
"""val x = ""${'"'}${'"'}<caret>""/**/"""
|
||||
)
|
||||
|
||||
fun testNoAutoCloseBetweenMultiQuotes1() = doTypeTest(
|
||||
'"',
|
||||
"""val x = ""${'"'}"<caret>"${'"'}/**/""",
|
||||
"""val x = ""${'"'}""<caret>${'"'}/**/"""
|
||||
)
|
||||
|
||||
fun testNoAutoCloseAfterEscape() = doTypeTest(
|
||||
'"',
|
||||
"""val x = "\""<caret>""",
|
||||
"""val x = "\""${'"'}<caret>""""
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceInFunctionDeclaration() = doTypeTest(
|
||||
'{',
|
||||
"fun foo() <caret>",
|
||||
"fun foo() {<caret>}"
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceInLocalFunctionDeclaration() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" fun bar() <caret>\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" fun bar() {<caret>}\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceInAssignment() = doTypeTest(
|
||||
'{',
|
||||
"fun foo() {\n" +
|
||||
" val a = <caret>\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" val a = {<caret>}\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedIfSurroundOnSameLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if() <caret>foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if() {foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedElseSurroundOnSameLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {} else <caret>foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {} else {foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedTryOnSameLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try <caret>foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try {foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedCatchOnSameLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try {} catch (e: Exception) <caret>foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try {} catch (e: Exception) {foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedFinallyOnSameLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try {} catch (e: Exception) finally <caret>foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try {} catch (e: Exception) finally {foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedWhileSurroundOnSameLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" while() <caret>foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" while() {foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedWhileSurroundOnNewLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" while()\n" +
|
||||
"<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" while()\n" +
|
||||
" {\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedIfSurroundOnOtherLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) <caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedElseSurroundOnOtherLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {} else <caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {} else {<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedTryOnOtherLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try <caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try {<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedIfSurroundOnNewLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true)\n" +
|
||||
" <caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true)\n" +
|
||||
" {<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedElseSurroundOnNewLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {} else\n" +
|
||||
" <caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if(true) {} else\n" +
|
||||
" {<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testDoNotAutoCloseBraceInUnfinishedTryOnNewLine() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try\n" +
|
||||
" <caret>\n" +
|
||||
" foo()\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" try\n" +
|
||||
" {<caret>\n" +
|
||||
" foo()\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceInsideFor() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" for (elem in some.filter <caret>) {\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" for (elem in some.filter {<caret>}) {\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceInsideForAfterCloseParen() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" for (elem in some.foo(true) <caret>) {\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" for (elem in some.foo(true) {<caret>}) {\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceBeforeIf() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" <caret>if (true) {}\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" {<caret>if (true) {}\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testAutoCloseBraceInIfCondition() = doTypeTest(
|
||||
'{',
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if (some.hello (12) <caret>)\n" +
|
||||
"}",
|
||||
|
||||
"fun foo() {\n" +
|
||||
" if (some.hello (12) {<caret>})\n" +
|
||||
"}"
|
||||
)
|
||||
|
||||
fun testInsertSpaceAfterRightBraceOfNestedLambda() = doTypeTest(
|
||||
'{',
|
||||
"val t = Array(100) { Array(200) <caret>}",
|
||||
"val t = Array(100) { Array(200) {<caret>} }"
|
||||
)
|
||||
|
||||
fun testAutoInsertParenInStringLiteral() = doTypeTest(
|
||||
'(',
|
||||
"""fun f() { println("$dollar{f<caret>}") }""",
|
||||
"""fun f() { println("$dollar{f(<caret>)}") }"""
|
||||
)
|
||||
|
||||
fun testAutoInsertParenInCode() = doTypeTest(
|
||||
'(',
|
||||
"""fun f() { val a = f<caret> }""",
|
||||
"""fun f() { val a = f(<caret>) }"""
|
||||
)
|
||||
|
||||
fun testSplitStringByEnter() = doTypeTest(
|
||||
'\n',
|
||||
"""val s = "foo<caret>bar"""",
|
||||
"val s = \"foo\" +\n" +
|
||||
" \"bar\""
|
||||
)
|
||||
|
||||
fun testSplitStringByEnterEmpty() = doTypeTest(
|
||||
'\n',
|
||||
"""val s = "<caret>"""",
|
||||
"val s = \"\" +\n" +
|
||||
" \"\""
|
||||
)
|
||||
|
||||
fun testSplitStringByEnterBeforeEscapeSequence() = doTypeTest(
|
||||
'\n',
|
||||
"""val s = "foo<caret>\nbar"""",
|
||||
"val s = \"foo\" +\n" +
|
||||
" \"\\nbar\""
|
||||
)
|
||||
|
||||
fun testSplitStringByEnterBeforeSubstitution() = doTypeTest(
|
||||
'\n',
|
||||
"""val s = "foo<caret>${dollar}bar"""",
|
||||
"val s = \"foo\" +\n" +
|
||||
" \"${dollar}bar\""
|
||||
)
|
||||
|
||||
fun testSplitStringByEnterAddParentheses() = doTypeTest(
|
||||
'\n',
|
||||
"""val l = "foo<caret>bar".length()""",
|
||||
"val l = (\"foo\" +\n" +
|
||||
" \"bar\").length()"
|
||||
)
|
||||
|
||||
fun testSplitStringByEnterExistingParentheses() = doTypeTest(
|
||||
'\n',
|
||||
"""val l = ("asdf" + "foo<caret>bar").length()""",
|
||||
"val l = (\"asdf\" + \"foo\" +\n" +
|
||||
" \"bar\").length()"
|
||||
)
|
||||
|
||||
fun testTypeLtInFunDeclaration() {
|
||||
doLtGtTest("fun <caret>")
|
||||
}
|
||||
|
||||
fun testTypeLtInOngoingConstructorCall() {
|
||||
doLtGtTest("fun test() { Collection<caret> }")
|
||||
}
|
||||
|
||||
fun testTypeLtInClassDeclaration() {
|
||||
doLtGtTest("class Some<caret> {}")
|
||||
}
|
||||
|
||||
fun testTypeLtInPropertyType() {
|
||||
doLtGtTest("val a: List<caret> ")
|
||||
}
|
||||
|
||||
fun testTypeLtInExtensionFunctionReceiver() {
|
||||
doLtGtTest("fun <T> Collection<caret> ")
|
||||
}
|
||||
|
||||
fun testTypeLtInFunParam() {
|
||||
doLtGtTest("fun some(a : HashSet<caret>)")
|
||||
}
|
||||
|
||||
fun testTypeLtInFun() {
|
||||
doLtGtTestNoAutoClose("fun some() { <<caret> }")
|
||||
}
|
||||
|
||||
fun testTypeLtInLess() {
|
||||
doLtGtTestNoAutoClose("fun some() { val a = 12; a <<caret> }")
|
||||
}
|
||||
|
||||
fun testColonOfSuperTypeList() {
|
||||
doTypeTest(
|
||||
':',
|
||||
"""
|
||||
|open class A
|
||||
|class B
|
||||
|<caret>
|
||||
""",
|
||||
"""
|
||||
|open class A
|
||||
|class B
|
||||
| :<caret>
|
||||
""")
|
||||
}
|
||||
|
||||
fun testColonOfSuperTypeListInObject() {
|
||||
doTypeTest(
|
||||
':',
|
||||
"""
|
||||
|interface A
|
||||
|object B
|
||||
|<caret>
|
||||
""",
|
||||
"""
|
||||
|interface A
|
||||
|object B
|
||||
| :<caret>
|
||||
""")
|
||||
}
|
||||
|
||||
fun testColonOfSuperTypeListInCompanionObject() {
|
||||
doTypeTest(
|
||||
':',
|
||||
"""
|
||||
|interface A
|
||||
|class B {
|
||||
| companion object
|
||||
| <caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|interface A
|
||||
|class B {
|
||||
| companion object
|
||||
| :<caret>
|
||||
|}
|
||||
""")
|
||||
}
|
||||
|
||||
fun testColonOfSuperTypeListBeforeBody() {
|
||||
doTypeTest(
|
||||
':',
|
||||
"""
|
||||
|open class A
|
||||
|class B
|
||||
|<caret> {
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|open class A
|
||||
|class B
|
||||
| :<caret> {
|
||||
|}
|
||||
""")
|
||||
}
|
||||
|
||||
fun testColonOfSuperTypeListNotNullIndent() {
|
||||
doTypeTest(
|
||||
':',
|
||||
"""
|
||||
|fun test() {
|
||||
| open class A
|
||||
| class B
|
||||
| <caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| open class A
|
||||
| class B
|
||||
| :<caret>
|
||||
|}
|
||||
""")
|
||||
}
|
||||
|
||||
fun testChainCallContinueWithDot() {
|
||||
doTypeTest(
|
||||
'.',
|
||||
"""
|
||||
|class Test{ fun test() = this }
|
||||
|fun some() {
|
||||
| Test()
|
||||
| <caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|class Test{ fun test() = this }
|
||||
|fun some() {
|
||||
| Test()
|
||||
| .<caret>
|
||||
|}
|
||||
""")
|
||||
}
|
||||
|
||||
fun testChainCallContinueWithSafeCall() {
|
||||
doTypeTest(
|
||||
'.',
|
||||
"""
|
||||
|class Test{ fun test() = this }
|
||||
|fun some() {
|
||||
| Test()
|
||||
| ?<caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|class Test{ fun test() = this }
|
||||
|fun some() {
|
||||
| Test()
|
||||
| ?.<caret>
|
||||
|}
|
||||
""")
|
||||
}
|
||||
|
||||
fun testContinueWithElvis() {
|
||||
doTypeTest(
|
||||
':',
|
||||
"""
|
||||
|fun test(): Any? = null
|
||||
|fun some() {
|
||||
| test()
|
||||
| ?<caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test(): Any? = null
|
||||
|fun some() {
|
||||
| test()
|
||||
| ?:<caret>
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testContinueWithOr() {
|
||||
doTypeTest(
|
||||
'|',
|
||||
"""
|
||||
|fun some() {
|
||||
| if (true
|
||||
| |<caret>)
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun some() {
|
||||
| if (true
|
||||
| ||<caret>)
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testContinueWithAnd() {
|
||||
doTypeTest(
|
||||
'&',
|
||||
"""
|
||||
|fun some() {
|
||||
| val test = true
|
||||
| &<caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun some() {
|
||||
| val test = true
|
||||
| &&<caret>
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testSpaceAroundRange() {
|
||||
doTypeTest(
|
||||
'.',
|
||||
"""
|
||||
| val test = 1 <caret>
|
||||
""",
|
||||
"""
|
||||
| val test = 1 .<caret>
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testIndentBeforeElseWithBlock() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test(b: Boolean) {
|
||||
| if (b) {
|
||||
| }<caret>
|
||||
| else if (!b) {
|
||||
| }
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test(b: Boolean) {
|
||||
| if (b) {
|
||||
| }
|
||||
| <caret>
|
||||
| else if (!b) {
|
||||
| }
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testIndentBeforeElseWithoutBlock() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test(b: Boolean) {
|
||||
| if (b)
|
||||
| foo()<caret>
|
||||
| else {
|
||||
| }
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test(b: Boolean) {
|
||||
| if (b)
|
||||
| foo()
|
||||
| <caret>
|
||||
| else {
|
||||
| }
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testIndentOnFinishedVariableEndAfterEquals() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test() {
|
||||
| val a =<caret>
|
||||
| foo()
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| val a =
|
||||
| <caret>
|
||||
| foo()
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testIndentNotFinishedVariableEndAfterEquals() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test() {
|
||||
| val a =<caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| val a =
|
||||
| <caret>
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testSmartEnterWithTabsOnConstructorParameters() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|class A(
|
||||
| a: Int,<caret>
|
||||
|)
|
||||
""",
|
||||
"""
|
||||
|class A(
|
||||
| a: Int,
|
||||
| <caret>
|
||||
|)
|
||||
""",
|
||||
enableSmartEnterWithTabs()
|
||||
)
|
||||
}
|
||||
|
||||
fun testSmartEnterWithTabsInMethodParameters() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun method(
|
||||
| arg1: String,<caret>
|
||||
|) {}
|
||||
""",
|
||||
"""
|
||||
|fun method(
|
||||
| arg1: String,
|
||||
| <caret>
|
||||
|) {}
|
||||
""",
|
||||
enableSmartEnterWithTabs()
|
||||
)
|
||||
}
|
||||
|
||||
fun testAutoIndentInWhenClause() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test() {
|
||||
| when (2) {
|
||||
| is Int -><caret>
|
||||
| }
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| when (2) {
|
||||
| is Int ->
|
||||
| <caret>
|
||||
| }
|
||||
|}
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
fun testEnterInFunctionWithExpressionBody() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test() =<caret>
|
||||
""",
|
||||
"""
|
||||
|fun test() =
|
||||
| <caret>
|
||||
""",
|
||||
ENABLE_KOTLIN_OFFICIAL_CODE_STYLE
|
||||
)
|
||||
}
|
||||
|
||||
fun testEnterInMultiDeclaration() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|fun test() {
|
||||
| val (a, b) =<caret>
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| val (a, b) =
|
||||
| <caret>
|
||||
|}
|
||||
""",
|
||||
ENABLE_KOTLIN_OFFICIAL_CODE_STYLE
|
||||
)
|
||||
}
|
||||
|
||||
fun testEnterInVariableDeclaration() {
|
||||
doTypeTest(
|
||||
'\n',
|
||||
"""
|
||||
|val test =<caret>
|
||||
""",
|
||||
"""
|
||||
|val test =
|
||||
| <caret>
|
||||
""",
|
||||
ENABLE_KOTLIN_OFFICIAL_CODE_STYLE
|
||||
)
|
||||
}
|
||||
|
||||
fun testMoveThroughGT() {
|
||||
configureFromFileText("a.kt", "val a: List<Set<Int<caret>>>")
|
||||
EditorTestUtil.performTypingAction(editor, '>')
|
||||
EditorTestUtil.performTypingAction(editor, '>')
|
||||
checkResultByText("val a: List<Set<Int>><caret>")
|
||||
}
|
||||
|
||||
fun testCharClosingQuote() {
|
||||
doTypeTest('\'', "val c = <caret>", "val c = ''")
|
||||
}
|
||||
|
||||
private fun enableSmartEnterWithTabs(): (Project) -> Unit = {
|
||||
val indentOptions = CodeStyle.getSettings(it).getIndentOptions(KotlinFileType.INSTANCE)
|
||||
indentOptions.USE_TAB_CHARACTER = true
|
||||
indentOptions.SMART_TABS = true
|
||||
}
|
||||
|
||||
private fun doTypeTest(ch: Char, beforeText: String, afterText: String, settingsModifier: ((Project) -> Unit)? = null) {
|
||||
doTypeTest(ch.toString(), beforeText, afterText, settingsModifier)
|
||||
}
|
||||
|
||||
private fun doTypeTest(text: String, beforeText: String, afterText: String, settingsModifier: ((Project) -> Unit)? = null) {
|
||||
try {
|
||||
if (settingsModifier != null) {
|
||||
settingsModifier(project)
|
||||
}
|
||||
|
||||
configureFromFileText("a.kt", beforeText.trimMargin())
|
||||
for (ch in text) {
|
||||
EditorTestUtil.performTypingAction(editor, ch)
|
||||
}
|
||||
checkResultByText(afterText.trimMargin())
|
||||
} finally {
|
||||
if (settingsModifier != null) {
|
||||
CodeStyle.getSettings(project).clearCodeStyleSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun doLtGtTestNoAutoClose(initText: String) {
|
||||
doLtGtTest(initText, false)
|
||||
}
|
||||
|
||||
private fun doLtGtTest(initText: String, shouldCloseBeInsert: Boolean) {
|
||||
configureFromFileText("a.kt", initText)
|
||||
|
||||
EditorTestUtil.performTypingAction(editor, '<')
|
||||
checkResultByText(if (shouldCloseBeInsert) initText.replace("<caret>", "<<caret>>") else initText.replace("<caret>", "<<caret>"))
|
||||
|
||||
EditorTestUtil.performTypingAction(editor, EditorTestUtil.BACKSPACE_FAKE_CHAR)
|
||||
checkResultByText(initText)
|
||||
}
|
||||
|
||||
private fun doLtGtTest(initText: String) {
|
||||
doLtGtTest(initText, true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val ENABLE_KOTLIN_OFFICIAL_CODE_STYLE: (Project) -> Unit = {
|
||||
val settings = ktCodeStyleSettings(it)?.all ?: error("No Settings")
|
||||
KotlinStyleGuideCodeStyle.apply(settings)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.kdoc;
|
||||
|
||||
import com.intellij.codeInsight.TargetElementUtil;
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner.class)
|
||||
public class KdocRenameTest extends LightCodeInsightTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PluginTestCaseBase.getTestDataPathBase() + "/kdoc/rename/";
|
||||
}
|
||||
|
||||
public void testParamReference() throws Exception {
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testTypeParamReference() throws Exception {
|
||||
doTest("R");
|
||||
}
|
||||
|
||||
public void testCodeReference() throws Exception {
|
||||
doTest("xyzzy");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities();
|
||||
}
|
||||
|
||||
private void doTest(String newName) throws Exception {
|
||||
configureByFile(getTestName(false) + ".kt");
|
||||
PsiElement element = TargetElementUtil
|
||||
.findTargetElement(getEditor(),
|
||||
TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED);
|
||||
assertNotNull(element);
|
||||
new RenameProcessor(getProject(), element, newName, true, true).run();
|
||||
checkResultByFile(getTestName(false) + ".kt.after");
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.navigation
|
||||
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractKotlinGotoImplementationTest : LightCodeInsightTestCase() {
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
invalidateLibraryCache(project)
|
||||
}
|
||||
|
||||
override fun getTestDataPath(): String = KotlinTestUtils.getHomeDirectory() + File.separator
|
||||
|
||||
override fun getProjectJDK(): Sdk = PluginTestCaseBase.mockJdk()
|
||||
|
||||
protected fun doTest(path: String) {
|
||||
configureByFile(path)
|
||||
val gotoData = NavigationTestUtils.invokeGotoImplementations(editor, file)
|
||||
NavigationTestUtils.assertGotoDataMatching(editor, gotoData)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.codeInsight.TargetElementUtil
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestUtil
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.idea.refactoring.rename.KotlinMemberInplaceRenameHandler
|
||||
import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler
|
||||
import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter
|
||||
import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
|
||||
override fun isRunInWriteAction(): Boolean = false
|
||||
override fun getTestDataPath(): String = PluginTestCaseBase.getTestDataPathBase() + "/refactoring/rename/inplace/"
|
||||
|
||||
fun testLocalVal() {
|
||||
doTestMemberInplaceRename("y")
|
||||
}
|
||||
|
||||
fun testForLoop() {
|
||||
doTestInplaceRename("j")
|
||||
}
|
||||
|
||||
fun testTryCatch() {
|
||||
doTestInplaceRename("e1")
|
||||
}
|
||||
|
||||
fun testFunctionLiteral() {
|
||||
doTestInplaceRename("y")
|
||||
}
|
||||
|
||||
fun testFunctionLiteralIt() {
|
||||
doTestImplicitLambdaParameter("y")
|
||||
}
|
||||
|
||||
fun testFunctionLiteralItEndCaret() {
|
||||
doTestImplicitLambdaParameter("y")
|
||||
}
|
||||
|
||||
fun testFunctionLiteralParenthesis() {
|
||||
doTestInplaceRename("y")
|
||||
}
|
||||
|
||||
fun testLocalFunction() {
|
||||
doTestMemberInplaceRename("bar")
|
||||
}
|
||||
|
||||
fun testFunctionParameterNotInplace() {
|
||||
doTestInplaceRename(null)
|
||||
}
|
||||
|
||||
fun testGlobalFunctionNotInplace() {
|
||||
doTestInplaceRename(null)
|
||||
}
|
||||
|
||||
fun testTopLevelValNotInplace() {
|
||||
doTestInplaceRename(null)
|
||||
}
|
||||
|
||||
fun testLabelFromFunction() {
|
||||
doTestMemberInplaceRename("foo")
|
||||
}
|
||||
|
||||
fun testMultiDeclaration() {
|
||||
doTestInplaceRename("foo")
|
||||
}
|
||||
|
||||
fun testLocalVarShadowingMemberProperty() {
|
||||
doTestMemberInplaceRename("name1")
|
||||
}
|
||||
|
||||
fun testNoReformat() {
|
||||
doTestMemberInplaceRename("subject2")
|
||||
}
|
||||
|
||||
fun testInvokeToFoo() {
|
||||
doTestMemberInplaceRename("foo")
|
||||
}
|
||||
|
||||
fun testInvokeToGet() {
|
||||
doTestMemberInplaceRename("get")
|
||||
}
|
||||
|
||||
fun testInvokeToGetWithQualifiedExpr() {
|
||||
doTestMemberInplaceRename("get")
|
||||
}
|
||||
|
||||
fun testInvokeToGetWithSafeQualifiedExpr() {
|
||||
doTestMemberInplaceRename("get")
|
||||
}
|
||||
|
||||
fun testInvokeToPlus() {
|
||||
doTestMemberInplaceRename("plus")
|
||||
}
|
||||
|
||||
fun testGetToFoo() {
|
||||
doTestMemberInplaceRename("foo")
|
||||
}
|
||||
|
||||
fun testGetToInvoke() {
|
||||
doTestMemberInplaceRename("invoke")
|
||||
}
|
||||
|
||||
fun testGetToInvokeWithQualifiedExpr() {
|
||||
doTestMemberInplaceRename("invoke")
|
||||
}
|
||||
|
||||
fun testGetToInvokeWithSafeQualifiedExpr() {
|
||||
doTestMemberInplaceRename("invoke")
|
||||
}
|
||||
|
||||
fun testGetToPlus() {
|
||||
doTestMemberInplaceRename("plus")
|
||||
}
|
||||
|
||||
fun testAddQuotes() {
|
||||
doTestMemberInplaceRename("is")
|
||||
}
|
||||
|
||||
fun testAddThis() {
|
||||
doTestMemberInplaceRename("foo")
|
||||
}
|
||||
|
||||
fun testExtensionAndNoReceiver() {
|
||||
doTestMemberInplaceRename("b")
|
||||
}
|
||||
|
||||
fun testTwoExtensions() {
|
||||
doTestMemberInplaceRename("example")
|
||||
}
|
||||
|
||||
fun testQuotedLocalVar() {
|
||||
doTestMemberInplaceRename("x")
|
||||
}
|
||||
|
||||
fun testQuotedParameter() {
|
||||
doTestMemberInplaceRename("x")
|
||||
}
|
||||
|
||||
fun testEraseCompanionName() {
|
||||
doTestMemberInplaceRename("")
|
||||
}
|
||||
|
||||
fun testLocalVarRedeclaration() {
|
||||
doTestMemberInplaceRename("localValB")
|
||||
}
|
||||
|
||||
fun testLocalFunRedeclaration() {
|
||||
doTestMemberInplaceRename("localFunB")
|
||||
}
|
||||
|
||||
fun testLocalClassRedeclaration() {
|
||||
doTestMemberInplaceRename("LocalClassB")
|
||||
}
|
||||
|
||||
fun testBacktickedWithAccessors() {
|
||||
doTestMemberInplaceRename("`object`")
|
||||
}
|
||||
|
||||
fun testNoTextUsagesForLocalVar() {
|
||||
doTestMemberInplaceRename("w")
|
||||
}
|
||||
|
||||
private fun doTestImplicitLambdaParameter(newName: String) {
|
||||
configureByFile(getTestName(false) + ".kt")
|
||||
|
||||
// This code is copy-pasted from CodeInsightTestUtil.doInlineRename() and slightly modified.
|
||||
// Original method was not suitable because it expects renamed element to be reference to other or referrable
|
||||
|
||||
val file = getFile()!!
|
||||
val editor = getEditor()!!
|
||||
val element = file.findElementForRename<KtNameReferenceExpression>(editor.caretModel.offset)!!
|
||||
assertNotNull(element)
|
||||
|
||||
val dataContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PSI_ELEMENT.name, element,
|
||||
getCurrentEditorDataContext())
|
||||
val handler = RenameKotlinImplicitLambdaParameter()
|
||||
|
||||
assertTrue(handler.isRenaming(dataContext), "In-place rename not allowed for " + element)
|
||||
|
||||
val project = editor.project!!
|
||||
|
||||
TemplateManagerImpl.setTemplateTesting(project, testRootDisposable)
|
||||
|
||||
object : WriteCommandAction.Simple<Any>(project) {
|
||||
override fun run() {
|
||||
handler.invoke(project, editor, file, dataContext)
|
||||
}
|
||||
}.execute()
|
||||
|
||||
var state = TemplateManagerImpl.getTemplateState(editor)
|
||||
assert(state != null)
|
||||
val range = state!!.currentVariableRange
|
||||
assert(range != null)
|
||||
object : WriteCommandAction.Simple<Any>(project) {
|
||||
override fun run() {
|
||||
editor.document.replaceString(range!!.startOffset, range.endOffset, newName)
|
||||
}
|
||||
}.execute().throwException()
|
||||
|
||||
state = TemplateManagerImpl.getTemplateState(editor)
|
||||
assert(state != null)
|
||||
state!!.gotoEnd(false)
|
||||
|
||||
checkResultByFile(getTestName(false) + ".kt.after")
|
||||
}
|
||||
|
||||
private fun doTestMemberInplaceRename(newName: String?) {
|
||||
doTestInplaceRename(newName, KotlinMemberInplaceRenameHandler())
|
||||
}
|
||||
|
||||
private fun doTestInplaceRename(newName: String?, handler: VariableInplaceRenameHandler = KotlinVariableInplaceRenameHandler()) {
|
||||
configureByFile(getTestName(false) + ".kt")
|
||||
val element = TargetElementUtil.findTargetElement(
|
||||
editor,
|
||||
TargetElementUtil.ELEMENT_NAME_ACCEPTED or TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED
|
||||
)
|
||||
|
||||
assertNotNull(element)
|
||||
|
||||
val dataContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PSI_ELEMENT.name, element!!, currentEditorDataContext)
|
||||
|
||||
if (newName == null) {
|
||||
assertFalse(handler.isRenaming(dataContext), "In-place rename is allowed for " + element)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
assertTrue(handler.isRenaming(dataContext), "In-place rename not allowed for " + element)
|
||||
CodeInsightTestUtil.doInlineRename(handler, newName, getEditor(), element)
|
||||
checkResultByFile(getTestName(false) + ".kt.after")
|
||||
} catch (e: BaseRefactoringProcessor.ConflictsInTestsException) {
|
||||
val expectedMessage = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// SHOULD_FAIL_WITH: ")
|
||||
TestCase.assertEquals(expectedMessage, e.messages.joinToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.rename;
|
||||
|
||||
import com.intellij.codeInsight.TargetElementUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
||||
|
||||
public class SimpleNameReferenceRenameTest extends LightCodeInsightTestCase {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PluginTestCaseBase.getTestDataPathBase() + "/refactoring/rename/simpleNameReference/";
|
||||
}
|
||||
|
||||
public void testRenameLabel() throws Exception {
|
||||
doTest("foo");
|
||||
}
|
||||
|
||||
public void testRenameLabel2() throws Exception {
|
||||
doTest("anotherFoo");
|
||||
}
|
||||
|
||||
public void testRenameField() throws Exception {
|
||||
doTest("renamed");
|
||||
}
|
||||
|
||||
public void testRenameFieldIdentifier() throws Exception {
|
||||
doTest("anotherRenamed");
|
||||
}
|
||||
|
||||
public void testMemberOfLocalObject() throws Exception {
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testLocalFunction() throws Exception {
|
||||
doTest("xyzzy");
|
||||
}
|
||||
|
||||
public void testParameterOfCopyMethod() throws Exception {
|
||||
doTest("y");
|
||||
}
|
||||
|
||||
private void doTest(String newName) throws Exception {
|
||||
configureByFile(getTestName(true) + ".kt");
|
||||
PsiElement element = TargetElementUtil
|
||||
.findTargetElement(getEditor(),
|
||||
TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED);
|
||||
assertNotNull(element);
|
||||
new RenameProcessor(getProject(), element, newName, true, true).run();
|
||||
checkResultByFile(getTestName(true) + ".kt.after");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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.script
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.module.JavaModuleType
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.PlatformTestCase
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.idea.completion.test.KotlinCompletionTestCase
|
||||
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companion.updateScriptDependenciesSynchronously
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||
import org.jetbrains.kotlin.idea.core.script.isScriptDependenciesUpdaterDisabled
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.util.addDependency
|
||||
import org.jetbrains.kotlin.test.util.projectLibrary
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR
|
||||
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMMON_JAR
|
||||
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
|
||||
private val validKeys = setOf("javaHome", "sources", "classpath", "imports", "template-classes-names")
|
||||
private const val useDefaultTemplate = "// DEPENDENCIES:"
|
||||
private const val templatesSettings = "// TEMPLATES: "
|
||||
// some bugs can only be reproduced when some module and script have intersecting library dependencies
|
||||
private const val configureConflictingModule = "// CONFLICTING_MODULE"
|
||||
|
||||
private fun String.splitOrEmpty(delimeters: String) = split(delimeters).takeIf { it.size > 1 } ?: emptyList()
|
||||
internal val switches = listOf(
|
||||
useDefaultTemplate,
|
||||
configureConflictingModule
|
||||
)
|
||||
|
||||
abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
|
||||
companion object {
|
||||
private const val SCRIPT_NAME = "script.kts"
|
||||
}
|
||||
|
||||
override fun setUpModule() {
|
||||
// do not create default module
|
||||
}
|
||||
|
||||
private fun findMainScript(testDir: String): File {
|
||||
val scriptFile = File(testDir).walkTopDown().find { it.name == SCRIPT_NAME }
|
||||
if (scriptFile != null) return scriptFile
|
||||
|
||||
return File(testDir).walkTopDown().singleOrNull { it.name.contains("script") }
|
||||
?: error("Couldn't find $SCRIPT_NAME file in $testDir")
|
||||
}
|
||||
|
||||
private val sdk by lazy {
|
||||
val jdk = PluginTestCaseBase.jdk(TestJdkKind.MOCK_JDK)
|
||||
runWriteAction {
|
||||
ProjectJdkTable.getInstance().addJdk(jdk, testRootDisposable)
|
||||
ProjectRootManager.getInstance(project).projectSdk = jdk
|
||||
}
|
||||
jdk
|
||||
}
|
||||
|
||||
protected fun configureScriptFile(path: String) {
|
||||
val mainScriptFile = findMainScript(path)
|
||||
val environment = createScriptEnvironment(mainScriptFile)
|
||||
registerScriptTemplateProvider(environment)
|
||||
|
||||
File(path, "mainModule").takeIf { it.exists() }?.let {
|
||||
myModule = createTestModuleFromDir(it)
|
||||
}
|
||||
|
||||
File(path).listFiles { file -> file.name.startsWith("module") }.filter { it.exists() }.forEach {
|
||||
val newModule = createTestModuleFromDir(it)
|
||||
assert(myModule != null) { "Main module should exists" }
|
||||
ModuleRootModificationUtil.addDependency(myModule, newModule)
|
||||
}
|
||||
|
||||
if (module != null) {
|
||||
module.addDependency(
|
||||
projectLibrary(
|
||||
"script-runtime",
|
||||
classesRoot = VfsUtil.findFileByIoFile(PathUtil.kotlinPathsForDistDirectory.scriptRuntimePath, true)
|
||||
)
|
||||
)
|
||||
|
||||
if (environment["template-classes"] != null) {
|
||||
module.addDependency(
|
||||
projectLibrary(
|
||||
"script-template-library",
|
||||
classesRoot = VfsUtil.findFileByIoFile(environment["template-classes"] as File, true)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (configureConflictingModule in environment) {
|
||||
val sharedLib = VfsUtil.findFileByIoFile(environment["lib-classes"] as File, true)!!
|
||||
if (module == null) {
|
||||
// Force create module if it doesn't exist
|
||||
myModule = createTestModuleByName("mainModule")
|
||||
}
|
||||
module.addDependency(projectLibrary("sharedLib", classesRoot = sharedLib))
|
||||
}
|
||||
|
||||
if (module != null) {
|
||||
ModuleRootModificationUtil.updateModel(module) { model ->
|
||||
model.sdk = sdk
|
||||
}
|
||||
}
|
||||
|
||||
createFileAndSyncDependencies(mainScriptFile)
|
||||
}
|
||||
|
||||
private val oldScripClasspath: String? = System.getProperty("kotlin.script.classpath")
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
ApplicationManager.getApplication().isScriptDependenciesUpdaterDisabled = true
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
ApplicationManager.getApplication().isScriptDependenciesUpdaterDisabled = false
|
||||
|
||||
System.setProperty("kotlin.script.classpath", oldScripClasspath ?: "")
|
||||
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
private fun createTestModuleByName(name: String): Module {
|
||||
val newModuleDir = runWriteAction { VfsUtil.createDirectoryIfMissing(project.baseDir, name) }
|
||||
val newModule = createModuleAt(name, project, JavaModuleType.getModuleType(), newModuleDir.path)
|
||||
|
||||
// Return type was changed, but it's not used. BUNCH: 183
|
||||
@Suppress("MissingRecentApi")
|
||||
PsiTestUtil.addSourceContentToRoots(newModule, newModuleDir)
|
||||
return newModule
|
||||
}
|
||||
|
||||
private fun createTestModuleFromDir(dir: File): Module {
|
||||
return createTestModuleByName(dir.name).apply {
|
||||
PlatformTestCase.copyDirContentsTo(LocalFileSystem.getInstance().findFileByIoFile(dir)!!, moduleFile!!.parent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createScriptEnvironment(scriptFile: File): Environment {
|
||||
val defaultEnvironment = defaultEnvironment(scriptFile.parent + File.separator)
|
||||
val env = mutableMapOf<String, Any?>()
|
||||
scriptFile.forEachLine { line ->
|
||||
|
||||
fun iterateKeysInLine(prefix: String) {
|
||||
if (line.contains(prefix)) {
|
||||
line.trim().substringAfter(prefix).split(";").forEach { entry ->
|
||||
val (key, values) = entry.splitOrEmpty(":").map { it.trim() }
|
||||
assert(key in validKeys) { "Unexpected key: $key" }
|
||||
env[key] = values.split(",").map {
|
||||
val str = it.trim()
|
||||
defaultEnvironment[str] ?: str
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterateKeysInLine(useDefaultTemplate)
|
||||
iterateKeysInLine(templatesSettings)
|
||||
|
||||
switches.forEach {
|
||||
if (it in line) {
|
||||
env[it] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (env[useDefaultTemplate] != true && env["template-classes-names"] == null) {
|
||||
env["template-classes-names"] = listOf("custom.scriptDefinition.Template")
|
||||
}
|
||||
|
||||
if (env["javaHome"] != null) {
|
||||
val jdkKind = when ((env["javaHome"] as? List<String>)?.singleOrNull()) {
|
||||
"9" -> TestJdkKind.FULL_JDK_9
|
||||
else -> TestJdkKind.MOCK_JDK
|
||||
}
|
||||
runWriteAction {
|
||||
val jdk = PluginTestCaseBase.jdk(jdkKind)
|
||||
ProjectJdkTable.getInstance().addJdk(jdk, testRootDisposable)
|
||||
env["javaHome"] = File(jdk.homePath)
|
||||
}
|
||||
}
|
||||
|
||||
env.putAll(defaultEnvironment)
|
||||
return env
|
||||
}
|
||||
|
||||
private fun defaultEnvironment(path: String): Map<String, File?> {
|
||||
val templateOutDir = File("${path}template").takeIf { it.isDirectory }?.let {
|
||||
compileLibToDir(it, *scriptClasspath())
|
||||
} ?: File("idea/testData/script/definition/defaultTemplate").takeIf { it.isDirectory }?.let {
|
||||
compileLibToDir(it, *scriptClasspath())
|
||||
}
|
||||
|
||||
val libSrcDir = File("${path}lib").takeIf { it.isDirectory }
|
||||
|
||||
val libClasses = libSrcDir?.let { compileLibToDir(it) }
|
||||
|
||||
return mapOf(
|
||||
"runtime-classes" to ForTestCompileRuntime.runtimeJarForTests(),
|
||||
"runtime-source" to File("libraries/stdlib/src"),
|
||||
"lib-classes" to libClasses,
|
||||
"lib-source" to libSrcDir,
|
||||
"template-classes" to templateOutDir
|
||||
)
|
||||
}
|
||||
|
||||
private fun scriptClasspath(): Array<String> {
|
||||
return with(PathUtil.kotlinPathsForDistDirectory) {
|
||||
arrayOf(
|
||||
File(libPath, KOTLIN_JAVA_SCRIPT_RUNTIME_JAR).path,
|
||||
File(libPath, KOTLIN_SCRIPTING_COMMON_JAR).path,
|
||||
File(libPath, KOTLIN_SCRIPTING_JVM_JAR).path
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFileAndSyncDependencies(scriptFile: File) {
|
||||
var script: VirtualFile? = null
|
||||
if (module != null) {
|
||||
script = module.moduleFile?.parent?.findChild(scriptFile.name)
|
||||
}
|
||||
|
||||
if (script == null) {
|
||||
val target = File(project.basePath, scriptFile.name)
|
||||
scriptFile.copyTo(target)
|
||||
script = VfsUtil.findFileByIoFile(target, true)
|
||||
}
|
||||
|
||||
if (script == null) error("Test file with script couldn't be found in test project")
|
||||
|
||||
configureByExistingFile(script)
|
||||
updateScriptDependenciesSynchronously(myFile, project)
|
||||
|
||||
VfsUtil.markDirtyAndRefresh(false, true, true, project.baseDir)
|
||||
// This is needed because updateScriptDependencies invalidates psiFile that was stored in myFile field
|
||||
myFile = psiManager.findFile(script)
|
||||
|
||||
val ktFile = myFile as KtFile
|
||||
val reports = IdeScriptReportSink.getReports(ktFile)
|
||||
val isFatalErrorPresent = reports.any { it.severity == ScriptDiagnostic.Severity.FATAL }
|
||||
assert(isFatalErrorPresent || KotlinHighlightingUtil.shouldHighlight(myFile)) {
|
||||
"Highlighting is switched off for ${myFile.virtualFile.path}\n" +
|
||||
"reports=$reports\n" +
|
||||
"scriptDefinition=${ktFile.findScriptDefinition()}"
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileLibToDir(srcDir: File, vararg classpath: String): File {
|
||||
//TODO: tmpDir would be enough, but there is tricky fail under AS otherwise
|
||||
val outDir = KotlinTestUtils.tmpDirForReusableFolder("${getTestName(false)}${srcDir.name}Out")
|
||||
|
||||
val kotlinSourceFiles = FileUtil.findFilesByMask(Pattern.compile(".+\\.kt$"), srcDir)
|
||||
if (kotlinSourceFiles.isNotEmpty()) {
|
||||
MockLibraryUtil.compileKotlin(srcDir.path, outDir, extraClasspath = *classpath)
|
||||
}
|
||||
|
||||
val javaSourceFiles = FileUtil.findFilesByMask(Pattern.compile(".+\\.java$"), srcDir)
|
||||
if (javaSourceFiles.isNotEmpty()) {
|
||||
KotlinTestUtils.compileJavaFiles(
|
||||
javaSourceFiles,
|
||||
listOf("-cp", StringUtil.join(listOf(*classpath, outDir), File.pathSeparator), "-d", outDir.path)
|
||||
)
|
||||
}
|
||||
return outDir
|
||||
}
|
||||
|
||||
private fun registerScriptTemplateProvider(environment: Environment) {
|
||||
val provider = if (environment[useDefaultTemplate] == true) {
|
||||
FromTextTemplateProvider(environment)
|
||||
} else {
|
||||
CustomScriptTemplateProvider(environment)
|
||||
}
|
||||
|
||||
ScriptDefinitionContributor.EP_NAME.getPoint(null).registerExtension(provider)
|
||||
|
||||
ScriptDefinitionsManager.getInstance(project).reloadScriptDefinitions()
|
||||
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.test.util
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||
import com.intellij.openapi.vfs.JarFileSystem
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.HeavyPlatformTestCase
|
||||
import org.jetbrains.kotlin.test.testFramework.runWriteAction
|
||||
import java.io.File
|
||||
|
||||
fun HeavyPlatformTestCase.projectLibrary(
|
||||
libraryName: String = "TestLibrary",
|
||||
classesRoot: VirtualFile? = null,
|
||||
sourcesRoot: VirtualFile? = null,
|
||||
kind: PersistentLibraryKind<*>? = null
|
||||
): Library {
|
||||
return runWriteAction {
|
||||
val modifiableModel = ProjectLibraryTable.getInstance(project).modifiableModel
|
||||
val library = try {
|
||||
modifiableModel.createLibrary(libraryName, kind)
|
||||
} finally {
|
||||
modifiableModel.commit()
|
||||
}
|
||||
with (library.modifiableModel) {
|
||||
classesRoot?.let { addRoot(it, OrderRootType.CLASSES) }
|
||||
sourcesRoot?.let { addRoot(it, OrderRootType.SOURCES) }
|
||||
commit()
|
||||
}
|
||||
library
|
||||
}
|
||||
}
|
||||
|
||||
val File.jarRoot: VirtualFile
|
||||
get() {
|
||||
val virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(this) ?: error("Cannot find file $this")
|
||||
return JarFileSystem.getInstance().getRootByLocal(virtualFile) ?: error("Can't find root by file $virtualFile")
|
||||
}
|
||||
|
||||
fun Module.addDependency(
|
||||
library: Library,
|
||||
dependencyScope: DependencyScope = DependencyScope.COMPILE,
|
||||
exported: Boolean = false
|
||||
) = ModuleRootModificationUtil.addDependency(this, library, dependencyScope, exported)
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.j2k
|
||||
|
||||
import com.intellij.codeInsight.ContainerProvider
|
||||
import com.intellij.codeInsight.NullableNotNullManager
|
||||
import com.intellij.codeInsight.runner.JavaMainMethodProvider
|
||||
import com.intellij.core.CoreApplicationEnvironment
|
||||
import com.intellij.core.JavaCoreApplicationEnvironment
|
||||
import com.intellij.core.JavaCoreProjectEnvironment
|
||||
import com.intellij.lang.MetaLanguage
|
||||
import com.intellij.lang.jvm.facade.JvmElementProvider
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.extensions.ExtensionsArea
|
||||
import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.augment.PsiAugmentProvider
|
||||
import com.intellij.psi.augment.TypeAnnotationModifier
|
||||
import com.intellij.psi.compiled.ClassFileDecompilers
|
||||
import com.intellij.psi.impl.JavaClassSupersImpl
|
||||
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
||||
import com.intellij.psi.meta.MetaDataContributor
|
||||
import com.intellij.psi.stubs.BinaryFileStubBuilders
|
||||
import com.intellij.psi.util.JavaClassSupers
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
abstract class AbstractJavaToKotlinConverterForWebDemoTest : TestCase() {
|
||||
val DISPOSABLE = Disposer.newDisposable()
|
||||
|
||||
fun doTest(javaPath: String) {
|
||||
try {
|
||||
val fileContents = FileUtil.loadFile(File(javaPath), true)
|
||||
val javaCoreEnvironment: JavaCoreProjectEnvironment = setUpJavaCoreEnvironment()
|
||||
translateToKotlin(fileContents, javaCoreEnvironment.project)
|
||||
}
|
||||
finally {
|
||||
Disposer.dispose(DISPOSABLE)
|
||||
}
|
||||
}
|
||||
|
||||
fun setUpJavaCoreEnvironment(): JavaCoreProjectEnvironment {
|
||||
// FIXME: There is no `Extensions.cleanRootArea` in 193 platform
|
||||
// Extensions.cleanRootArea(DISPOSABLE)
|
||||
val area = Extensions.getRootArea()
|
||||
|
||||
registerExtensionPoints(area)
|
||||
|
||||
val applicationEnvironment = JavaCoreApplicationEnvironment(DISPOSABLE)
|
||||
val javaCoreEnvironment = object : JavaCoreProjectEnvironment(DISPOSABLE, applicationEnvironment) {
|
||||
override fun preregisterServices() {
|
||||
val projectArea = Extensions.getArea(project)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiElementFinder.EP_NAME, PsiElementFinder::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(projectArea, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
javaCoreEnvironment.project.registerService(NullableNotNullManager::class.java, object : NullableNotNullManager(javaCoreEnvironment.project) {
|
||||
override fun isNullable(owner: PsiModifierListOwner, checkBases: Boolean) = !isNotNull(owner, checkBases)
|
||||
override fun isNotNull(owner: PsiModifierListOwner, checkBases: Boolean) = true
|
||||
override fun hasHardcodedContracts(element: PsiElement): Boolean = false
|
||||
override fun getNullables() = emptyList<String>()
|
||||
override fun setNullables(vararg p0: String) = Unit
|
||||
override fun getNotNulls() = emptyList<String>()
|
||||
override fun setNotNulls(vararg p0: String) = Unit
|
||||
override fun getDefaultNullable() = ""
|
||||
override fun setDefaultNullable(defaultNullable: String) = Unit
|
||||
override fun getDefaultNotNull() = ""
|
||||
override fun setDefaultNotNull(p0: String) = Unit
|
||||
override fun setInstrumentedNotNulls(p0: List<String>) = Unit
|
||||
override fun getInstrumentedNotNulls() = emptyList<String>()
|
||||
})
|
||||
|
||||
applicationEnvironment.application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
|
||||
|
||||
for (root in PathUtil.getJdkClassesRootsFromCurrentJre()) {
|
||||
javaCoreEnvironment.addJarToClassPath(root)
|
||||
}
|
||||
val annotations: File? = findAnnotations()
|
||||
if (annotations != null && annotations.exists()) {
|
||||
javaCoreEnvironment.addJarToClassPath(annotations)
|
||||
}
|
||||
return javaCoreEnvironment
|
||||
}
|
||||
|
||||
private fun registerExtensionPoints(area: ExtensionsArea) {
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider::class.java)
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider::class.java)
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler::class.java)
|
||||
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
|
||||
}
|
||||
|
||||
fun findAnnotations(): File? {
|
||||
var classLoader = JavaToKotlinTranslator::class.java.classLoader
|
||||
while (classLoader != null) {
|
||||
val loader = classLoader
|
||||
if (loader is URLClassLoader) {
|
||||
for (url in loader.urLs) {
|
||||
if ("file" == url.protocol && url.file!!.endsWith("/annotations.jar")) {
|
||||
return File(url.file!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
classLoader = classLoader.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.uast.test.kotlin
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.patterns.uast.injectionHostUExpression
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl
|
||||
import com.intellij.psi.util.PropertyUtil
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.registerServiceInstance
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.evaluateString
|
||||
import org.jetbrains.uast.toUElementOfType
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.fail
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class KotlinUastReferencesTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||
|
||||
|
||||
@Test
|
||||
fun `test original getter is visible when reference is under renaming`() {
|
||||
|
||||
registerReferenceProviders(testRootDisposable) {
|
||||
registerUastReferenceProvider(injectionHostUExpression(), uastInjectionHostReferenceProvider { _, psiLanguageInjectionHost ->
|
||||
arrayOf(GetterReference("KotlinBean", psiLanguageInjectionHost))
|
||||
})
|
||||
}
|
||||
|
||||
myFixture.configureByText(
|
||||
"KotlinBean.kt", """
|
||||
data class KotlinBean(val myF<caret>ield: String)
|
||||
|
||||
val reference = "myField"
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
myFixture.renameElementAtCaret("myRenamedField")
|
||||
|
||||
myFixture.checkResult(
|
||||
"""
|
||||
data class KotlinBean(val myRenamedField: String)
|
||||
|
||||
val reference = "myRenamedField"
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GetterReference(
|
||||
val className: String,
|
||||
psiElement: PsiElement
|
||||
) : PsiReferenceBase<PsiElement>(psiElement) {
|
||||
override fun resolve(): PsiMethod? {
|
||||
val psiClass = JavaPsiFacade.getInstance(element.project).findClass(className, element.resolveScope) ?: return null
|
||||
val name = element.toUElementOfType<UExpression>()?.evaluateString() ?: return null
|
||||
return PropertyUtil.getGetters(psiClass, name).firstOrNull()
|
||||
}
|
||||
|
||||
override fun handleElementRename(newElementName: String): PsiElement {
|
||||
val resolve = resolve()
|
||||
?: fail("can't resolve during rename, looks like someone renamed or removed the source element before updating references")
|
||||
|
||||
val newName =
|
||||
if (PropertyUtil.getPropertyName(resolve) != null)
|
||||
PropertyUtil.getPropertyName(newElementName) ?: newElementName
|
||||
else newElementName
|
||||
|
||||
return super.handleElementRename(newName)
|
||||
}
|
||||
|
||||
override fun getVariants(): Array<Any> = emptyArray()
|
||||
}
|
||||
|
||||
|
||||
fun registerReferenceProviders(disposable: Disposable, registerContributors: PsiReferenceRegistrar.() -> Unit) {
|
||||
registerReferenceContributor(object : PsiReferenceContributor() {
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) = registrar.registerContributors()
|
||||
}, disposable)
|
||||
}
|
||||
|
||||
fun registerReferenceContributor(contributor: PsiReferenceContributor, disposable: Disposable) {
|
||||
error("PsiReferenceContributorEP is final in 193 platform")
|
||||
// val referenceContributorEp = Extensions.getArea(null).getExtensionPoint<PsiReferenceContributorEP>(PsiReferenceContributor.EP_NAME.name)
|
||||
//
|
||||
// val contributorEp = object : PsiReferenceContributorEP() {
|
||||
// override fun getInstance(): PsiReferenceContributor = contributor
|
||||
// }
|
||||
//
|
||||
// referenceContributorEp.registerExtension(contributorEp)
|
||||
//
|
||||
// val application = ApplicationManager.getApplication()
|
||||
//
|
||||
// //we need a fresh ReferenceProvidersRegistry after updating ReferenceContributors
|
||||
// val oldReferenceProviderRegistry =
|
||||
// application.picoContainer.getComponentInstance(ReferenceProvidersRegistry::class.java) as ReferenceProvidersRegistry
|
||||
// application.registerServiceInstance(ReferenceProvidersRegistry::class.java, ReferenceProvidersRegistryImpl())
|
||||
//
|
||||
// Disposer.register(disposable, Disposable {
|
||||
// referenceContributorEp.unregisterExtension(contributorEp)
|
||||
// application.registerServiceInstance(ReferenceProvidersRegistry::class.java, oldReferenceProviderRegistry)
|
||||
// })
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user