gradle: tasks resolve updated

This commit is contained in:
Vladislav.Soroka
2016-11-29 20:50:24 +03:00
parent 52ac9083f4
commit 7639ed2a75
12 changed files with 235 additions and 448 deletions
-1
View File
@@ -59,7 +59,6 @@
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleProjectContributor"/>
<!--<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleTaskContributor"/>-->
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleConfigurationsContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleBuildScriptContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleDistributionsContributor"/>
@@ -286,7 +286,12 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
GradleExtensions gradleExtensions = resolverCtx.getExtraProject(gradleModule, GradleExtensions.class);
if (gradleExtensions != null) {
ideModule.createChild(GradleExtensionsDataService.KEY, new DefaultGradleExtensions(gradleExtensions));
DefaultGradleExtensions extensions = new DefaultGradleExtensions(gradleExtensions);
ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
if (externalProject != null) {
extensions.getTasks().addAll(externalProject.getTasks().values());
}
ideModule.createChild(GradleExtensionsDataService.KEY, extensions);
}
}
@@ -19,7 +19,10 @@ import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.util.Ref
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PatternCondition
import com.intellij.patterns.PsiJavaPatterns.psiElement
import com.intellij.psi.CommonClassNames.JAVA_LANG_STRING
import com.intellij.psi.CommonClassNames.JAVA_UTIL_MAP
import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveState
import com.intellij.psi.scope.ElementClassHint
@@ -27,17 +30,19 @@ import com.intellij.psi.scope.NameHint
import com.intellij.psi.scope.PsiScopeProcessor
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.*
import org.jetbrains.plugins.gradle.settings.GradleExtensionsSettings
import org.jetbrains.plugins.groovy.dsl.holders.NonCodeMembersHolder.DOCUMENTATION
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.COMPOSITE_LSHIFT_SIGN
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*
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.statements.expressions.path.GrMethodCallExpressionImpl
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyPatterns.groovyBinaryExpression
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
@@ -82,7 +87,7 @@ class GradleExtensionsContributor : GradleMethodContextContributor {
processor: PsiScopeProcessor,
state: ResolveState,
place: PsiElement): Boolean {
val extensionsData = Companion.getExtensionsFor(place) ?: return true
val extensionsData = getExtensionsFor(place) ?: return true
val classHint = processor.getHint(ElementClassHint.KEY)
val shouldProcessMethods = ResolveUtil.shouldProcessMethods(classHint)
val shouldProcessProperties = ResolveUtil.shouldProcessProperties(classHint)
@@ -90,8 +95,136 @@ class GradleExtensionsContributor : GradleMethodContextContributor {
val resolveScope = place.resolveScope
val projectClass = psiManager.findClassWithCache(GRADLE_API_PROJECT, resolveScope) ?: return true
val name = processor.getHint(NameHint.KEY)?.getName(state)
if (!shouldProcessMethods && shouldProcessProperties && place is GrReferenceExpression) {
if (!place.isQualified) {
if (psiElement().inside(closureInLeftShiftMethod).accepts(place)) {
if (!GradleResolverUtil.processDeclarations(psiManager, processor, state, place, GRADLE_API_DEFAULT_TASK)) {
return false
}
}
if (place.text == "task" && place is GrReferenceExpression && place.parent is GrApplicationStatement) {
if (GradleResolverUtil.isLShiftElement(place.parent?.children?.getOrNull(1)?.firstChild)) {
val taskContainerClass = psiManager.findClassWithCache(GRADLE_API_TASK_CONTAINER, resolveScope) ?: return true
val returnClass = psiManager.createTypeByFQClassName(GRADLE_API_TASK, resolveScope) ?: return true
val methodBuilder = GrLightMethodBuilder(place.manager, "create").apply {
containingClass = taskContainerClass
returnType = returnClass
}
methodBuilder.addParameter("task", GRADLE_API_TASK, true)
place.putUserData(RESOLVED_CODE, true)
if (!processor.execute(methodBuilder, state)) return false
}
}
for (extension in extensionsData.extensions) {
if (!shouldProcessMethods && shouldProcessProperties && name == extension.name) {
val variable = GrLightVariable(place.manager, name, extension.rootTypeFqn, place)
place.putUserData(RESOLVED_CODE, true)
if (!processor.execute(variable, state)) return false
}
if (shouldProcessMethods && name == extension.name) {
val returnClass = psiManager.createTypeByFQClassName(extension.rootTypeFqn, resolveScope) ?: continue
val methodBuilder = GrLightMethodBuilder(place.manager, extension.name).apply {
containingClass = projectClass
returnType = returnClass
}
methodBuilder.addParameter("configuration", GROOVY_LANG_CLOSURE, true)
place.putUserData(RESOLVED_CODE, true)
if (!processor.execute(methodBuilder, state)) return false
}
val objectTypeFqn = extension.namedObjectTypeFqn?.let { if (it.isNotBlank()) it else null }
val extensionClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, extension.name))
val placeText = place.text
val psiElement = psiElement()
if (psiElement.inside(extensionClosure).accepts(place)) {
if (shouldProcessMethods && !GradleResolverUtil.processDeclarations(psiManager, processor, state, place, extension.rootTypeFqn)) {
return false
}
if (objectTypeFqn == null) break
if (place.parent is GrMethodCallExpression) {
val methodBuilder = GradleResolverUtil.createMethodWithClosure(placeText, objectTypeFqn, null, place, psiManager)
if (methodBuilder != null) {
place.putUserData(RESOLVED_CODE, true)
if (!processor.execute(methodBuilder, state)) return false
}
}
if (place.parent is GrReferenceExpression || psiElement.withTreeParent(extensionClosure).accepts(place)) {
val variable = GrLightVariable(place.manager, placeText, objectTypeFqn, place)
place.putUserData(RESOLVED_CODE, true)
if (!processor.execute(variable, state)) return false
}
}
if (name == extension.name) break
}
if (place.getUserData(RESOLVED_CODE).let { it == null || !it }) {
if (psiElement().withAncestor(2, groovyClosure().with(object : PatternCondition<GrClosableBlock?>("withDelegatesToInfo") {
override fun accepts(t: GrClosableBlock, context: ProcessingContext?): Boolean {
return getDelegatesToInfo(t) != null
}
})).accepts(place)) {
return true
}
var isTaskDeclaration = false
val parent = place.parent
val superParent = parent?.parent
if (superParent is GrCommandArgumentList && superParent.parent?.firstChild?.text == "task") {
isTaskDeclaration = true
}
for (gradleTask in extensionsData.tasks) {
if (shouldProcessMethods && name == gradleTask.name) {
val returnClass = psiManager.createTypeByFQClassName(
if (isTaskDeclaration) JAVA_LANG_STRING else gradleTask.typeFqn, resolveScope) ?: continue
val methodBuilder = GrLightMethodBuilder(place.manager, gradleTask.name).apply {
containingClass = projectClass
returnType = returnClass
if (parent is GrMethodCallExpressionImpl && parent.argumentList.namedArguments.isNotEmpty()) {
addParameter("args", JAVA_UTIL_MAP, true)
}
addParameter("configuration", GROOVY_LANG_CLOSURE, true)
}
if (!processor.execute(methodBuilder, state)) return false
break
}
val taskClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, gradleTask.name))
val psiElement = psiElement()
if (psiElement.inside(taskClosure).accepts(place)) {
if (shouldProcessMethods && !GradleResolverUtil.processDeclarations(psiManager, processor, state, place, gradleTask.typeFqn)) {
place.putUserData(RESOLVED_CODE, null)
return false
}
else {
place.putUserData(RESOLVED_CODE, null)
}
}
}
if (!shouldProcessMethods && shouldProcessProperties && place is GrReferenceExpression && !place.isQualified) {
for (gradleTask in extensionsData.tasks) {
if (name == gradleTask.name) {
val docRef = Ref.create<String>()
val variable = object : GrLightVariable(place.manager, name, gradleTask.typeFqn, place) {
override fun getNavigationElement(): PsiElement {
val navigationElement = super.getNavigationElement()
navigationElement.putUserData(DOCUMENTATION, docRef.get())
return navigationElement
}
}
val doc = getDocumentation(gradleTask, variable)
docRef.set(doc)
place.putUserData(DOCUMENTATION, doc)
if (!processor.execute(variable, state)) return false
break
}
}
for (gradleProp in extensionsData.properties) {
if (name == gradleProp.name) {
val docRef = Ref.create<String>()
@@ -106,50 +239,12 @@ class GradleExtensionsContributor : GradleMethodContextContributor {
docRef.set(doc)
place.putUserData(DOCUMENTATION, doc)
if (!processor.execute(variable, state)) return false
break
}
}
}
}
for (extension in extensionsData.extensions) {
if (!shouldProcessMethods && shouldProcessProperties && name == extension.name) {
val variable = GrLightVariable(place.manager, name, extension.rootTypeFqn, place)
if (!processor.execute(variable, state)) return false
}
if (shouldProcessMethods && name == extension.name) {
val returnClass = psiManager.createTypeByFQClassName(extension.rootTypeFqn, resolveScope) ?: continue
val methodBuilder = GrLightMethodBuilder(place.manager, extension.name).apply {
containingClass = projectClass
returnType = returnClass
}
methodBuilder.addParameter("configuration", GROOVY_LANG_CLOSURE, true)
if (!processor.execute(methodBuilder, state)) return false
}
val objectTypeFqn = extension.namedObjectTypeFqn?.let { if (it.isNotBlank()) it else null }
val extensionClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, extension.name))
val placeText = place.text
val psiElement = psiElement()
if (psiElement.inside(extensionClosure).accepts(place)) {
if (shouldProcessMethods && !GradleResolverUtil.processDeclarations(psiManager, processor, state, place, extension.rootTypeFqn)) {
return false
}
if(objectTypeFqn == null) continue
if (place.parent is GrMethodCallExpression) {
val methodBuilder = GradleResolverUtil.createMethodWithClosure(placeText, objectTypeFqn, null, place, psiManager)
if (methodBuilder != null) {
if (!processor.execute(methodBuilder, state)) return false
}
}
if (place.parent is GrReferenceExpression || psiElement.withTreeParent(extensionClosure).accepts(place)) {
val variable = GrLightVariable(place.manager, placeText, objectTypeFqn, place)
if (!processor.execute(variable, state)) return false
}
}
}
return true
}
@@ -164,6 +259,13 @@ class GradleExtensionsContributor : GradleMethodContextContributor {
buffer.append(" = " + gradleProp.value)
}
buffer.append("</PRE>")
if (gradleProp is GradleExtensionsSettings.GradleTask) {
if (!gradleProp.description.isNullOrBlank()) {
buffer.append(gradleProp.description)
}
}
if (hasInitializer) {
buffer.append("<b>Initial value has been got during last import</b>")
}
@@ -171,6 +273,13 @@ class GradleExtensionsContributor : GradleMethodContextContributor {
}
companion object {
val closureInLeftShiftMethod = groovyClosure().withTreeParent(
groovyBinaryExpression().with(object : PatternCondition<GrBinaryExpression?>("leftShiftCondition") {
override fun accepts(t: GrBinaryExpression, context: ProcessingContext?): Boolean {
return t.operationTokenType == COMPOSITE_LSHIFT_SIGN
}
}))
fun getExtensionsFor(psiElement: PsiElement): GradleExtensionsSettings.GradleExtensionsData? {
val project = psiElement.project
val virtualFile = psiElement.containingFile?.originalFile?.virtualFile ?: return null
@@ -1,242 +0,0 @@
/*
* Copyright 2000-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.plugins.gradle.service.resolve;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.util.Couple;
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.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.settings.GradleLocalSettings;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
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.util.GroovyPropertyUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static com.intellij.util.containers.ContainerUtil.*;
import static org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*;
import static org.jetbrains.plugins.gradle.service.resolve.GradleResolverUtil.canBeMethodOf;
/**
* @author Vladislav.Soroka
* @since 9/24/13
*/
public class GradleImplicitContributor implements GradleMethodContextContributor {
private final static Map<String, String> BUILT_IN_TASKS = newHashMap(
Couple.of("assemble", GRADLE_API_DEFAULT_TASK),
Couple.of("build", GRADLE_API_DEFAULT_TASK),
Couple.of("buildDependents", GRADLE_API_DEFAULT_TASK),
Couple.of("buildNeeded", GRADLE_API_DEFAULT_TASK),
Couple.of("clean", GRADLE_API_TASKS_DELETE),
Couple.of("jar", GRADLE_API_TASKS_BUNDLING_JAR),
Couple.of("war", GRADLE_API_TASKS_BUNDLING_WAR),
Couple.of("classes", GRADLE_API_DEFAULT_TASK),
Couple.of("compileJava", GRADLE_API_TASKS_COMPILE_JAVA_COMPILE),
Couple.of("compileTestJava", GRADLE_API_DEFAULT_TASK),
Couple.of("processTestResources", GRADLE_API_DEFAULT_TASK),
Couple.of("testClasses", GRADLE_API_DEFAULT_TASK),
Couple.of("processResources", GRADLE_LANGUAGE_JVM_TASKS_PROCESS_RESOURCES),
Couple.of("setupBuild", GRADLE_BUILDSETUP_TASKS_SETUP_BUILD),
Couple.of("wrapper", GRADLE_API_TASKS_WRAPPER_WRAPPER),
Couple.of("javadoc", GRADLE_API_TASKS_JAVADOC_JAVADOC),
Couple.of("dependencies", GRADLE_API_TASKS_DIAGNOSTICS_DEPENDENCY_REPORT_TASK),
Couple.of("dependencyInsight", GRADLE_API_TASKS_DIAGNOSTICS_DEPENDENCY_INSIGHT_REPORT_TASK),
Couple.of("projects", GRADLE_API_TASKS_DIAGNOSTICS_PROJECT_REPORT_TASK),
Couple.of("properties", GRADLE_API_TASKS_DIAGNOSTICS_PROPERTY_REPORT_TASK),
Couple.of("tasks", GRADLE_API_TASKS_DIAGNOSTICS_TASK_REPORT_TASK),
Couple.of("check", GRADLE_API_DEFAULT_TASK),
Couple.of("test", GRADLE_API_TASKS_TESTING_TEST),
Couple.of("uploadArchives", GRADLE_API_TASKS_UPLOAD)
);
@Override
public boolean process(@NotNull List<String> methodCallInfo,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
//Module module = ProjectFileIndex.SERVICE.getInstance(place.getProject()).getModuleForFile(place.getContainingFile().getVirtualFile());
//String rootProjectPath = ExternalSystemApiUtil.getExternalRootProjectPath(module);
//if (rootProjectPath != null) {
// ExternalProject externalProject = ExternalProjectDataCache.getInstance(place.getProject())
// .getRootExternalProject(GradleConstants.SYSTEM_ID, new File(rootProjectPath));
// if (externalProject != null) {
// Map<String, ExternalProperty> properties = externalProject.getProperties();
//
// if (true || ResolveUtil.shouldProcessProperties(processor.getHint(ElementClassHint.KEY))) {
// String placeText = place.getText();
// ExternalProperty externalProperty = properties.get(placeText);
// if (externalProperty != null) {
// String type = externalProperty.getType() == null ? CommonClassNames.JAVA_LANG_OBJECT : externalProperty.getType();
// //String name = processor.getHint(NameHint.KEY).getName(state);
// LightVariableBuilder variable =
// new LightVariableBuilder(place.getManager(), placeText, TypesUtil.createType(type, place),
// GroovyLanguage.INSTANCE);
// if (!processor.execute(variable, state)) return;
// //if (((String)name).let {it == null || it == "hostname" }) {
// //val variable = LightVariableBuilder<LightVariableBuilder<*>>(
// // place.manager, "hostname", TypesUtil.createType(JAVA_LANG_STRING, place), GroovyLanguage)
// //if (!processor.execute(variable, state)) return
// //}
// }
// }
// }
//}
if (true) return true;
if (methodCallInfo.isEmpty()) {
checkForAvailableTasks(0, place.getText(), processor, state, place);
return true;
}
final String methodCall = getLastItem(methodCallInfo);
if (methodCall == null) return true;
if (!methodCall.equals("task")) {
if (methodCallInfo.size() == 1) {
checkForAvailableTasks(1, place.getText(), processor, state, place);
}
if (methodCallInfo.size() == 2) {
processAvailableTasks(methodCallInfo, methodCall, processor, state, place);
}
}
if (methodCallInfo.size() >= 3 && Arrays.equals(
ar("dirs", "flatDir", "repositories"), methodCallInfo.subList(0, 3).toArray())) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(
psiManager, processor, state, place, GRADLE_API_ARTIFACTS_REPOSITORIES_FLAT_DIRECTORY_ARTIFACT_REPOSITORY);
}
if (methodCallInfo.size() == 3) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
if ("manifest".equals(methodCallInfo.get(1)) && "jar".equals(methodCallInfo.get(2))) {
GradleResolverUtil.processDeclarations(
psiManager, processor, state, place, GRADLE_API_JAVA_ARCHIVES_MANIFEST);
}
}
if (place instanceof GrExpression && GradleResolverUtil.getTypeOf((GrExpression)place) == null) {
GrClosableBlock closableBlock = GradleResolverUtil.findParent(place, GrClosableBlock.class);
if (closableBlock != null && closableBlock.getParent() instanceof GrMethodCallExpression) {
PsiType psiType = GradleResolverUtil.getTypeOf(((GrExpression)closableBlock.getParent()));
if (psiType != null) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(
psiManager, processor, state, place, TypesUtil.getQualifiedName(psiType));
}
}
}
return true;
}
public static void processImplicitDeclarations(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
if (!place.getText().equals("resources")) {
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(psiManager, processor, state, place, GRADLE_API_PROJECT);
}
}
private static void checkForAvailableTasks(int level,
@Nullable String taskName,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
if (taskName == null) return;
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
PsiClass gradleApiProjectClass = psiManager.findClassWithCache(GRADLE_API_PROJECT, place.getResolveScope());
if (canBeMethodOf(taskName, gradleApiProjectClass)) return;
if (canBeMethodOf(GroovyPropertyUtils.getGetterNameNonBoolean(taskName), gradleApiProjectClass)) return;
final String className = BUILT_IN_TASKS.get(taskName);
if (className != null) {
if (level <= 1) {
GradleResolverUtil.addImplicitVariable(processor, state, place, className);
}
processTask(taskName, className, psiManager, processor, state, place);
return;
}
Module module = ModuleUtilCore.findModuleForPsiElement(place);
if (module == null) return;
String path = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY);
GradleLocalSettings localSettings = GradleLocalSettings.getInstance(place.getProject());
Collection<ExternalTaskPojo> taskPojos = localSettings.getAvailableTasks().get(path);
if (taskPojos == null) return;
for (ExternalTaskPojo taskPojo : taskPojos) {
if (taskName.equals(taskPojo.getName())) {
processTask(taskName, GRADLE_API_TASK, psiManager, processor, state, place);
return;
}
}
}
private static void processTask(@NotNull String taskName,
@NotNull String fqName,
@NotNull GroovyPsiManager psiManager,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
if (taskName.equals(place.getText())) {
if (!(place instanceof GrClosableBlock)) {
GrLightMethodBuilder methodBuilder = GradleResolverUtil.createMethodWithClosure(taskName, fqName, null, place, psiManager);
if (methodBuilder == null) return;
processor.execute(methodBuilder, state);
PsiClass contributorClass =
psiManager.findClassWithCache(fqName, place.getResolveScope());
if (contributorClass == null) return;
//GradleResolverUtil.processMethod(taskName, contributorClass, processor, state, place);
}
}
else {
GradleResolverUtil.processDeclarations(psiManager, processor, state, place, fqName);
}
}
private static void processAvailableTasks(List<String> methodCallInfo, @NotNull String taskName,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
PsiClass gradleApiProjectClass = psiManager.findClassWithCache(GRADLE_API_PROJECT, place.getResolveScope());
if (canBeMethodOf(taskName, gradleApiProjectClass)) return;
if (canBeMethodOf(GroovyPropertyUtils.getGetterNameNonBoolean(taskName), gradleApiProjectClass)) return;
final String className = BUILT_IN_TASKS.get(taskName);
if (className != null) {
//GradleResolverUtil.processDeclarations(
// methodCallInfo.size() > 0 ? methodCallInfo.get(0) : null, psiManager, processor, state, place, className);
}
}
}
@@ -1,143 +0,0 @@
/*
* 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.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
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.impl.synthetic.GrLightParameter;
import java.util.List;
/**
* @author Vladislav.Soroka
* @since 9/9/13
*/
public class GradleTaskContributor implements GradleMethodContextContributor {
@Override
public boolean process(@NotNull List<String> methodCallInfo,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
if (methodCallInfo.isEmpty()) return true;
if (methodCallInfo.size() == 1) {
if(GradleResolverUtil.isLShiftElement(place.getParent())) {
GradleResolverUtil.addImplicitVariable(processor, state, place, GradleCommonClassNames.GRADLE_API_TASK);
}
}
else if (methodCallInfo.size() == 2) {
if (place.getParent().getParent() instanceof GrCommandArgumentList) {
// Assuming that the method call is addition of new task into the project.
processTaskAddition(methodCallInfo.get(0), GradleCommonClassNames.GRADLE_API_TASK_CONTAINER, processor, state, place);
}
else {
processTaskTypeParameter(processor, state, place);
}
GradleImplicitContributor.processImplicitDeclarations(processor, state, place);
}
else if (methodCallInfo.size() >= 3) {
processTaskTypeParameter(processor, state, place);
GradleImplicitContributor.processImplicitDeclarations(processor, state, place);
}
return true;
}
private static void processTaskTypeParameter(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
final int taskTypeParameterLevel = 3;
PsiElement psiElement = GradleResolverUtil.findParent(place, taskTypeParameterLevel);
if (psiElement instanceof GrMethodCallExpression) {
GrMethodCallExpression callExpression = (GrMethodCallExpression)psiElement;
GrArgumentList argumentList = callExpression.getArgumentList();
if (argumentList.getAllArguments().length > 0) {
for (GroovyPsiElement argument : argumentList.getAllArguments()) {
if (argument instanceof GrNamedArgument) {
GrNamedArgument namedArgument = (GrNamedArgument)argument;
GrExpression grExpression = namedArgument.getExpression();
PsiType psiType = null;
if (grExpression != null) {
psiType = GradleResolverUtil.getTypeOf(grExpression);
}
if (psiType instanceof PsiImmediateClassType) {
PsiImmediateClassType immediateClassType = (PsiImmediateClassType)psiType;
for (PsiType type : immediateClassType.getParameters()) {
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(psiManager, processor, state, place, TypesUtil.getQualifiedName(type));
}
}
}
}
}
else {
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
GradleResolverUtil.processDeclarations(psiManager, processor, state, place, GradleCommonClassNames.GRADLE_API_TASK);
}
}
}
private static void processTaskAddition(@NotNull String name,
@NotNull String handlerClass,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
PsiClass psiClass = psiManager.findClassWithCache(handlerClass, place.getResolveScope());
if (psiClass == null) {
return;
}
GrLightMethodBuilder builder = new GrLightMethodBuilder(place.getManager(), name);
PsiElementFactory factory = JavaPsiFacade.getElementFactory(place.getManager().getProject());
PsiType type = new PsiArrayType(factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, place.getResolveScope()));
builder.addParameter(new GrLightParameter("taskInfo", type, builder));
PsiClassType retType = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, place.getResolveScope());
builder.setReturnType(retType);
processor.execute(builder, state);
GrMethodCall call = PsiTreeUtil.getParentOfType(place, GrMethodCall.class);
if (call == null) {
return;
}
GrArgumentList args = call.getArgumentList();
int argsCount = GradleResolverUtil.getGrMethodArumentsCount(args);
argsCount++; // Configuration name is delivered as an argument.
for (PsiMethod method : psiClass.findMethodsByName("create", false)) {
if (method.getParameterList().getParametersCount() == argsCount) {
builder.setNavigationElement(method);
}
}
}
}
@@ -16,21 +16,21 @@
package org.jetbrains.plugins.gradle.service.resolve
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.ResolveState
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.groovy.lang.psi.patterns.GroovyPatterns
import java.util.*
/**
* @author Vladislav.Soroka
* @since 11/11/2016
*/
@JvmField val RESOLVED_CODE = Key.create<Boolean?>("gradle.resolved")
fun processDeclarations(handlerClass: PsiClass,
processor: PsiScopeProcessor,
state: ResolveState,
@@ -42,11 +42,16 @@ fun processDeclarations(handlerClass: PsiClass,
if (!componentClass.processDeclarations(componentProcessor, state, null, place)) return false
}
else {
val processedSignatures = HashSet<List<String>>()
for (method in componentClass.findMethodsByName(name, true)) {
processedSignatures.add(method.getSignature(PsiSubstitutor.EMPTY).parameterTypes.map({ it.canonicalText }))
place.putUserData(RESOLVED_CODE, true)
if (!componentProcessor.execute(method, state)) return false
}
for (prefix in arrayOf("add", "set")) {
for (method in componentClass.findMethodsByName(prefix + 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
}
}
@@ -22,14 +22,18 @@ import com.intellij.openapi.components.Storage;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
import com.intellij.util.SmartList;
import com.intellij.util.xmlb.XmlSerializerUtil;
import com.intellij.util.xmlb.annotations.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter;
import org.jetbrains.plugins.gradle.model.ExternalTask;
import org.jetbrains.plugins.gradle.model.GradleExtensions;
import org.jetbrains.plugins.gradle.model.GradleProperty;
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import java.io.Serializable;
@@ -99,6 +103,28 @@ public class GradleExtensionsSettings implements PersistentStateComponent<Gradle
}
extensionsData.properties.add(gradleProp);
}
for (ExternalTask task : gradleExtensions.getTasks()) {
GradleTask gradleTask = new GradleTask();
gradleTask.name = task.getName();
String type = task.getType();
if (type != null) {
gradleTask.typeFqn = type;
}
StringBuilder description = new StringBuilder();
if(task.getDescription() != null) {
description.append(task.getDescription());
if(task.getGroup() != null) {
description.append("<p>");
}
}
if(task.getGroup() != null) {
description.append("<i>Task group: ").append(task.getGroup()).append("<i>");
}
gradleTask.description = description.toString();
extensionsData.tasks.add(gradleTask);
}
gradleProject.extensions.put(entry.getKey(), extensionsData);
}
@@ -145,25 +171,38 @@ public class GradleExtensionsSettings implements PersistentStateComponent<Gradle
@Property(surroundWithTag = false)
@AbstractCollection(surroundWithTag = false)
public List<GradleProp> properties = new SmartList<>();
@Property(surroundWithTag = false)
@AbstractCollection(surroundWithTag = false)
public List<GradleTask> tasks = new SmartList<>();
}
@Tag("ext")
public static class GradleExtension {
@Attribute("name")
public String name;
@Attribute("rootTypeFqn")
public String rootTypeFqn;
@Attribute("namedObjectTypeFqn")
@Attribute("type")
public String rootTypeFqn = CommonClassNames.JAVA_LANG_OBJECT_SHORT;
@Attribute("objectType")
public String namedObjectTypeFqn;
}
@Tag("p")
@Tag("prop")
public static class GradleProp {
@Attribute("name")
public String name;
@Attribute("typeFqn")
public String typeFqn;
@Attribute("type")
public String typeFqn = CommonClassNames.JAVA_LANG_STRING;
@Nullable
@Attribute("val")
@Text
public String value;
}
@Tag("task")
public static class GradleTask extends GradleProp {
@Nullable
@Text
public String description;
@Attribute("type")
public String typeFqn = GradleCommonClassNames.GRADLE_API_DEFAULT_TASK;
}
}
@@ -30,4 +30,7 @@ public interface GradleExtensions extends Serializable {
@NotNull
List<GradleProperty> getGradleProperties();
@NotNull
List<ExternalTask> getTasks();
}
@@ -27,7 +27,7 @@ public class DefaultGradleExtension extends DefaultGradleProperty implements Gra
@Nullable
private final String myNamedObjectTypeFqn;
public DefaultGradleExtension(@NotNull String name, @NotNull String typeFqn, @Nullable String namedObjectTypeFqn) {
public DefaultGradleExtension(@NotNull String name, @Nullable String typeFqn, @Nullable String namedObjectTypeFqn) {
super(name, typeFqn, null);
myNamedObjectTypeFqn = namedObjectTypeFqn;
}
@@ -35,6 +35,7 @@ public class DefaultGradleExtension extends DefaultGradleProperty implements Gra
public DefaultGradleExtension(GradleExtension extension) {
this(extension.getName(), extension.getTypeFqn(), extension.getNamedObjectTypeFqn());
}
@Nullable
@Override
public String getNamedObjectTypeFqn() {
@@ -30,6 +30,8 @@ public class DefaultGradleExtensions implements GradleExtensions {
private final List<GradleExtension> myExtensions = new ArrayList<GradleExtension>();
@NotNull
private final List<GradleProperty> myGradleProperties = new ArrayList<GradleProperty>();
@NotNull
private List<ExternalTask> myTasks = new ArrayList<ExternalTask>();
public DefaultGradleExtensions() {
}
@@ -41,6 +43,9 @@ public class DefaultGradleExtensions implements GradleExtensions {
for (GradleProperty property : extensions.getGradleProperties()) {
myGradleProperties.add(new DefaultGradleProperty(property));
}
for (ExternalTask entry : extensions.getTasks()) {
myTasks.add(new DefaultExternalTask(entry));
}
}
@NotNull
@@ -54,4 +59,10 @@ public class DefaultGradleExtensions implements GradleExtensions {
public List<GradleProperty> getGradleProperties() {
return myGradleProperties;
}
@NotNull
@Override
public List<ExternalTask> getTasks() {
return myTasks;
}
}
@@ -33,9 +33,9 @@ public class DefaultGradleProperty implements GradleProperty {
@Nullable
private final Serializable myValue;
public DefaultGradleProperty(@NotNull String name, @NotNull String typeFqn, @Nullable Serializable value) {
public DefaultGradleProperty(@NotNull String name, @Nullable String typeFqn, @Nullable Serializable value) {
myName = name;
myRootTypeFqn = typeFqn;
myRootTypeFqn = typeFqn == null ? "Object" : typeFqn;
myValue = value;
}
@@ -63,7 +63,7 @@ class ProjectExtensionsDataBuilderImpl implements ModelBuilderService {
result.extensions.add(new DefaultGradleExtension(name, rootTypeFqn, namedObjectTypeFqn))
}
}
return result.extensions.isEmpty() && result.gradleProperties.isEmpty() ? null : result
return result
}
@Override
@@ -75,7 +75,7 @@ class ProjectExtensionsDataBuilderImpl implements ModelBuilderService {
}
static String getType(object) {
def clazz = object.getClass()?.canonicalName
def clazz = object?.getClass()?.canonicalName
def decorIndex = clazz?.lastIndexOf('_Decorated')
!decorIndex || decorIndex == -1 ? clazz : clazz.substring(0, decorIndex)
}