gradle: misc contributor

This commit is contained in:
Vladislav.Soroka
2016-11-29 20:50:24 +03:00
parent 7639ed2a75
commit e3ecc6282a
10 changed files with 181 additions and 64 deletions
+2
View File
@@ -67,6 +67,7 @@
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleDependenciesContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleArtifactsContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleJavaContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleMiscContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleExtensionsContributor"/>
<projectResolve implementation="org.jetbrains.plugins.gradle.service.project.BaseGradleProjectResolverExtension"/>
<frameworkSupport implementation="org.jetbrains.plugins.gradle.frameworkSupport.GradleJavaFrameworkSupportProvider"/>
@@ -170,6 +171,7 @@
<importContributor implementation="org.jetbrains.plugins.gradle.config.GradleDefaultImportContributor"/>
<variableEnhancer order="first" implementation="org.jetbrains.plugins.gradle.service.resolve.GradleClosureAsAnonymousParameterEnhancer"/>
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleSettingsScriptContributor"/>
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleNonCodeMembersContributor"/>
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleScriptContributor"/>
<delegatesToProvider implementation="org.jetbrains.plugins.gradle.service.resolve.GradleDelegatesToProvider"/>
<referenceTypeEnhancer implementation="org.jetbrains.plugins.gradle.service.resolve.NamedDomainObjectCollectionTypeEnhancer"/>
@@ -31,6 +31,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethod
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.GrLightField
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter
import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyClosure
@@ -57,7 +58,8 @@ class GradleArtifactsContributor : GradleMethodContextContributor {
if (methodName != null && place is GrReferenceExpression && psiElement().inside(artifactsClosure).accepts(place)) {
val text = place.text
if (!methodCallInfo.contains(text) && place is GrReferenceExpression) {
GradleResolverUtil.addImplicitVariable(processor, state, place, JAVA_LANG_OBJECT)
val myPsi = GrLightField(text, JAVA_LANG_OBJECT, place)
processor.execute(myPsi, state)
return false
}
@@ -45,6 +45,7 @@ public final class GradleCommonClassNames {
@NonNls public static final String GRADLE_API_DISTRIBUTION_CONTAINER = "org.gradle.api.distribution.DistributionContainer";
@NonNls public static final String GRADLE_API_DISTRIBUTION = "org.gradle.api.distribution.Distribution";
@NonNls public static final String GRADLE_API_FILE_COPY_SPEC = "org.gradle.api.file.CopySpec";
@NonNls public static final String GRADLE_API_FILE_CONFIGURABLE_FILE_TREE = "org.gradle.api.file.ConfigurableFileTree";
@NonNls public static final String GRADLE_API_SCRIPT_HANDLER = "org.gradle.api.initialization.dsl.ScriptHandler";
@NonNls public static final String GRADLE_API_TASK = "org.gradle.api.Task";
@NonNls public static final String GRADLE_API_DEFAULT_TASK = "org.gradle.api.DefaultTask";
@@ -60,6 +61,8 @@ public final class GradleCommonClassNames {
@NonNls public static final String GRADLE_API_TASKS_DIAGNOSTICS_PROPERTY_REPORT_TASK = "org.gradle.api.tasks.diagnostics.PropertyReportTask";
@NonNls public static final String GRADLE_API_TASKS_DIAGNOSTICS_TASK_REPORT_TASK = "org.gradle.api.tasks.diagnostics.TaskReportTask";
@NonNls public static final String GRADLE_API_TASKS_TESTING_TEST = "org.gradle.api.tasks.testing.Test";
@NonNls public static final String GRADLE_API_JUNIT_OPTIONS = "org.gradle.api.tasks.testing.junit.JUnitOptions";
@NonNls public static final String GRADLE_API_TEST_LOGGING_CONTAINER = "org.gradle.api.tasks.testing.logging.TestLoggingContainer";
@NonNls public static final String GRADLE_API_TASKS_UPLOAD = "org.gradle.api.tasks.Upload";
@NonNls public static final String GRADLE_API_ARTIFACTS_REPOSITORIES_FLAT_DIRECTORY_ARTIFACT_REPOSITORY = "org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository";
@NonNls public static final String GRADLE_LANGUAGE_JVM_TASKS_PROCESS_RESOURCES = "org.gradle.language.jvm.tasks.ProcessResources";
@@ -66,6 +66,12 @@ class GradleIdeaPluginScriptContributor : GradleMethodContextContributor {
if (ideaImlClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(IDEA_MODULE_IML_FQN, closure), Closure.DELEGATE_FIRST)
}
if (ideaProjectClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(IDEA_PROJECT_FQN, closure), Closure.DELEGATE_FIRST)
}
if (ideaModuleClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(IDEA_MODULE_FQN, closure), Closure.DELEGATE_FIRST)
}
return null
}
@@ -86,15 +92,10 @@ class GradleIdeaPluginScriptContributor : GradleMethodContextContributor {
}
val psiManager = GroovyPsiManager.getInstance(place.project)
if (psiElement().inside(ideaModuleClosure).accepts(place)) {
if (GradleResolverUtil.processDeclarations(psiManager, processor, state, place, IDEA_MODULE_FQN)) return false
}
if (psiElement().inside(ideaProjectClosure).accepts(place)) {
if (psiElement().inside(ideaIprClosure).accepts(place)) {
if (GradleResolverUtil.processDeclarations(psiManager, processor, state, place, IDE_XML_MERGER_FQN)) return false
}
if (GradleResolverUtil.processDeclarations(psiManager, processor, state, place, IDEA_PROJECT_FQN)) return false
}
return true
@@ -0,0 +1,101 @@
/*
* 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.plugins.gradle.service.resolve
import com.intellij.patterns.PsiJavaPatterns.psiElement
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveState
import com.intellij.psi.scope.PsiScopeProcessor
import groovy.lang.Closure
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression
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.groovyClosure
import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY
import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DelegatesToInfo
/**
* @author Vladislav.Soroka
*
* @since 11/24/2016
*/
class GradleMiscContributor : GradleMethodContextContributor {
companion object {
val useJUnitClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_TASKS_TESTING_TEST, "useJUnit"))
val testLoggingClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_TASKS_TESTING_TEST, "testLogging"))
val downloadClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, "download"))
val domainCollectionWithTypeClosure = groovyClosure().inMethod(psiMethod("org.gradle.api.DomainObjectCollection", "withType"))
val downloadSpecFqn = "de.undercouch.gradle.tasks.download.DownloadSpec"
val pluginDependenciesSpecFqn = "org.gradle.plugin.use.PluginDependenciesSpec"
}
override fun getDelegatesToInfo(closure: GrClosableBlock): DelegatesToInfo? {
if (useJUnitClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(GRADLE_API_JUNIT_OPTIONS, closure), Closure.DELEGATE_FIRST)
}
if (testLoggingClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(GRADLE_API_TEST_LOGGING_CONTAINER, closure), Closure.DELEGATE_FIRST)
}
if (downloadClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(downloadSpecFqn, closure), Closure.DELEGATE_FIRST)
}
if (domainCollectionWithTypeClosure.accepts(closure)) {
val parent = closure.parent
if (parent is GrMethodCallExpression) {
val psiElement = parent.argumentList.allArguments.singleOrNull()?.reference?.resolve()
if (psiElement is PsiClass) {
return DelegatesToInfo(TypesUtil.createType(psiElement.qualifiedName, closure), Closure.DELEGATE_FIRST)
}
}
}
return null
}
override fun process(methodCallInfo: MutableList<String>, processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean {
val classHint = processor.getHint(com.intellij.psi.scope.ElementClassHint.KEY)
val shouldProcessMethods = ResolveUtil.shouldProcessMethods(classHint)
val psiManager = GroovyPsiManager.getInstance(place.project)
val resolveScope = place.resolveScope
if (shouldProcessMethods && place.parent?.parent is GroovyFile && place.text == "plugins") {
val pluginsDependenciesClass = psiManager.findClassWithCache(pluginDependenciesSpecFqn, resolveScope) ?: return true
val returnClass = psiManager.createTypeByFQClassName(pluginDependenciesSpecFqn, resolveScope) ?: return true
val methodBuilder = GrLightMethodBuilder(place.manager, "plugins").apply {
containingClass = pluginsDependenciesClass
returnType = returnClass
}
methodBuilder.addAndGetParameter("configuration", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, pluginDependenciesSpecFqn)
place.putUserData(RESOLVED_CODE, true)
if (!processor.execute(methodBuilder, state)) return false
}
if (psiElement().inside(domainCollectionWithTypeClosure).accepts(place)) {
}
return true
}
}
@@ -0,0 +1,42 @@
/*
* 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.plugins.gradle.service.resolve
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import com.intellij.psi.ResolveState
import com.intellij.psi.scope.PsiScopeProcessor
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor
/**
* @author Vladislav.Soroka
*
* @since 11/25/2016
*/
class GradleNonCodeMembersContributor : NonCodeMembersContributor() {
override fun processDynamicElements(qualifierType: PsiType,
aClass: PsiClass?,
processor: PsiScopeProcessor,
place: PsiElement,
state: ResolveState) {
if (aClass == null) return
val containingFile = place.containingFile
if (!containingFile.isGradleScript() || containingFile?.originalFile?.virtualFile == aClass.containingFile?.originalFile?.virtualFile) return
processDeclarations(aClass, processor, state, place)
}
}
@@ -19,8 +19,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveState
import com.intellij.psi.scope.PsiScopeProcessor
import groovy.lang.Closure
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_FILE_COPY_SPEC
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_PROJECT
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil
@@ -36,6 +35,7 @@ class GradleProjectContributor : GradleMethodContextContributor {
companion object {
val copySpecClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, "copy", "copySpec"))
val fileTreeClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, "fileTree"))
}
@@ -43,6 +43,9 @@ class GradleProjectContributor : GradleMethodContextContributor {
if (copySpecClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(GRADLE_API_FILE_COPY_SPEC, closure), Closure.DELEGATE_FIRST)
}
if (fileTreeClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(GRADLE_API_FILE_CONFIGURABLE_FILE_TREE, closure), Closure.DELEGATE_FIRST)
}
return null
}
@@ -60,25 +60,6 @@ public class GradleResolverUtil {
return argsCount;
}
public static void addImplicitVariable(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull GrReferenceExpressionImpl expression,
@NotNull String type) {
if (expression.getQualifier() == null && expression.getReferenceName() != null) {
PsiVariable myPsi = new GrLightField(expression.getReferenceName(), type, expression);
processor.execute(myPsi, state);
}
}
public static void addImplicitVariable(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement element,
@NotNull String type) {
PsiVariable myPsi = new GrLightField(element.getText(), type, element);
processor.execute(myPsi, state);
}
@Nullable
public static GrLightMethodBuilder createMethodWithClosure(@NotNull String name,
@Nullable String returnType,
@@ -53,13 +53,7 @@ public class GradleScriptContributor extends NonCodeMembersContributor {
@NotNull PsiScopeProcessor processor,
@NotNull PsiElement place,
@NotNull ResolveState state) {
if (!(aClass instanceof GroovyScriptClass)) {
return;
}
PsiFile file = aClass.getContainingFile();
if (file == null || !FileUtilRt.extensionEquals(file.getName(), GradleConstants.EXTENSION)
|| GradleConstants.SETTINGS_FILE_NAME.equals(file.getName())) return;
if(!UtilKt.isResolvedInGradleScript(aClass)) return;
List<String> methodInfo = ContainerUtilRt.newArrayList();
for (GrMethodCall current = PsiTreeUtil.getParentOfType(place, GrMethodCall.class);
@@ -17,10 +17,9 @@ package org.jetbrains.plugins.gradle.service.resolve
import com.intellij.openapi.util.Key
import com.intellij.psi.*
import com.intellij.psi.scope.BaseScopeProcessor
import com.intellij.psi.scope.ElementClassHint
import com.intellij.psi.scope.NameHint.KEY
import com.intellij.psi.scope.PsiScopeProcessor
import org.jetbrains.plugins.gradle.util.GradleConstants.EXTENSION
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyPatterns
import java.util.*
@@ -28,51 +27,40 @@ import java.util.*
* @author Vladislav.Soroka
* @since 11/11/2016
*/
internal fun PsiClass?.isResolvedInGradleScript() = this is GroovyScriptClass && this.containingFile.isGradleScript()
internal fun PsiFile?.isGradleScript() = this?.originalFile?.virtualFile?.extension == EXTENSION
@JvmField val RESOLVED_CODE = Key.create<Boolean?>("gradle.resolved")
fun processDeclarations(handlerClass: PsiClass,
fun processDeclarations(aClass: PsiClass,
processor: PsiScopeProcessor,
state: ResolveState,
place: PsiElement): Boolean {
val name = processor.getHint(KEY)?.getName(state)
val componentClass = handlerClass
val componentProcessor = ComponentProcessor(processor, place, name)
val name = processor.getHint(com.intellij.psi.scope.NameHint.KEY)?.getName(state)
if (name == null) {
if (!componentClass.processDeclarations(componentProcessor, state, null, place)) return false
aClass.processDeclarations(processor, state, null, place)
}
else {
val isSetterCandidate = name.startsWith("set")
val processedSignatures = HashSet<List<String>>()
for (method in componentClass.findMethodsByName(name, true)) {
processedSignatures.add(method.getSignature(PsiSubstitutor.EMPTY).parameterTypes.map({ it.canonicalText }))
for (method in aClass.findMethodsByName(name, true)) {
if (!isSetterCandidate) {
processedSignatures.add(method.getSignature(PsiSubstitutor.EMPTY).parameterTypes.map({ it.canonicalText }))
}
place.putUserData(RESOLVED_CODE, true)
if (!componentProcessor.execute(method, state)) return false
if (!processor.execute(method, state)) return false
}
for (prefix in arrayOf("add", "set")) {
for (method in componentClass.findMethodsByName(prefix + name.capitalize(), true)) {
if (!isSetterCandidate) {
for (method in aClass.findMethodsByName("set" + name.capitalize(), true)) {
if (processedSignatures.contains(method.getSignature(PsiSubstitutor.EMPTY).parameterTypes.map({ it.canonicalText }))) continue
place.putUserData(RESOLVED_CODE, true)
if (!componentProcessor.execute(method, state)) return false
if (!processor.execute(method, state)) return false
}
}
}
return true
}
class ComponentProcessor(val delegate: PsiScopeProcessor, val place: PsiElement, val name: String?) : BaseScopeProcessor() {
override fun execute(method: PsiElement, state: ResolveState): Boolean {
method as? PsiMethod ?: return true
return delegate.execute(method, state)
}
override fun <T : Any?> getHint(hintKey: Key<T>): T? = if (hintKey == com.intellij.psi.scope.ElementClassHint.KEY) {
@Suppress("UNCHECKED_CAST")
ElementClassHint { it == com.intellij.psi.scope.ElementClassHint.DeclarationKind.METHOD } as T
}
else {
null
}
}
fun psiMethodInClass(containingClass: String) = GroovyPatterns.psiMethod().definedInClass(containingClass)