diff --git a/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml b/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml
index 51ec7a78ce1c..22dce1242e39 100644
--- a/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml
+++ b/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml
@@ -35,8 +35,6 @@
-
@@ -61,6 +59,7 @@
+
diff --git a/plugins/gradle/java/src/codeInsight/ConfigurationsCompletionContributor.kt b/plugins/gradle/java/src/codeInsight/ConfigurationsCompletionContributor.kt
deleted file mode 100644
index 312517f9192a..000000000000
--- a/plugins/gradle/java/src/codeInsight/ConfigurationsCompletionContributor.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2000-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 file.
-package org.jetbrains.plugins.gradle.codeInsight
-
-import com.intellij.codeInsight.completion.*
-import com.intellij.codeInsight.lookup.LookupElementBuilder
-import com.intellij.patterns.PlatformPatterns.psiElement
-import com.intellij.psi.PsiElement
-import com.intellij.util.ProcessingContext
-import icons.GradleIcons
-import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*
-import org.jetbrains.plugins.gradle.service.resolve.GradleExtensionsContributor
-import org.jetbrains.plugins.groovy.dsl.holders.NonCodeMembersHolder
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
-import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable
-import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyClosure
-import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod
-import java.lang.Double.MAX_VALUE
-
-/**
- * @author Vladislav.Soroka
- */
-class ConfigurationsCompletionContributor : AbstractGradleCompletionContributor() {
-
- class ConfigurationsCompletionProvider(val isScriptClasspath: Boolean = false) : CompletionProvider() {
-
- override fun addCompletions(params: CompletionParameters,
- context: ProcessingContext,
- result: CompletionResultSet) {
- val position = params.position
- val extensionsData = GradleExtensionsContributor.getExtensionsFor(position) ?: return
- for (configuration in extensionsData.configurations.values) {
- if (isScriptClasspath != configuration.scriptClasspath) continue
-
- val confVar = object : GrLightVariable(position.manager, configuration.name, GRADLE_API_CONFIGURATION, position) {
- override fun getNavigationElement(): PsiElement {
- val navigationElement = super.getNavigationElement()
- val description = if (isScriptClasspath && configuration.description == null) DEFAULT_SCRIPT_CLASSPATH_DESCRIPTION else configuration.description
- navigationElement.putUserData(NonCodeMembersHolder.DOCUMENTATION, description)
- return navigationElement
- }
- }
- val elementBuilder = LookupElementBuilder.create(confVar, configuration.name)
- .withIcon(GradleIcons.Gradle)
- .withTypeText("Configuration")
- result.addElement(PrioritizedLookupElement.withPriority(elementBuilder, MAX_VALUE))
- }
- }
- }
-
- init {
- extend(CompletionType.BASIC, PROJECT_DEPENDENCIES_PLACE_PATTERN, ConfigurationsCompletionProvider())
- extend(CompletionType.BASIC, SCRIPT_DEPENDENCIES_PLACE_PATTERN, ConfigurationsCompletionProvider(true))
- }
-
- companion object {
-
- private const val DEFAULT_SCRIPT_CLASSPATH_DESCRIPTION = "The script classpath configuration used to compile and execute a build script. " +
- "This classpath is also used to load the plugins which the build script uses."
-
- private val PROJECT_DEPENDENCIES_PLACE_PATTERN = psiElement()
- .and(GRADLE_FILE_PATTERN)
- .withParent(GrReferenceExpression::class.java)
- .withAncestor(4, groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, "dependencies")))
-
- private val SCRIPT_DEPENDENCIES_PLACE_PATTERN = psiElement()
- .and(GRADLE_FILE_PATTERN)
- .withParent(GrReferenceExpression::class.java)
- .withAncestor(4, groovyClosure().inMethod(psiMethod(GRADLE_API_SCRIPT_HANDLER, "dependencies")))
- }
-}
\ No newline at end of file
diff --git a/plugins/gradle/java/src/service/resolve/GradleBuildScriptContributor.kt b/plugins/gradle/java/src/service/resolve/GradleBuildScriptContributor.kt
index bddec09dcdb7..eb0a60fbaed2 100644
--- a/plugins/gradle/java/src/service/resolve/GradleBuildScriptContributor.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleBuildScriptContributor.kt
@@ -1,6 +1,7 @@
-// Copyright 2000-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 file.
+// Copyright 2000-2019 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.util.ProcessingContext
import groovy.lang.Closure
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_PROJECT
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_SCRIPT_HANDLER
@@ -16,12 +17,17 @@ import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DelegatesToInfo
*/
class GradleBuildScriptContributor : GradleMethodContextContributor {
companion object {
- val buildscriptClosure: GroovyClosurePattern = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, "buildscript"))
+ val buildscriptClosure: GroovyClosurePattern = groovyClosure().inMethod(
+ psiMethod(GRADLE_API_PROJECT, "buildscript")
+ ).inMethodResult(saveProjectType)
}
override fun getDelegatesToInfo(closure: GrClosableBlock): DelegatesToInfo? {
- if (buildscriptClosure.accepts(closure)) {
- return DelegatesToInfo(TypesUtil.createType(GRADLE_API_SCRIPT_HANDLER, closure), Closure.DELEGATE_FIRST)
+ val context = ProcessingContext()
+ if (buildscriptClosure.accepts(closure, context)) {
+ val scriptHandler = TypesUtil.createType(GRADLE_API_SCRIPT_HANDLER, closure)
+ val delegate = context.get(projectTypeKey)?.setType(scriptHandler, true) ?: scriptHandler
+ return DelegatesToInfo(delegate, Closure.DELEGATE_FIRST)
}
return null
}
diff --git a/plugins/gradle/java/src/service/resolve/GradleDependenciesContributor.kt b/plugins/gradle/java/src/service/resolve/GradleDependenciesContributor.kt
index 8e898b153241..e429003b7008 100644
--- a/plugins/gradle/java/src/service/resolve/GradleDependenciesContributor.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleDependenciesContributor.kt
@@ -1,25 +1,15 @@
// Copyright 2000-2019 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.patterns.PsiJavaPatterns.psiElement
import com.intellij.patterns.StandardPatterns.or
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiElement
-import com.intellij.psi.ResolveState
-import com.intellij.psi.scope.ElementClassHint
-import com.intellij.psi.scope.PsiScopeProcessor
+import com.intellij.util.ProcessingContext
import groovy.lang.Closure
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*
-import org.jetbrains.plugins.gradle.service.resolve.GradleResolverUtil.canBeMethodOf
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
-import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil
-import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyClosurePattern
import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyClosure
import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod
-import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DelegatesToInfo
/**
@@ -31,7 +21,7 @@ class GradleDependenciesContributor : GradleMethodContextContributor {
val dependenciesClosure: GroovyClosurePattern = groovyClosure().inMethod(or(
psiMethod(GRADLE_API_PROJECT, "dependencies"),
psiMethod(GRADLE_API_SCRIPT_HANDLER, "dependencies")
- ))
+ )).inMethodResult(saveProjectType)
val dependencyClosure: GroovyClosurePattern = groovyClosure().inMethod(psiMethod(GRADLE_API_DEPENDENCY_HANDLER, "add"))
val moduleClosure: GroovyClosurePattern = groovyClosure().inMethod(psiMethod(GRADLE_API_DEPENDENCY_HANDLER, "module"))
@@ -44,8 +34,13 @@ class GradleDependenciesContributor : GradleMethodContextContributor {
}
override fun getDelegatesToInfo(closure: GrClosableBlock): DelegatesToInfo? {
+ val context = ProcessingContext()
+ if (dependenciesClosure.accepts(closure, context)) {
+ val dependencyHandler = TypesUtil.createType(GRADLE_API_DEPENDENCY_HANDLER, closure)
+ val delegate = context.get(projectTypeKey)?.setType(dependencyHandler) ?: dependencyHandler
+ return DelegatesToInfo(delegate, Closure.DELEGATE_FIRST)
+ }
val fqn = when {
- dependenciesClosure.accepts(closure) -> GRADLE_API_DEPENDENCY_HANDLER
dependencyClosure.accepts(closure) -> GRADLE_API_ARTIFACTS_MODULE_DEPENDENCY
moduleClosure.accepts(closure) -> GRADLE_API_ARTIFACTS_CLIENT_MODULE_DEPENDENCY
componentsClosure.accepts(closure) -> GRADLE_API_COMPONENT_METADATA_HANDLER
@@ -55,30 +50,4 @@ class GradleDependenciesContributor : GradleMethodContextContributor {
}
return DelegatesToInfo(TypesUtil.createType(fqn, closure), Closure.DELEGATE_FIRST)
}
-
- override fun process(methodCallInfo: List, processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean {
- val groovyPsiManager = GroovyPsiManager.getInstance(place.project)
- val methodName = methodCallInfo.firstOrNull() ?: return true
-
- val classHint = processor.getHint(ElementClassHint.KEY)
- val shouldProcessMethods = ResolveUtil.shouldProcessMethods(classHint)
- if (shouldProcessMethods && place is GrReferenceExpression && psiElement().inside(dependenciesClosure).accepts(place)) {
- if (methodCallInfo.size == 2) {
- val resolveScope = place.getResolveScope()
- val psiClass = JavaPsiFacade.getInstance(place.project).findClass(GRADLE_API_DEPENDENCY_HANDLER, resolveScope) ?: return true
- if (canBeMethodOf(methodName, psiClass)) {
- return true
- }
-
- val returnClass = groovyPsiManager.createTypeByFQClassName(GRADLE_API_ARTIFACTS_DEPENDENCY, resolveScope)
- val wrappedBase = GrLightMethodBuilder(place.manager, methodName).apply {
- returnType = returnClass
- containingClass = psiClass
- }
- wrappedBase.addParameter("dependencyNotation", TypesUtil.getJavaLangObject(place).createArrayType())
- if (!processor.execute(wrappedBase, state)) return false
- }
- }
- return true
- }
-}
\ No newline at end of file
+}
diff --git a/plugins/gradle/java/src/service/resolve/GradleDependencyHandlerContributor.kt b/plugins/gradle/java/src/service/resolve/GradleDependencyHandlerContributor.kt
new file mode 100644
index 000000000000..faf91bf2cf04
--- /dev/null
+++ b/plugins/gradle/java/src/service/resolve/GradleDependencyHandlerContributor.kt
@@ -0,0 +1,60 @@
+// Copyright 2000-2019 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.psi.*
+import com.intellij.psi.scope.PsiScopeProcessor
+import icons.GradleIcons
+import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_DEPENDENCY_HANDLER
+import org.jetbrains.plugins.gradle.settings.GradleExtensionsSettings.GradleConfiguration
+import org.jetbrains.plugins.gradle.util.GradleBundle
+import org.jetbrains.plugins.groovy.dsl.holders.NonCodeMembersHolder
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil
+import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
+import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor
+import org.jetbrains.plugins.groovy.lang.resolve.getName
+import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods
+
+class GradleDependencyHandlerContributor : NonCodeMembersContributor() {
+
+ override fun getParentClassName(): String? = GRADLE_API_DEPENDENCY_HANDLER
+
+ override fun processDynamicElements(qualifierType: PsiType,
+ clazz: PsiClass?,
+ processor: PsiScopeProcessor,
+ place: PsiElement,
+ state: ResolveState) {
+ if (qualifierType !is GradleProjectAwareType) return
+
+ if (clazz == null) return
+ if (!processor.shouldProcessMethods()) return
+
+ val data = GradleExtensionsContributor.getExtensionsFor(place) ?: return
+ val methodName = processor.getName(state)
+ val manager = place.manager
+ val objectVarargType = PsiEllipsisType(TypesUtil.getJavaLangObject(place))
+
+ val configurations = if (methodName == null) data.configurations.values else listOf(data.configurations[methodName] ?: return)
+ for (configuration in configurations) {
+ if (configuration.scriptClasspath != qualifierType.buildscript) continue
+ val configurationName = configuration.name ?: continue
+ val method = GrLightMethodBuilder(manager, configurationName).apply {
+ methodKind = GradleArtifactHandlerContributor.ourMethodKind
+ containingClass = clazz
+ returnType = null
+ addParameter("dependencyNotation", objectVarargType)
+ setBaseIcon(GradleIcons.Gradle)
+ putUserData(NonCodeMembersHolder.DOCUMENTATION, configuration.getDescription())
+ }
+ if (!processor.execute(method, state)) return
+ }
+ }
+
+ private fun GradleConfiguration.getDescription(): String? {
+ if (description == null && scriptClasspath && name == "classpath") {
+ return GradleBundle.message("gradle.codeInsigt.buildscript.classpath.description")
+ }
+ else {
+ return description
+ }
+ }
+}
diff --git a/plugins/gradle/java/src/service/resolve/GradleProjectAwareType.kt b/plugins/gradle/java/src/service/resolve/GradleProjectAwareType.kt
index f15c25a4f5a3..b64507220e43 100644
--- a/plugins/gradle/java/src/service/resolve/GradleProjectAwareType.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleProjectAwareType.kt
@@ -8,8 +8,9 @@ import com.intellij.psi.PsiType
import com.intellij.psi.search.GlobalSearchScope
// TODO track exact project id to obtain project extension data
-class GradleProjectAwareType(
- private val delegate: PsiClassType
+class GradleProjectAwareType (
+ private val delegate: PsiClassType,
+ val buildscript: Boolean
) : PsiClassType(LanguageLevel.HIGHEST) {
override fun isValid(): Boolean = delegate.isValid
@@ -17,7 +18,7 @@ class GradleProjectAwareType(
override fun resolve(): PsiClass? = delegate.resolve()
override fun resolveGenerics(): ClassResolveResult = delegate.resolveGenerics()
override fun getParameters(): Array = delegate.parameters
- override fun rawType(): PsiClassType = GradleProjectAwareType(delegate.rawType())
+ override fun rawType(): PsiClassType = GradleProjectAwareType(delegate.rawType(), buildscript)
override fun getClassName(): String = delegate.className
override fun getCanonicalText(): String = delegate.canonicalText
@@ -27,5 +28,11 @@ class GradleProjectAwareType(
override fun getLanguageLevel(): LanguageLevel = delegate.languageLevel
override fun setLanguageLevel(languageLevel: LanguageLevel): PsiClassType = error("must not be called")
- fun setType(delegate: PsiClassType): GradleProjectAwareType = GradleProjectAwareType(delegate)
+ fun setType(delegate: PsiClassType): GradleProjectAwareType {
+ return GradleProjectAwareType(delegate, buildscript)
+ }
+
+ fun setType(delegate: PsiClassType, buildscript: Boolean): GradleProjectAwareType {
+ return GradleProjectAwareType(delegate, buildscript)
+ }
}
diff --git a/plugins/gradle/java/src/service/resolve/GradleProjectCallTypeCalculator.kt b/plugins/gradle/java/src/service/resolve/GradleProjectCallTypeCalculator.kt
index 815e17561d94..f5631956df7c 100644
--- a/plugins/gradle/java/src/service/resolve/GradleProjectCallTypeCalculator.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleProjectCallTypeCalculator.kt
@@ -14,7 +14,8 @@ class GradleProjectCallTypeCalculator : GrCallTypeCalculator {
private val methodNames = setOf(
"getProject",
"getArtifacts",
- "getTasks"
+ "getTasks",
+ "getDependencies"
)
override fun getType(receiver: PsiType?, method: PsiMethod, arguments: Arguments?, context: PsiElement): PsiType? {
diff --git a/plugins/gradle/java/src/service/resolve/GradleScriptMembersContributor.kt b/plugins/gradle/java/src/service/resolve/GradleScriptMembersContributor.kt
index 9bc09e2cf1fb..f930d7959872 100644
--- a/plugins/gradle/java/src/service/resolve/GradleScriptMembersContributor.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleScriptMembersContributor.kt
@@ -21,7 +21,7 @@ class GradleScriptMembersContributor : NonCodeMembersContributor() {
place: PsiElement,
state: ResolveState) {
if (aClass == null || !aClass.isResolvedInGradleScript()) return
- val delegate = GradleProjectAwareType(createType(GRADLE_API_PROJECT, place.containingFile))
+ val delegate = GradleProjectAwareType(createType(GRADLE_API_PROJECT, place.containingFile), false)
delegate.processReceiverType(processor, state, place)
}
}
diff --git a/plugins/gradle/java/testSources/dsl/GradleDependenciesTest.groovy b/plugins/gradle/java/testSources/dsl/GradleDependenciesTest.groovy
index e626d0c33920..167cc01eb2e1 100644
--- a/plugins/gradle/java/testSources/dsl/GradleDependenciesTest.groovy
+++ b/plugins/gradle/java/testSources/dsl/GradleDependenciesTest.groovy
@@ -16,12 +16,12 @@ class GradleDependenciesTest extends GradleHighlightingBaseTest implements Resol
@Override
protected List getParentCalls() {
- return super.getParentCalls() + 'buildscript'
+ return []
}
@Test
void dependenciesTest() {
- importProject("")
+ importProject("apply plugin: 'java'")
new RunAll().append {
'dependencies delegate'()
} append {
@@ -38,6 +38,14 @@ class GradleDependenciesTest extends GradleHighlightingBaseTest implements Resol
'modules delegate'()
} append {
'modules module delegate'()
+ } append {
+ 'classpath configuration'()
+ } append {
+ 'compile configuration'()
+ } append {
+ 'buildscript classpath configuration'()
+ } append {
+ 'buildscript compile configuration'()
} run()
}
@@ -96,4 +104,34 @@ class GradleDependenciesTest extends GradleHighlightingBaseTest implements Resol
closureDelegateTest(GRADLE_API_COMPONENT_MODULE_METADATA_DETAILS, 1)
}
}
+
+ void 'classpath configuration'() {
+ doTest('dependencies { classpath("hi") }') {
+ resolveTest(null)
+ }
+ }
+
+ void 'compile configuration'() {
+ doTest('dependencies { compile("hi") }') {
+ methodTest(resolveTest(PsiMethod), "compile", GRADLE_API_DEPENDENCY_HANDLER)
+ }
+ }
+
+ void 'compile confiduration via property'() {
+ doTest('dependencies.testCompile("hi")') {
+ methodTest(resolveTest(PsiMethod), "testCompile", GRADLE_API_DEPENDENCY_HANDLER)
+ }
+ }
+
+ void 'buildscript classpath configuration'() {
+ doTest('buildscript { dependencies { classpath("hi") } }') {
+ methodTest(resolveTest(PsiMethod), "classpath", GRADLE_API_DEPENDENCY_HANDLER)
+ }
+ }
+
+ void 'buildscript compile configuration'() {
+ doTest('buildscript { dependencies { compile("hi") } }') {
+ resolveTest(null)
+ }
+ }
}
diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties
index 0e81960856c4..e109a1fbcb58 100644
--- a/plugins/gradle/resources/i18n/GradleBundle.properties
+++ b/plugins/gradle/resources/i18n/GradleBundle.properties
@@ -46,6 +46,9 @@ gradle.codeInsight.action.apply_plugin.popup.title=Choose plugin
gradle.codeInsight.action.add_maven_dependency.text=Add Maven artifact dependency
gradle.codeInsight.action.add_maven_dependency.description=Add selected Maven artifact dependency to the project
+gradle.codeInsigt.buildscript.classpath.description=The script classpath configuration used to compile and execute a build script. \
+This classpath is also used to load the plugins which the build script uses.
+
gradle.runner=Runner
gradle.runner.toggle.tree.text.action.name=Toggle tasks executions/text mode
gradle.preferred_test_runner.CHOOSE_PER_TEST=Choose per test