IDEA-50450 Gradle code insight. 'configurations' resolving added

This commit is contained in:
Vladislav.Soroka
2013-08-30 16:43:46 +04:00
parent 6ec1856ccb
commit 368636d241
6 changed files with 255 additions and 19 deletions
+2
View File
@@ -31,6 +31,7 @@
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleRepositoriesContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleDependenciesContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleConfigurationsContributor"/>
<resolve.contributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleRootContributor"/>
</extensions>
@@ -72,6 +73,7 @@
<groovyFrameworkConfigNotification implementation="org.jetbrains.plugins.gradle.config.GradleGroovyConfigNotification"/>
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleScriptContributor"/>
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleConfigurationsNonCodeMembersContributor"/>
<methodDescriptor class="org.gradle.api.Project" name="apply">
<namedArgument name="plugin" values="java,groovy,idea,eclipse,scala,antlr,application,ear,jetty,maven,osgi,war,announce,build-announcements,checkstyle,codenarc,eclipse-wtp,findbugs,jdepend,pmd,project-report,signing,sonar"/>
</methodDescriptor>
@@ -0,0 +1,86 @@
/*
* Copyright 2000-2013 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.PsiVariable;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrImplicitVariableImpl;
import java.util.List;
/**
* @author Vladislav.Soroka
* @since 8/29/13
*/
public class GradleConfigurationsContributor implements GradleMethodContextContributor {
private static final String CONFIGURATIONS = "configurations";
@Override
public void process(@NotNull List<String> methodCallInfo,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
if (methodCallInfo.isEmpty()) {
return;
}
final String methodCall = methodCallInfo.get(0);
PsiClass contributorClass = null;
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
if (methodCallInfo.size() == 1) {
if (methodCall.startsWith(CONFIGURATIONS + '.')) {
contributorClass = psiManager.findClassWithCache(Configuration.class.getName(), place.getResolveScope());
}
else if (CONFIGURATIONS.equals(methodCall)) {
contributorClass = psiManager.findClassWithCache(ConfigurationContainer.class.getName(), place.getResolveScope());
if (place instanceof GrReferenceExpressionImpl) {
addImplicitConfiguration(processor, state, (GrReferenceExpressionImpl)place);
return;
}
}
}
else if (methodCallInfo.size() == 2) {
if (CONFIGURATIONS.equals(methodCallInfo.get(1))) {
contributorClass = psiManager.findClassWithCache(ConfigurationContainer.class.getName(), place.getResolveScope());
if (place instanceof GrReferenceExpressionImpl) {
addImplicitConfiguration(processor, state, (GrReferenceExpressionImpl)place);
return;
}
}
}
if (contributorClass != null) {
contributorClass.processDeclarations(processor, state, null, place);
}
}
@SuppressWarnings("MethodMayBeStatic")
private void addImplicitConfiguration(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull GrReferenceExpressionImpl expression) {
String expr = expression.getCanonicalText();
PsiVariable myPsi = new GrImplicitVariableImpl(expression.getManager(), expr, Configuration.class.getName(), expression);
processor.execute(myPsi, state);
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2000-2013 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.*;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import groovy.lang.Closure;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrImplicitVariableImpl;
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.resolve.NonCodeMembersContributor;
/**
* @author Vladislav.Soroka
* @since 8/30/13
*/
public class GradleConfigurationsNonCodeMembersContributor extends NonCodeMembersContributor {
private static final String METHOD_GET_BY_NAME = "getByName";
@Override
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiClass aClass,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state) {
if (place == null) {
return;
}
if (!ConfigurationContainer.class.getName().equals(aClass.getQualifiedName())) {
return;
}
// Assuming that the method call is equivalent to calling ConfigurationContainer.getByName()
processConfigurationAddition(aClass, processor, state, place);
}
@SuppressWarnings("MethodMayBeStatic")
private void processConfigurationAddition(@NotNull PsiClass dependencyHandlerClass,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
GrMethodCall call = PsiTreeUtil.getParentOfType(place, GrMethodCall.class);
if (call == null) {
// TODO replace with groovy implicit method
GrReferenceExpressionImpl expression = (GrReferenceExpressionImpl)place;
String expr = expression.getCanonicalText();
GrImplicitVariableImpl myPsi = new GrImplicitVariableImpl(place.getManager(), expr, Configuration.class.getName(), place);
processor.execute(myPsi, state);
setNavigation(myPsi, dependencyHandlerClass, METHOD_GET_BY_NAME, 1);
return;
}
GrArgumentList args = call.getArgumentList();
if (args == null) {
return;
}
int argsCount = GradleResolverUtil.getGrMethodArumentsCount(args);
argsCount++; // Configuration name is delivered as an argument.
if (argsCount == 1) {
GrLightMethodBuilder builder = new GrLightMethodBuilder(place.getManager(), METHOD_GET_BY_NAME);
PsiClassType type = PsiType.getJavaLangObject(place.getManager(), place.getResolveScope());
builder.addParameter(new GrLightParameter("s", type, builder));
processor.execute(builder, state);
argsCount++; // we need method with extra argument of type Closure.
setNavigation(builder, dependencyHandlerClass, METHOD_GET_BY_NAME, argsCount);
}
}
@SuppressWarnings("MethodMayBeStatic")
private void setNavigation(LightElement element, PsiClass dependencyHandlerClass, String methodName, int parametersCount) {
for (PsiMethod method : dependencyHandlerClass.findMethodsByName(methodName, false)) {
int methodParameterCount = method.getParameterList().getParametersCount();
if (methodParameterCount == parametersCount &&
method.getParameterList().getParameters()[methodParameterCount - 1].getType().equalsToText(Closure.class.getName())) {
element.setNavigationElement(method);
}
}
}
}
@@ -35,7 +35,7 @@ import java.util.List;
* @since 8/14/13 12:58 PM
*/
public class GradleDependenciesContributor implements GradleMethodContextContributor {
@Override
public void process(@NotNull List<String> methodCallInfo,
@NotNull PsiScopeProcessor processor,
@@ -50,7 +50,7 @@ public class GradleDependenciesContributor implements GradleMethodContextContrib
if (i != 1) {
return;
}
// Assuming that the method call is addition of new dependency into configuration.
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
PsiClass contributorClass = psiManager.findClassWithCache(DependencyHandler.class.getName(), place.getResolveScope());
@@ -70,7 +70,7 @@ public class GradleDependenciesContributor implements GradleMethodContextContrib
PsiClassType type = PsiType.getJavaLangObject(place.getManager(), place.getResolveScope());
builder.addParameter(new GrLightParameter("dependencyInfo", type, builder));
processor.execute(builder, state);
GrMethodCall call = PsiTreeUtil.getParentOfType(place, GrMethodCall.class);
if (call == null) {
return;
@@ -79,20 +79,8 @@ public class GradleDependenciesContributor implements GradleMethodContextContrib
if (args == null) {
return;
}
int argsCount = 0;
boolean namedArgProcessed = false;
for (GroovyPsiElement arg : args.getAllArguments()) {
if (arg instanceof GrNamedArgument) {
if (!namedArgProcessed) {
namedArgProcessed = true;
argsCount++;
}
}
else {
argsCount++;
}
}
int argsCount = GradleResolverUtil.getGrMethodArumentsCount(args);
argsCount++; // Configuration name is delivered as an argument.
for (PsiMethod method : dependencyHandlerClass.findMethodsByName("add", false)) {
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2013 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 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;
/**
* @author Vladislav.Soroka
* @since 8/30/13
*/
public class GradleResolverUtil {
public static int getGrMethodArumentsCount(GrArgumentList args) {
int argsCount = 0;
boolean namedArgProcessed = false;
for (GroovyPsiElement arg : args.getAllArguments()) {
if (arg instanceof GrNamedArgument) {
if (!namedArgProcessed) {
namedArgProcessed = true;
argsCount++;
}
}
else {
argsCount++;
}
}
return argsCount;
}
}
@@ -19,12 +19,13 @@ import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.containers.Stack;
import com.intellij.util.containers.ContainerUtil;
import org.gradle.api.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import java.util.List;
import java.util.Set;
/**
* @author Denis Zhdanov
@@ -32,12 +33,22 @@ import java.util.List;
*/
public class GradleRootContributor implements GradleMethodContextContributor {
private final static Set<String> PROJECT_ACTIONS = ContainerUtil.newHashSet(
"subprojects",
"allprojects",
"beforeEvaluate",
"afterEvaluate");
@Override
public void process(@NotNull List<String> methodCallInfo,
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull PsiElement place) {
if (methodCallInfo.size() > 1) {
if(methodCallInfo.size() > 2) {
return;
}
if (methodCallInfo.size() == 2 && !PROJECT_ACTIONS.contains(methodCallInfo.get(1))) {
return;
}