mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[gradle] IDEA-171199 IDEA-197590 absolute project references in project("...")
GitOrigin-RevId: 37e62b43c880f5d5dc7b91624a819dba6e9fa0ef
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6a8055fb0f
commit
30c4bfb9ff
@@ -47,6 +47,14 @@
|
||||
implementationClass="org.jetbrains.plugins.gradle.execution.GradleGroovyRunLineMarkerProvider"/>
|
||||
|
||||
<fileTypeUsageSchemaDescriptor schema="Gradle" implementationClass="org.jetbrains.plugins.gradle.config.GradleScriptTypeDetector"/>
|
||||
<psi.symbolReferenceProvider hostLanguage="Groovy"
|
||||
hostElementClass="org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral"
|
||||
targetClass="org.jetbrains.plugins.gradle.service.resolve.GradleProjectSymbol"
|
||||
implementationClass="org.jetbrains.plugins.gradle.service.resolve.GradleProjectReferenceProvider"/>
|
||||
<searcher forClass="com.intellij.model.search.PsiSymbolReferenceSearchParameters"
|
||||
implementationClass="org.jetbrains.plugins.gradle.service.resolve.GradleProjectReferenceSearcher"/>
|
||||
<lang.symbolTextSearcher forClass="org.jetbrains.plugins.gradle.service.resolve.GradleProjectSymbol"
|
||||
implementationClass="org.jetbrains.plugins.gradle.service.resolve.GradleProjectTextSearcher"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.intellij.groovy">
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.gradle.service.resolve
|
||||
|
||||
import com.intellij.model.SingleTargetReference
|
||||
import com.intellij.model.Symbol
|
||||
import com.intellij.model.psi.PsiCompletableReference
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.plugins.gradle.settings.GradleExtensionsSettings
|
||||
import org.jetbrains.plugins.gradle.settings.GradleExtensionsSettings.GradleProject
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral
|
||||
|
||||
@Internal
|
||||
class GradleProjectReference(
|
||||
private val literal: GrLiteral,
|
||||
private val range: TextRange,
|
||||
private val projectPath: List<String>
|
||||
) : SingleTargetReference(), PsiCompletableReference {
|
||||
|
||||
init {
|
||||
require(projectPath.isNotEmpty())
|
||||
}
|
||||
|
||||
private val projectPathString = projectPath.joinToString(":")
|
||||
|
||||
override fun getElement(): PsiElement = literal
|
||||
|
||||
override fun getRangeInElement(): TextRange = range
|
||||
|
||||
override fun resolveSingleTarget(): Symbol? {
|
||||
val gradleProject = GradleExtensionsSettings.getRootProject(literal) ?: return null
|
||||
if (projectPathString in gradleProject.extensions) {
|
||||
return GradleProjectSymbol(projectPath)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be much easier if we could query list of sub-projects by project fqn.
|
||||
*/
|
||||
override fun getCompletionVariants(): Collection<Any> {
|
||||
val gradleProject: GradleProject = GradleExtensionsSettings.getRootProject(literal) ?: return emptyList()
|
||||
val allProjectFqns: Set<String> = gradleProject.extensions.keys
|
||||
val parentProjectFqn: List<String> = projectPath // ["com", "IntellijIdeaRulezzz"]
|
||||
.run { take(size - 1) } // ["com"]
|
||||
val parentProjectPrefix: String = parentProjectFqn.joinToString("") { "$it:" } // "com:"
|
||||
val result = LinkedHashSet<String>()
|
||||
for (projectFqn in allProjectFqns) { // "com:foo:bar"
|
||||
if (!projectFqn.startsWith(parentProjectPrefix)) {
|
||||
continue
|
||||
}
|
||||
val relativeFqn = projectFqn.removePrefix(parentProjectPrefix) // "foo:bar"
|
||||
val childProjectName = relativeFqn.split(':').firstOrNull() // "foo"
|
||||
if (childProjectName.isNullOrEmpty()) {
|
||||
continue
|
||||
}
|
||||
result += childProjectName
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.gradle.service.resolve
|
||||
|
||||
import com.intellij.model.Symbol
|
||||
import com.intellij.model.psi.PsiExternalReferenceHost
|
||||
import com.intellij.model.psi.PsiSymbolReference
|
||||
import com.intellij.model.psi.PsiSymbolReferenceHints
|
||||
import com.intellij.model.psi.PsiSymbolReferenceProvider
|
||||
import com.intellij.model.search.SearchRequest
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.ElementManipulators
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral
|
||||
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyMethodCallPattern
|
||||
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyPatterns
|
||||
import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyElement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod
|
||||
|
||||
@Internal
|
||||
class GradleProjectReferenceProvider : PsiSymbolReferenceProvider {
|
||||
|
||||
private val myPattern = GroovyPatterns.stringLiteral().withParent(
|
||||
groovyElement<GrArgumentList>().withParent(
|
||||
GroovyMethodCallPattern.resolvesTo(psiMethod(GradleCommonClassNames.GRADLE_API_PROJECT, "project"))
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* Handled by [GradleProjectReferenceSearcher].
|
||||
*/
|
||||
override fun getSearchRequests(project: Project, target: Symbol): Collection<SearchRequest> = emptyList()
|
||||
|
||||
override fun getReferences(element: PsiExternalReferenceHost, hints: PsiSymbolReferenceHints): Collection<PsiSymbolReference> {
|
||||
if (element !is GrLiteral || !myPattern.accepts(element)) {
|
||||
return emptyList()
|
||||
}
|
||||
val escaper = element.createLiteralTextEscaper()
|
||||
val manipulator = ElementManipulators.getManipulator(element)
|
||||
val value = StringBuilder()
|
||||
val rangeInHost = manipulator.getRangeInElement(element)
|
||||
if (!escaper.decode(rangeInHost, value)) {
|
||||
return emptyList()
|
||||
}
|
||||
if (!value.startsWith(":")) {
|
||||
return emptyList()
|
||||
}
|
||||
val path = value.split(":")
|
||||
val result = SmartList<PsiSymbolReference>()
|
||||
val subPath = ArrayList<String>()
|
||||
var currentOffsetInPath = 0
|
||||
for (part in path) {
|
||||
subPath.add(part)
|
||||
val partStart = escaper.getOffsetInHost(currentOffsetInPath, rangeInHost)
|
||||
currentOffsetInPath += part.length
|
||||
val partEnd = escaper.getOffsetInHost(currentOffsetInPath, rangeInHost)
|
||||
currentOffsetInPath += 1 // ":"
|
||||
if (partStart < 0 || partEnd < 0) {
|
||||
continue
|
||||
}
|
||||
result += GradleProjectReference(element, TextRange(partStart, partEnd), ArrayList(subPath))
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.gradle.service.resolve
|
||||
|
||||
import com.intellij.model.psi.PsiSymbolReference
|
||||
import com.intellij.model.search.PsiSymbolReferenceSearchParameters
|
||||
import com.intellij.model.search.PsiSymbolReferenceSearcher
|
||||
import com.intellij.model.search.SearchContext
|
||||
import com.intellij.model.search.SearchService
|
||||
import com.intellij.model.search.impl.ExternalReferenceMapper
|
||||
import com.intellij.util.Query
|
||||
import org.jetbrains.plugins.groovy.GroovyLanguage
|
||||
|
||||
class GradleProjectReferenceSearcher : PsiSymbolReferenceSearcher {
|
||||
|
||||
override fun collectSearchRequests(parameters: PsiSymbolReferenceSearchParameters): Collection<Query<out PsiSymbolReference>> {
|
||||
val projectSymbol = parameters.symbol as? GradleProjectSymbol ?: return emptyList()
|
||||
val projectName = projectSymbol.projectName.takeIf(String::isNotEmpty) ?: return emptyList()
|
||||
val query = SearchService.getInstance()
|
||||
.searchWord(parameters.project, projectName)
|
||||
.inScope(parameters.searchScope)
|
||||
.inFilesWithLanguage(GroovyLanguage)
|
||||
.inContexts(SearchContext.IN_STRINGS)
|
||||
.buildQuery(ExternalReferenceMapper(projectSymbol.createPointer()))
|
||||
return listOf(query)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.gradle.service.resolve
|
||||
|
||||
import com.intellij.model.Pointer
|
||||
import com.intellij.model.presentation.PresentableSymbol
|
||||
import com.intellij.model.presentation.SymbolPresentation
|
||||
import icons.GradleIcons
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle
|
||||
import javax.swing.Icon
|
||||
|
||||
@Internal
|
||||
class GradleProjectSymbol(private val myQualifiedName: List<String>) : PresentableSymbol {
|
||||
|
||||
init {
|
||||
require(myQualifiedName.isNotEmpty())
|
||||
}
|
||||
|
||||
override fun createPointer(): Pointer<GradleProjectSymbol> = Pointer.hardPointer(this)
|
||||
|
||||
val projectName: String get() = myQualifiedName.last()
|
||||
val qualifiedName: String get() = myQualifiedName.joinToString(separator = ":")
|
||||
|
||||
private val myPresentation = object : SymbolPresentation {
|
||||
override fun getIcon(): Icon? = GradleIcons.Gradle
|
||||
override fun getShortNameString(): String = projectName
|
||||
override fun getShortDescription(): String = GradleBundle.message("gradle.project.0", projectName)
|
||||
override fun getLongDescription(): String = GradleBundle.message("gradle.project.0", qualifiedName)
|
||||
}
|
||||
|
||||
override fun getSymbolPresentation(): SymbolPresentation = myPresentation
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GradleProjectSymbol
|
||||
|
||||
if (myQualifiedName != other.myQualifiedName) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return myQualifiedName.hashCode()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.gradle.service.resolve
|
||||
|
||||
import com.intellij.find.usages.SymbolTextSearcher
|
||||
|
||||
class GradleProjectTextSearcher : SymbolTextSearcher<GradleProjectSymbol> {
|
||||
|
||||
override fun getStringsToSearch(symbol: GradleProjectSymbol): Collection<String> = listOf(symbol.qualifiedName)
|
||||
}
|
||||
@@ -165,3 +165,4 @@ compiler.build.messages.gradle.configuration.not.found=Unable to make ''{0}''.\n
|
||||
|
||||
gradle.project.generation.wrapper.progress.title=Generating Gradle Wrapper
|
||||
gradle.commandline.description=Configures Gradle projects under the given folder
|
||||
gradle.project.0=Gradle project ''{0}''
|
||||
+23
-3
@@ -12,10 +12,14 @@ import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.CommonClassNames;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter;
|
||||
@@ -188,14 +192,20 @@ public class GradleExtensionsSettings {
|
||||
*/
|
||||
@Nullable
|
||||
public GradleExtensionsData getExtensionsFor(@Nullable String rootProjectPath, @Nullable String gradlePath) {
|
||||
if (rootProjectPath == null || gradlePath == null) return null;
|
||||
GradleProject gradleProject = projects.get(rootProjectPath);
|
||||
GradleProject gradleProject = getRootGradleProject(rootProjectPath);
|
||||
if (gradleProject == null) return null;
|
||||
return gradleProject.extensions.get(gradlePath);
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public GradleProject getRootGradleProject(@Nullable String rootProjectPath) {
|
||||
if (rootProjectPath == null) return null;
|
||||
return projects.get(rootProjectPath);
|
||||
}
|
||||
}
|
||||
|
||||
static class GradleProject {
|
||||
public static class GradleProject {
|
||||
public Map<String, GradleExtensionsData> extensions = new HashMap<>();
|
||||
}
|
||||
|
||||
@@ -219,6 +229,7 @@ public class GradleExtensionsSettings {
|
||||
public final Map<String, GradleConfiguration> configurations = new HashMap<>();
|
||||
@NotNull
|
||||
public final Map<String, GradleConfiguration> buildScriptConfigurations = new HashMap<>();
|
||||
|
||||
@Nullable
|
||||
public GradleExtensionsData getParent() {
|
||||
if (myGradleProject == null) return null;
|
||||
@@ -315,4 +326,13 @@ public class GradleExtensionsSettings {
|
||||
public boolean scriptClasspath;
|
||||
public String description;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GradleProject getRootProject(@NotNull PsiElement element) {
|
||||
final PsiFile containingFile = element.getContainingFile().getOriginalFile();
|
||||
final Project project = containingFile.getProject();
|
||||
final Module module = ModuleUtilCore.findModuleForFile(containingFile);
|
||||
final String rootProjectPath = ExternalSystemApiUtil.getExternalRootProjectPath(module);
|
||||
return getInstance(project).getRootGradleProject(rootProjectPath);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user