Remove 173 bunch files

This commit is contained in:
Vyacheslav Gerasimov
2019-01-14 15:34:41 +03:00
parent 96c21297b6
commit 818910267e
475 changed files with 0 additions and 82220 deletions
@@ -1,135 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android
import com.android.SdkConstants
import com.android.resources.ResourceType
import com.intellij.codeHighlighting.Pass
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler
import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.codeInsight.navigation.NavigationUtil
import com.intellij.icons.AllIcons
import com.intellij.ide.highlighter.XmlFileType
import com.intellij.navigation.GotoRelatedItem
import com.intellij.openapi.editor.markup.GutterIconRenderer
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.xml.XmlAttributeValue
import com.intellij.ui.awt.RelativePoint
import com.intellij.util.Function
import org.jetbrains.android.dom.manifest.Manifest
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import java.awt.event.MouseEvent
import javax.swing.Icon
class KotlinAndroidLineMarkerProvider : LineMarkerProvider {
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? = null
override fun collectSlowLineMarkers(elements: List<PsiElement>, result: MutableCollection<LineMarkerInfo<PsiElement>>) {
elements.forEach {
(it as? KtClass)?.getLineMarkerInfo()?.let { marker -> result.add(marker) }
}
}
private fun KtClass.getLineMarkerInfo(): LineMarkerInfo<PsiElement>? {
val nameIdentifier = nameIdentifier ?: return null
val androidFacet = AndroidFacet.getInstance(this) ?: return null
val manifest = androidFacet.manifest ?: return null
val manifestItems = collectGoToRelatedManifestItems(manifest)
if (manifestItems.isEmpty() && !isClassWithLayoutXml()) {
return null
}
return LineMarkerInfo(
nameIdentifier,
nameIdentifier.textRange,
AllIcons.FileTypes.Xml,
Pass.LINE_MARKERS,
Function { "Related XML file" },
GutterIconNavigationHandler { e: MouseEvent, _: PsiElement ->
NavigationUtil
.getRelatedItemsPopup(
manifestItems + collectGoToRelatedLayoutItems(androidFacet),
"Go to Related Files")
.show(RelativePoint(e))
},
GutterIconRenderer.Alignment.RIGHT)
}
private fun KtClass.collectGoToRelatedLayoutItems(androidFacet: AndroidFacet): List<GotoRelatedItem> {
val resources = mutableSetOf<PsiFile>()
accept(object: KtVisitorVoid() {
override fun visitKtElement(element: KtElement) {
element.acceptChildren(this)
}
override fun visitReferenceExpression(expression: KtReferenceExpression) {
super.visitReferenceExpression(expression)
val resClassName = ResourceType.LAYOUT.getName()
val info = (expression as? KtSimpleNameExpression)?.let {
getReferredResourceOrManifestField(androidFacet, it, resClassName, true)
}
if (info == null || info.isFromManifest) {
return
}
val files = androidFacet
.localResourceManager
.findResourcesByFieldName(resClassName, info.fieldName)
.filterIsInstance<PsiFile>()
resources.addAll(files)
}
})
return resources.map { GotoRelatedLayoutItem(it) }
}
private fun KtClass.collectGoToRelatedManifestItems(manifest: Manifest): List<GotoRelatedItem> =
findComponentDeclarationInManifest(manifest)?.xmlAttributeValue?.let { listOf(GotoManifestItem(it)) } ?: emptyList()
private class GotoManifestItem(attributeValue: XmlAttributeValue) : GotoRelatedItem(attributeValue) {
override fun getCustomName(): String? = "AndroidManifest.xml"
override fun getCustomContainerName(): String? = ""
override fun getCustomIcon(): Icon? = XmlFileType.INSTANCE.icon
}
private class GotoRelatedLayoutItem(private val file: PsiFile) : GotoRelatedItem(file, "Layout Files") {
override fun getCustomContainerName(): String? = "(${file.containingDirectory.name})"
}
companion object {
private val CLASSES_WITH_LAYOUT_XML = arrayOf(
SdkConstants.CLASS_ACTIVITY,
SdkConstants.CLASS_FRAGMENT,
SdkConstants.CLASS_V4_FRAGMENT,
"android.widget.Adapter")
private fun KtClass.isClassWithLayoutXml(): Boolean {
val type = (unsafeResolveToDescriptor(BodyResolveMode.PARTIAL) as? ClassDescriptor)?.defaultType ?: return false
return CLASSES_WITH_LAYOUT_XML.any { type.isSubclassOf(it, true) }
}
}
}
@@ -1,270 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.resources.ResourceItem;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.common.resources.ResourceResolver;
import com.android.resources.ResourceType;
import com.android.tools.idea.configurations.Configuration;
import com.android.tools.idea.res.AppResourceRepository;
import com.android.tools.idea.res.LocalResourceRepository;
import com.android.tools.idea.res.ResourceHelper;
import com.android.tools.idea.ui.resourcechooser.ColorPicker;
import com.android.utils.XmlUtils;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ui.ColorIcon;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.JBUI;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import static com.android.SdkConstants.*;
import static com.android.SdkConstants.ANDROID_URI;
import static com.android.SdkConstants.ATTR_DRAWABLE;
import static com.android.tools.idea.uibuilder.property.renderer.NlDefaultRenderer.ICON_SIZE;
import static org.jetbrains.android.AndroidColorAnnotator.pickLayoutFile;
/**
* Contains copied privates from AndroidColorAnnotator, so we could use them for Kotlin AndroidResourceReferenceAnnotator
*/
public class ResourceReferenceAnnotatorUtil {
@Nullable
public static File pickBitmapFromXml(@NotNull File file, @NotNull ResourceResolver resourceResolver, @NotNull Project project) {
try {
String xml = Files.toString(file, Charsets.UTF_8);
Document document = XmlUtils.parseDocumentSilently(xml, true);
if (document != null && document.getDocumentElement() != null) {
Element root = document.getDocumentElement();
String tag = root.getTagName();
Element target = null;
String attribute = null;
if ("vector".equals(tag)) {
// Vectors are handled in the icon cache
return file;
}
else if ("bitmap".equals(tag) || "nine-patch".equals(tag)) {
target = root;
attribute = ATTR_SRC;
}
else if ("selector".equals(tag) ||
"level-list".equals(tag) ||
"layer-list".equals(tag) ||
"transition".equals(tag)) {
NodeList children = root.getChildNodes();
for (int i = children.getLength() - 1; i >= 0; i--) {
Node item = children.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE && TAG_ITEM.equals(item.getNodeName())) {
target = (Element)item;
if (target.hasAttributeNS(ANDROID_URI, ATTR_DRAWABLE)) {
attribute = ATTR_DRAWABLE;
break;
}
}
}
}
else if ("clip".equals(tag) || "inset".equals(tag) || "scale".equals(tag)) {
target = root;
attribute = ATTR_DRAWABLE;
} else {
// <shape> etc - no bitmap to be found
return null;
}
if (attribute != null && target.hasAttributeNS(ANDROID_URI, attribute)) {
String src = target.getAttributeNS(ANDROID_URI, attribute);
ResourceValue value = resourceResolver.findResValue(src, false);
if (value != null) {
return ResourceHelper.resolveDrawable(resourceResolver, value, project);
}
}
}
} catch (Throwable ignore) {
// Not logging for now; afraid to risk unexpected crashes in upcoming preview. TODO: Re-enable.
//Logger.getInstance(AndroidColorAnnotator.class).warn(String.format("Could not read/render icon image %1$s", file), e);
}
return null;
}
/** Looks up the resource item of the given type and name for the given configuration, if any */
@Nullable
public static ResourceValue findResourceValue(ResourceType type,
String name,
boolean isFramework,
Module module,
Configuration configuration) {
if (isFramework) {
ResourceRepository frameworkResources = configuration.getFrameworkResources();
if (frameworkResources == null) {
return null;
}
if (!frameworkResources.hasResourceItem(type, name)) {
return null;
}
ResourceItem item = frameworkResources.getResourceItem(type, name);
return item.getResourceValue(type, configuration.getFullConfig(), false);
} else {
LocalResourceRepository appResources = AppResourceRepository.getAppResources(module, true);
if (appResources == null) {
return null;
}
if (!appResources.hasResourceItem(type, name)) {
return null;
}
return appResources.getConfiguredValue(type, name, configuration.getFullConfig());
}
}
/** Picks a suitable configuration to use for resource resolution */
@Nullable
public static Configuration pickConfiguration(AndroidFacet facet, Module module, PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) {
return null;
}
VirtualFile parent = virtualFile.getParent();
if (parent == null) {
return null;
}
VirtualFile layout;
String parentName = parent.getName();
if (!parentName.startsWith(FD_RES_LAYOUT)) {
layout = pickLayoutFile(module, facet);
if (layout == null) {
return null;
}
} else {
layout = virtualFile;
}
return facet.getConfigurationManager().getConfiguration(layout);
}
public static class ColorRenderer extends GutterIconRenderer {
private final PsiElement myElement;
private final Color myColor;
ColorRenderer(@NotNull PsiElement element, @Nullable Color color) {
myElement = element;
myColor = color;
}
@NotNull
@Override
public Icon getIcon() {
Color color = getCurrentColor();
return JBUI.scale(color == null ? EmptyIcon.create(ICON_SIZE) : new ColorIcon(ICON_SIZE, color));
}
@Nullable
private Color getCurrentColor() {
if (myColor != null) {
return myColor;
} else if (myElement instanceof XmlTag) {
return ResourceHelper.parseColor(((XmlTag)myElement).getValue().getText());
} else if (myElement instanceof XmlAttributeValue) {
return ResourceHelper.parseColor(((XmlAttributeValue)myElement).getValue());
} else {
return null;
}
}
@Override
public AnAction getClickAction() {
if (myColor != null) { // Cannot set colors that were derived
return null;
}
return new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
if (editor != null) {
// Need ARGB support in platform color chooser; see
// https://youtrack.jetbrains.com/issue/IDEA-123498
//final Color color =
// ColorChooser.chooseColor(editor.getComponent(), AndroidBundle.message("android.choose.color"), getCurrentColor());
final Color color = ColorPicker.showDialog(editor.getComponent(), "Choose Color", getCurrentColor(), true, null, false);
if (color != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
if (myElement instanceof XmlTag) {
((XmlTag)myElement).getValue().setText(ResourceHelper.colorToString(color));
} else if (myElement instanceof XmlAttributeValue) {
XmlAttribute attribute = PsiTreeUtil.getParentOfType(myElement, XmlAttribute.class);
if (attribute != null) {
attribute.setValue(ResourceHelper.colorToString(color));
}
}
}
});
}
}
}
};
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ColorRenderer that = (ColorRenderer)o;
// TODO: Compare with modification count in app resources (if not framework)
if (myColor != null ? !myColor.equals(that.myColor) : that.myColor != null) return false;
if (!myElement.equals(that.myElement)) return false;
return true;
}
@Override
public int hashCode() {
int result = myElement.hashCode();
result = 31 * result + (myColor != null ? myColor.hashCode() : 0);
return result;
}
}
}
@@ -1,133 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
import com.android.tools.idea.gradle.util.FilePaths
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDataService.CREATE_EMPTY_DIRECTORIES
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.util.containers.stream
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.gradle.KotlinCompilation
import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler
import org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService
import org.jetbrains.kotlin.idea.configuration.kotlinAndroidSourceSets
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import java.io.File
import java.io.IOException
class KotlinAndroidGradleMPPModuleDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
private fun shouldCreateEmptySourceRoots(
moduleDataNode: DataNode<ModuleData>,
module: Module
): Boolean {
val projectDataNode = ExternalSystemApiUtil.findParent(moduleDataNode, ProjectKeys.PROJECT) ?: return false
if (projectDataNode.getUserData<Boolean>(CREATE_EMPTY_DIRECTORIES) == true) return true
val projectSystemId = projectDataNode.data.owner
val externalSystemSettings = ExternalSystemApiUtil.getSettings(module.project, projectSystemId)
val path = ExternalSystemModulePropertyManager.getInstance(module).getRootProjectPath() ?: return false
return externalSystemSettings.getLinkedProjectSettings(path)?.isCreateEmptyContentRootDirectories ?: false
}
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (nodeToImport in toImport) {
val projectNode = ExternalSystemApiUtil.findParent(nodeToImport, ProjectKeys.PROJECT) ?: continue
val moduleData = nodeToImport.data
val module = modelsProvider.findIdeModule(moduleData) ?: continue
val shouldCreateEmptySourceRoots = shouldCreateEmptySourceRoots(nodeToImport, module)
val rootModel = modelsProvider.getModifiableRootModel(module)
val kotlinAndroidSourceSets = nodeToImport.kotlinAndroidSourceSets ?: continue
for (sourceSetInfo in kotlinAndroidSourceSets) {
val compilation = sourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
for (sourceSet in compilation.sourceSets) {
if (sourceSet.platform == KotlinPlatform.ANDROID) {
val sourceType = if (sourceSet.isTestModule) JavaSourceRootType.TEST_SOURCE else JavaSourceRootType.SOURCE
val resourceType = if (sourceSet.isTestModule) JavaResourceRootType.TEST_RESOURCE else JavaResourceRootType.RESOURCE
sourceSet.sourceDirs.forEach { addSourceRoot(it, sourceType, rootModel, shouldCreateEmptySourceRoots) }
sourceSet.resourceDirs.forEach { addSourceRoot(it, resourceType, rootModel, shouldCreateEmptySourceRoots) }
}
}
}
val androidModel = module.getAndroidModel(modelsProvider) ?: continue
val variantName = androidModel.selectedVariant.name
val activeSourceSetInfos = nodeToImport.kotlinAndroidSourceSets?.filter { it.kotlinModule.name.startsWith(variantName) } ?: emptyList()
for (activeSourceSetInfo in activeSourceSetInfos) {
val activeCompilation = activeSourceSetInfo.kotlinModule as? KotlinCompilation ?: continue
for (sourceSet in activeCompilation.sourceSets) {
if (sourceSet.platform != KotlinPlatform.ANDROID) {
val sourceSetId = activeSourceSetInfo.sourceSetIdsByName[sourceSet.name] ?: continue
val sourceSetData = ExternalSystemApiUtil.findFirstRecursively(projectNode) {
(it.data as? ModuleData)?.id == sourceSetId
}?.data as? ModuleData ?: continue
val sourceSetModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
val existingEntry = rootModel.findModuleOrderEntry(sourceSetModule)
val dependencyScope = if (activeSourceSetInfo.isTestModule) DependencyScope.TEST else DependencyScope.COMPILE
if (existingEntry != null && existingEntry.scope == dependencyScope) continue
rootModel.addModuleOrderEntry(sourceSetModule).also { it.scope = dependencyScope }
}
}
}
val mainSourceSetInfo = activeSourceSetInfos.firstOrNull { it.kotlinModule.name == variantName }
if (mainSourceSetInfo != null) {
KotlinSourceSetDataService.configureFacet(moduleData, mainSourceSetInfo, nodeToImport, module, modelsProvider)
}
val kotlinFacet = KotlinFacet.get(module)
if (kotlinFacet != null) {
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, nodeToImport) }
}
}
}
private fun addSourceRoot(
sourceRoot: File,
type: JpsModuleSourceRootType<*>,
rootModel: ModifiableRootModel,
shouldCreateEmptySourceRoots: Boolean
) {
val parent = FilePaths.findParentContentEntry(sourceRoot, rootModel.contentEntries) ?: return
val url = FilePaths.pathToIdeaUrl(sourceRoot)
parent.addSourceFolder(url, type)
if (shouldCreateEmptySourceRoots) {
ExternalSystemApiUtil.doWriteAction {
try {
VfsUtil.createDirectoryIfMissing(sourceRoot.path)
} catch (e: IOException) {
LOG.warn(String.format("Unable to create directory for the path: %s", sourceRoot.path), e)
}
}
}
}
companion object {
private val LOG = Logger.getInstance(KotlinAndroidGradleMPPModuleDataService::class.java)
}
}
@@ -1,98 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.android.configure
import com.android.builder.model.AndroidProject
import com.android.builder.model.NativeAndroidProject
import com.android.tools.idea.IdeInfo
import com.android.tools.idea.gradle.ImportedModule
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys.IMPORTED_MODULE
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
import com.intellij.openapi.externalSystem.util.Order
import org.gradle.tooling.model.idea.IdeaModule
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModelBuilder
import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.idea.configuration.KotlinAndroidSourceSetData
import org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver
import org.jetbrains.kotlin.idea.configuration.kotlinSourceSet
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
@Order(ExternalSystemConstants.UNORDERED - 1)
class KotlinAndroidMPPGradleProjectResolver : AbstractProjectResolverExtension() {
private val isAndroidProject by lazy {
resolverCtx.hasModulesWithModel(AndroidProject::class.java)
|| resolverCtx.hasModulesWithModel(NativeAndroidProject::class.java)
}
override fun getToolingExtensionsClasses(): Set<Class<out Any>> {
return setOf(KotlinMPPGradleModelBuilder::class.java, Unit::class.java)
}
override fun getExtraProjectModelClasses(): Set<Class<out Any>> {
return setOf(KotlinMPPGradleModel::class.java)
}
override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
return super.createModule(gradleModule, projectDataNode).also {
initializeModuleData(gradleModule, it, projectDataNode)
}
}
override fun populateModuleContentRoots(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
super.populateModuleContentRoots(gradleModule, ideModule)
if (IdeInfo.getInstance().isAndroidStudio || isAndroidProject) {
KotlinMPPGradleProjectResolver.populateContentRoots(gradleModule, ideModule, resolverCtx)
// Work around module disposal service which discards modules without accompanying ImportedModule instance
for (childNode in ExternalSystemApiUtil.getChildren(ideModule, GradleSourceSetData.KEY)) {
if (childNode.kotlinSourceSet == null) continue
val moduleName = childNode.data.internalName
val importedModule = ImportedModule(gradleModule)
importedModuleNameField.set(importedModule, moduleName)
ideModule.createChild(IMPORTED_MODULE, importedModule)
}
}
}
override fun populateModuleDependencies(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>, ideProject: DataNode<ProjectData>) {
super.populateModuleDependencies(gradleModule, ideModule, ideProject)
if (isAndroidProject) {
KotlinMPPGradleProjectResolver.populateModuleDependencies(gradleModule, ideProject, ideModule, resolverCtx)
}
}
private fun initializeModuleData(
gradleModule: IdeaModule,
mainModuleData: DataNode<ModuleData>,
projectDataNode: DataNode<ProjectData>
) {
if (!isAndroidProject) return
KotlinMPPGradleProjectResolver.initializeModuleData(gradleModule, mainModuleData, projectDataNode, resolverCtx)
val mppModel = resolverCtx.getExtraProject(gradleModule, KotlinMPPGradleModel::class.java) ?: return
val androidSourceSets = mppModel
.targets
.asSequence()
.flatMap { it.compilations.asSequence() }
.filter { it.platform == KotlinPlatform.ANDROID }
.mapNotNull { KotlinMPPGradleProjectResolver.createSourceSetInfo(it, gradleModule, resolverCtx) }
.toList()
mainModuleData.createChild(KotlinAndroidSourceSetData.KEY, KotlinAndroidSourceSetData(androidSourceSets))
}
companion object {
val importedModuleNameField by lazy {
ImportedModule::class.java.getDeclaredField("myName").apply { isAccessible = true }
}
}
}
@@ -1,66 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.debugger
import com.android.dx.cf.direct.DirectClassFile
import com.android.dx.cf.direct.StdAttributeFactory
import com.android.dx.dex.DexOptions
import com.android.dx.dex.cf.CfOptions
import com.android.dx.dex.cf.CfTranslator
import com.android.dx.dex.file.ClassDefItem
import com.android.dx.dex.file.DexFile
import com.intellij.ide.plugins.DynamicallyLoaded
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.ClassToLoad
import java.lang.reflect.Modifier
class AndroidDexWrapper {
@Suppress("unused") // Used in AndroidOClassLoadingAdapter#dex
fun dex(classes: Collection<ClassToLoad>): ByteArray? {
val dexOptions = DexOptions()
val cfOptions = CfOptions()
val dexFile = DexFile(dexOptions)
val methodWithContext = CfTranslator::class.java.declaredMethods
.singleOrNull { it.name == "translate" && Modifier.isStatic(it.modifiers) && it.parameterCount == 6 }
val dxContext = methodWithContext?.let { Class.forName("com.android.dx.command.dexer.DxContext").newInstance() }
for ((_, relativeFileName, bytes) in classes) {
val cf = DirectClassFile(bytes, relativeFileName, true)
cf.setAttributeFactory(StdAttributeFactory.THE_ONE)
val classDef = if (methodWithContext != null) {
methodWithContext(
null,
dxContext,
cf,
bytes,
cfOptions,
dexOptions,
dexFile
) as ClassDefItem
} else {
CfTranslator.translate(cf, bytes, cfOptions, dexOptions, dexFile)
}
dexFile.add(classDef)
}
return dexFile.toDex(null, false)
}
}
@@ -1,72 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.debugger
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.AndroidDexer
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.ClassToLoad
import java.io.File
import java.net.URLClassLoader
import java.security.ProtectionDomain
class AndroidDexerImpl(val project: Project) : AndroidDexer {
private val cachedDexWrapper = CachedValuesManager.getManager(project).createCachedValue({
val dexWrapper = doGetAndroidDexFile()?.let { dexJarFile ->
val androidDexWrapperName = AndroidDexWrapper::class.java.canonicalName
val classBytes = this.javaClass.classLoader.getResource(
androidDexWrapperName.replace('.', '/') + ".class").readBytes()
val dexClassLoader = object : URLClassLoader(arrayOf(dexJarFile.toURI().toURL()), this::class.java.classLoader) {
init {
defineClass(androidDexWrapperName, classBytes, 0, classBytes.size, null as ProtectionDomain?)
}
}
Class.forName(androidDexWrapperName, true, dexClassLoader).newInstance()
}
CachedValueProvider.Result.createSingleDependency(dexWrapper, ProjectRootModificationTracker.getInstance(project))
}, /* trackValue = */ false)
override fun dex(classes: Collection<ClassToLoad>): ByteArray? {
val dexWrapper = cachedDexWrapper.value
val dexMethod = dexWrapper::class.java.methods.firstOrNull { it.name == "dex" } ?: return null
return dexMethod.invoke(dexWrapper, classes) as? ByteArray ?: return null
}
private fun doGetAndroidDexFile(): File? {
for (module in ModuleManager.getInstance(project).modules) {
val androidFacet = AndroidFacet.getInstance(module) ?: continue
val sdkData = androidFacet.sdkData ?: continue
val latestBuildTool = sdkData.getLatestBuildTool(/* allowPreview = */ false)
?: sdkData.getLatestBuildTool(/* allowPreview = */ true)
?: continue
val dxJar = File(latestBuildTool.location, "lib/dx.jar")
if (dxJar.exists()) {
return dxJar
}
}
return null
}
}
@@ -1,259 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.folding
import com.android.SdkConstants.*
import com.android.ide.common.resources.configuration.FolderConfiguration
import com.android.ide.common.resources.configuration.LocaleQualifier
import com.android.resources.ResourceType
import com.android.tools.idea.folding.AndroidFoldingSettings
import com.android.tools.idea.res.AppResourceRepository
import com.android.tools.idea.res.LocalResourceRepository
import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilderEx
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.editor.Document
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.SourceTreeToPsiMap
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.uast.*
import org.jetbrains.uast.visitor.AbstractUastVisitor
import java.util.regex.Pattern
class ResourceFoldingBuilder : FoldingBuilderEx() {
companion object {
// See lint's StringFormatDetector
private val FORMAT = Pattern.compile("%(\\d+\\$)?([-+#, 0(<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])")
private val FOLD_MAX_LENGTH = 60
private val FORCE_PROJECT_RESOURCE_LOADING = true
private val UNIT_TEST_MODE: Boolean = ApplicationManager.getApplication().isUnitTestMode
private val RESOURCE_TYPES = listOf(ResourceType.STRING,
ResourceType.DIMEN,
ResourceType.INTEGER,
ResourceType.PLURALS)
}
private val isFoldingEnabled = AndroidFoldingSettings.getInstance().isCollapseAndroidStrings
override fun getPlaceholderText(node: ASTNode): String? {
tailrec fun UElement.unwrapReferenceAndGetValue(resources: LocalResourceRepository): String? = when (this) {
is UQualifiedReferenceExpression -> selector.unwrapReferenceAndGetValue(resources)
is UCallExpression -> (valueArguments.firstOrNull() as? UReferenceExpression)?.getAndroidResourceValue(resources, this)
else -> (this as? UReferenceExpression)?.getAndroidResourceValue(resources)
}
val element = SourceTreeToPsiMap.treeElementToPsi(node) ?: return null
val appResources = getAppResources(element) ?: return null
val uastContext = ServiceManager.getService(element.project, UastContext::class.java) ?: return null
return uastContext.convertElement(element, null, null)?.unwrapReferenceAndGetValue(appResources)
}
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> {
if (root !is KtFile || quick && !UNIT_TEST_MODE || !isFoldingEnabled || AndroidFacet.getInstance(root) == null) {
return emptyArray()
}
val file = root.toUElement()
val result = arrayListOf<FoldingDescriptor>()
file?.accept(object : AbstractUastVisitor() {
override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean {
node.getFoldingDescriptor()?.let { result.add(it) }
return super.visitSimpleNameReferenceExpression(node)
}
})
return result.toTypedArray()
}
override fun isCollapsedByDefault(node: ASTNode): Boolean = isFoldingEnabled
private fun UReferenceExpression.getFoldingDescriptor(): FoldingDescriptor? {
val resolved = resolve() ?: return null
val resourceType = resolved.getAndroidResourceType() ?: return null
if (resourceType !in RESOURCE_TYPES) return null
fun UElement.createFoldingDescriptor() = psi?.let { psi ->
val dependencies: Set<PsiElement> = setOf(psi)
FoldingDescriptor(psi.node, psi.textRange, null, dependencies)
}
val element = uastParent as? UQualifiedReferenceExpression ?: this
val getResourceValueCall = (element.uastParent as? UCallExpression)?.takeIf { it.isFoldableGetResourceValueCall() }
if (getResourceValueCall != null) {
val qualifiedCall = getResourceValueCall.uastParent as? UQualifiedReferenceExpression
if (qualifiedCall?.selector == getResourceValueCall) {
return qualifiedCall.createFoldingDescriptor()
}
return getResourceValueCall.createFoldingDescriptor()
}
return element.createFoldingDescriptor()
}
private fun UCallExpression.isFoldableGetResourceValueCall(): Boolean {
return methodName == "getString" ||
methodName == "getText" ||
methodName == "getInteger" ||
methodName?.startsWith("getDimension") ?: false ||
methodName?.startsWith("getQuantityString") ?: false
}
private fun PsiElement.getAndroidResourceType(): ResourceType? {
val elementType = parent as? PsiClass ?: return null
val elementPackage = elementType.parent as? PsiClass ?: return null
if (R_CLASS != elementPackage.name) return null
if (elementPackage.qualifiedName != "$ANDROID_PKG.$R_CLASS") {
return ResourceType.getEnum(elementType.name)
}
return null
}
private fun UReferenceExpression.getAndroidResourceValue(resources: LocalResourceRepository, call: UCallExpression? = null): String? {
val resourceType = resolve()?.getAndroidResourceType() ?: return null
val referenceConfig = FolderConfiguration().apply { localeQualifier = LocaleQualifier("xx") }
val key = resolvedName ?: return null
val resourceValue = resources.getResourceValue(resourceType, key, referenceConfig) ?: return null
val text = if (call != null) formatArguments(call, resourceValue) else resourceValue
if (resourceType == ResourceType.STRING || resourceType == ResourceType.PLURALS) {
return '"' + StringUtil.shortenTextWithEllipsis(text, FOLD_MAX_LENGTH - 2, 0) + '"'
}
else if (text.length <= 1) {
// Don't just inline empty or one-character replacements: they can't be expanded by a mouse click
// so are hard to use without knowing about the folding keyboard shortcut to toggle folding.
// This is similar to how IntelliJ 14 handles call parameters
return key + ": " + text
}
return StringUtil.shortenTextWithEllipsis(text, FOLD_MAX_LENGTH, 0)
}
private tailrec fun LocalResourceRepository.getResourceValue(
type: ResourceType,
name: String,
referenceConfig: FolderConfiguration): String? {
val value = getConfiguredValue(type, name, referenceConfig)?.value ?: return null
if (!value.startsWith('@')) {
return value
}
val (referencedTypeName, referencedName) = value.substring(1).split('/').takeIf { it.size == 2 } ?: return value
val referencedType = ResourceType.getEnum(referencedTypeName) ?: return value
return getResourceValue(referencedType, referencedName, referenceConfig)
}
// Converted from com.android.tools.idea.folding.InlinedResource#insertArguments
private fun formatArguments(callExpression: UCallExpression, formatString: String): String {
if (!formatString.contains('%')) {
return formatString
}
val args = callExpression.valueArguments
if (args.isEmpty() || !args.first().isPsiValid) {
return formatString
}
val matcher = FORMAT.matcher(formatString)
var index = 0
var prevIndex = 0
var nextNumber = 1
var start = 0
val sb = StringBuilder(2 * formatString.length)
while (true) {
if (matcher.find(index)) {
if ("%" == matcher.group(6)) {
index = matcher.end()
continue
}
val matchStart = matcher.start()
// Make sure this is not an escaped '%'
while (prevIndex < matchStart) {
val c = formatString[prevIndex]
if (c == '\\') {
prevIndex++
}
prevIndex++
}
if (prevIndex > matchStart) {
// We're in an escape, ignore this result
index = prevIndex
continue
}
index = matcher.end()
// Shouldn't throw a number format exception since we've already
// matched the pattern in the regexp
val number: Int
var numberString: String? = matcher.group(1)
if (numberString != null) {
// Strip off trailing $
numberString = numberString.substring(0, numberString.length - 1)
number = Integer.parseInt(numberString)
nextNumber = number + 1
}
else {
number = nextNumber++
}
if (number > 0 && number < args.size) {
val argExpression = args[number]
var value: Any? = argExpression.evaluate()
if (value == null) {
value = args[number].asSourceString()
}
for (i in start..matchStart - 1) {
sb.append(formatString[i])
}
sb.append("{")
sb.append(value)
sb.append('}')
start = index
}
}
else {
var i = start
val n = formatString.length
while (i < n) {
sb.append(formatString[i])
i++
}
break
}
}
return sb.toString()
}
private fun getAppResources(element: PsiElement): LocalResourceRepository? = ModuleUtilCore.findModuleForPsiElement(element)?.let {
AppResourceRepository.getAppResources(it, FORCE_PROJECT_RESOURCE_LOADING)
}
}
@@ -1,78 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.inspection
import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtPsiUtil.isUnsafeCast
import org.jetbrains.kotlin.psi.psiUtil.addTypeArgument
class TypeParameterFindViewByIdInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
val compileSdk = AndroidFacet.getInstance(session.file)?.androidModuleInfo?.buildSdkVersion?.apiLevel
if (compileSdk == null || compileSdk < 26) {
return KtVisitorVoid()
}
return object : KtVisitorVoid() {
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
if (expression.calleeExpression?.text != "findViewById" || expression.typeArguments.isNotEmpty()) {
return
}
val parentCast = (expression.parent as? KtBinaryExpressionWithTypeRHS)?.takeIf { isUnsafeCast(it) } ?: return
val typeText = parentCast.right?.getTypeTextWithoutQuestionMark() ?: return
val callableDescriptor = expression.resolveToCall()?.resultingDescriptor ?: return
if (callableDescriptor.name.asString() != "findViewById" || callableDescriptor.typeParameters.size != 1) {
return
}
holder.registerProblem(
parentCast,
"Can be converted to findViewById<$typeText>(...)",
ConvertCastToFindViewByIdWithTypeParameter())
}
}
}
class ConvertCastToFindViewByIdWithTypeParameter : LocalQuickFix {
override fun getFamilyName(): String = "Convert cast to findViewById with type parameter"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val cast = descriptor.psiElement as? KtBinaryExpressionWithTypeRHS ?: return
val typeText = cast.right?.getTypeTextWithoutQuestionMark() ?: return
val call = cast.left as? KtCallExpression ?: return
val newCall = call.copy() as KtCallExpression
val typeArgument = KtPsiFactory(call).createTypeArgument(typeText)
newCall.addTypeArgument(typeArgument)
cast.replace(newCall)
}
}
companion object {
fun KtTypeReference.getTypeTextWithoutQuestionMark(): String? =
(typeElement as? KtNullableType)?.innerType?.text ?: typeElement?.text
}
}
@@ -1,147 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.navigation;
import com.android.resources.ResourceType;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlElement;
import org.jetbrains.android.dom.AndroidAttributeValue;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.dom.manifest.ManifestElementWithRequiredName;
import org.jetbrains.android.dom.resources.Attr;
import org.jetbrains.android.dom.resources.DeclareStyleable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.android.AndroidUtilKt;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// TODO: ask for extension point
// this class is mostly copied from org.jetbrains.android.AndroidGotoDeclarationHandler
public class KotlinAndroidGotoDeclarationHandler implements GotoDeclarationHandler {
@Override
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement sourceElement, int offset, Editor editor) {
KtSimpleNameExpression referenceExpression = GotoResourceHelperKt.getReferenceExpression(sourceElement);
if (referenceExpression == null) {
return null;
}
AndroidFacet facet = AndroidUtilKt.getAndroidFacetForFile(referenceExpression);
if (facet == null) {
return null;
}
AndroidResourceUtil.MyReferredResourceFieldInfo info = GotoResourceHelperKt.getInfo(referenceExpression, facet);
if (info == null) return null;
String nestedClassName = info.getClassName();
String fieldName = info.getFieldName();
List<PsiElement> resourceList = new ArrayList<PsiElement>();
if (info.isFromManifest()) {
collectManifestElements(nestedClassName, fieldName, facet, resourceList);
}
else {
ResourceManager manager = info.isSystem()
? facet.getSystemResourceManager(false)
: facet.getLocalResourceManager();
if (manager == null) {
return null;
}
manager.collectLazyResourceElements(nestedClassName, fieldName, false, referenceExpression, resourceList);
if (manager instanceof LocalResourceManager) {
LocalResourceManager lrm = (LocalResourceManager) manager;
if (nestedClassName.equals(ResourceType.ATTR.getName())) {
for (Attr attr : lrm.findAttrs(fieldName)) {
resourceList.add(attr.getName().getXmlAttributeValue());
}
}
else if (nestedClassName.equals(ResourceType.STYLEABLE.getName())) {
for (DeclareStyleable styleable : lrm.findStyleables(fieldName)) {
resourceList.add(styleable.getName().getXmlAttributeValue());
}
for (Attr styleable : lrm.findStyleableAttributesByFieldName(fieldName)) {
resourceList.add(styleable.getName().getXmlAttributeValue());
}
}
}
}
if (resourceList.size() > 1) {
// Sort to ensure the output is stable, and to prefer the base folders
Collections.sort(resourceList, AndroidResourceUtil.RESOURCE_ELEMENT_COMPARATOR);
}
return resourceList.toArray(new PsiElement[resourceList.size()]);
}
private static void collectManifestElements(
@NotNull String nestedClassName,
@NotNull String fieldName,
@NotNull AndroidFacet facet,
@NotNull List<PsiElement> result
) {
Manifest manifest = facet.getManifest();
if (manifest == null) {
return;
}
List<? extends ManifestElementWithRequiredName> list;
if ("permission".equals(nestedClassName)) {
list = manifest.getPermissions();
}
else if ("permission_group".equals(nestedClassName)) {
list = manifest.getPermissionGroups();
}
else {
return;
}
for (ManifestElementWithRequiredName domElement : list) {
AndroidAttributeValue<String> nameAttribute = domElement.getName();
String name = nameAttribute.getValue();
if (AndroidUtils.equal(name, fieldName, false)) {
XmlElement psiElement = nameAttribute.getXmlAttributeValue();
if (psiElement != null) {
result.add(psiElement);
}
}
}
}
@Override
public String getActionText(DataContext context) {
return null;
}
}
@@ -1,84 +0,0 @@
/*
* 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.android.lint
import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import com.intellij.util.PathUtil
import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
import java.io.File
abstract class AbstractKotlinLintTest : KotlinAndroidTestCase() {
override fun setUp() {
super.setUp()
AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
(myFixture as CodeInsightTestFixtureImpl).setVirtualFileFilter { false } // Allow access to tree elements.
ConfigLibraryUtil.configureKotlinRuntime(myModule)
ConfigLibraryUtil.addLibrary(myModule, "androidExtensionsRuntime", "dist/kotlinc/lib", arrayOf("android-extensions-runtime.jar"))
}
override fun tearDown() {
ConfigLibraryUtil.unConfigureKotlinRuntime(myModule)
ConfigLibraryUtil.removeLibrary(myModule, "androidExtensionsRuntime")
super.tearDown()
}
fun doTest(path: String) {
val ktFile = File(path)
val fileText = ktFile.readText()
val mainInspectionClassName = findStringWithPrefixes(fileText, "// INSPECTION_CLASS: ") ?: error("Empty class name")
val dependencies = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// DEPENDENCY: ")
val inspectionClassNames = mutableListOf(mainInspectionClassName)
for (i in 2..100) {
val className = findStringWithPrefixes(ktFile.readText(), "// INSPECTION_CLASS$i: ") ?: break
inspectionClassNames += className
}
myFixture.enableInspections(*inspectionClassNames.map { className ->
val inspectionClass = Class.forName(className)
inspectionClass.newInstance() as InspectionProfileEntry
}.toTypedArray())
val additionalResourcesDir = File(ktFile.parentFile, getTestName(true))
if (additionalResourcesDir.exists()) {
for (file in additionalResourcesDir.listFiles()) {
if (file.isFile) {
myFixture.copyFileToProject(file.absolutePath, file.name)
}
else if (file.isDirectory) {
myFixture.copyDirectoryToProject(file.absolutePath, file.name)
}
}
}
val virtualFile = myFixture.copyFileToProject(ktFile.absolutePath, "src/${PathUtil.getFileName(path)}")
myFixture.configureFromExistingVirtualFile(virtualFile)
dependencies.forEach { dependency ->
val (dependencyFile, dependencyTargetPath) = dependency.split(" -> ").map(String::trim)
myFixture.copyFileToProject("${PathUtil.getParentPath(path)}/$dependencyFile", "src/$dependencyTargetPath")
}
myFixture.checkHighlighting(true, false, true)
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.android.quickfix
import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.PathUtil
import org.jetbrains.android.inspections.klint.AndroidLintInspectionBase
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import java.io.File
abstract class AbstractAndroidLintQuickfixTest : KotlinAndroidTestCase() {
override fun setUp() {
AndroidLintInspectionBase.invalidateInspectionShortName2IssueMap()
super.setUp()
}
fun doTest(path: String) {
val fileText = FileUtil.loadFile(File(path), true)
val intentionText = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// INTENTION_TEXT: ") ?: error("Empty intention text")
val mainInspectionClassName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// INSPECTION_CLASS: ") ?: error("Empty inspection class name")
val dependency = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// DEPENDENCY: ")
val intentionAvailable = !InTextDirectivesUtils.isDirectiveDefined(fileText, "// INTENTION_NOT_AVAILABLE")
val inspection = Class.forName(mainInspectionClassName).newInstance() as InspectionProfileEntry
myFixture.enableInspections(inspection)
val sourceFile = myFixture.copyFileToProject(path, "src/${PathUtil.getFileName(path)}")
myFixture.configureFromExistingVirtualFile(sourceFile)
if (dependency != null) {
val (dependencyFile, dependencyTargetPath) = dependency.split(" -> ").map(String::trim)
myFixture.copyFileToProject("${PathUtil.getParentPath(path)}/$dependencyFile", "src/$dependencyTargetPath")
}
if (intentionAvailable) {
val intention = myFixture.getAvailableIntention(intentionText) ?: error("Failed to find intention")
myFixture.launchAction(intention)
myFixture.checkResultByFile(path + ".expected")
}
else {
assertNull("Intention should not be available", myFixture.availableIntentions.find { it.text == intentionText })
}
}
}