IDEA-153848 Gradle: extra properties are not resolved (IDEA-115444, IDEA-131546)

This commit is contained in:
Vladislav.Soroka
2016-11-29 20:50:24 +03:00
parent f936f62e3a
commit 52ac9083f4
12 changed files with 232 additions and 50 deletions
+1 -1
View File
@@ -150,7 +150,7 @@
factoryClass="org.jetbrains.plugins.gradle.ui.GradleToolWindowFactory"
conditionClass="org.jetbrains.plugins.gradle.ui.GradleToolWindowFactoryCondition"/>
<lang.documentationProvider language="Groovy"
implementationClass="org.jetbrains.plugins.gradle.documentation.GradleDocumentationProvider"/>
implementationClass="org.jetbrains.plugins.gradle.documentation.GradleDocumentationProvider" order="first"/>
<editorNotificationProvider implementation="org.jetbrains.plugins.gradle.codeInsight.UseDistributionWithSourcesNotificationProvider"/>
<annotator language="Groovy" implementationClass="org.jetbrains.plugins.gradle.service.resolve.dsl.GradleDslAnnotator"/>
<weigher key="completion" implementationClass="org.jetbrains.plugins.gradle.service.resolve.dsl.GradleCompletionWeigher"
@@ -28,9 +28,11 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.jetbrains.plugins.gradle.util.GradleDocumentationBundle;
import org.jetbrains.plugins.groovy.dsl.CustomMembersGenerator;
import org.jetbrains.plugins.groovy.dsl.holders.NonCodeMembersHolder;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable;
import java.util.ArrayList;
import java.util.List;
@@ -44,6 +46,15 @@ public class GradleDocumentationProvider implements DocumentationProvider {
@Nullable
@Override
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
PsiFile file = element.getContainingFile();
if (file == null || !FileUtilRt.extensionEquals(file.getName(), GradleConstants.EXTENSION)) return null;
if (element instanceof GrLightVariable) {
PsiElement navigationElement = element.getNavigationElement();
if (navigationElement != null) {
String doc = navigationElement.getUserData(NonCodeMembersHolder.DOCUMENTATION);
if (doc != null) return doc;
}
}
return null;
}
@@ -15,7 +15,9 @@
*/
package org.jetbrains.plugins.gradle.service.resolve
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.PsiJavaPatterns.psiElement
import com.intellij.psi.PsiElement
@@ -27,6 +29,7 @@ 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.settings.GradleExtensionsSettings
import org.jetbrains.plugins.groovy.dsl.holders.NonCodeMembersHolder.DOCUMENTATION
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
@@ -87,6 +90,27 @@ 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) {
for (gradleProp in extensionsData.properties) {
if (name == gradleProp.name) {
val docRef = Ref.create<String>()
val variable = object : GrLightVariable(place.manager, name, gradleProp.typeFqn, place) {
override fun getNavigationElement(): PsiElement {
val navigationElement = super.getNavigationElement()
navigationElement.putUserData(DOCUMENTATION, docRef.get())
return navigationElement
}
}
val doc = getDocumentation(gradleProp, variable)
docRef.set(doc)
place.putUserData(DOCUMENTATION, doc)
if (!processor.execute(variable, state)) return false
}
}
}
}
for (extension in extensionsData.extensions) {
if (!shouldProcessMethods && shouldProcessProperties && name == extension.name) {
val variable = GrLightVariable(place.manager, name, extension.rootTypeFqn, place)
@@ -129,6 +153,23 @@ class GradleExtensionsContributor : GradleMethodContextContributor {
return true
}
private fun getDocumentation(gradleProp: GradleExtensionsSettings.GradleProp,
lightVariable: GrLightVariable): String {
val buffer = StringBuilder()
buffer.append("<PRE>")
JavaDocInfoGenerator.generateType(buffer, lightVariable.type, lightVariable, true)
buffer.append(" " + gradleProp.name)
val hasInitializer = !gradleProp.value.isNullOrBlank()
if (hasInitializer) {
buffer.append(" = " + gradleProp.value)
}
buffer.append("</PRE>")
if (hasInitializer) {
buffer.append("<b>Initial value has been got during last import</b>")
}
return buffer.toString()
}
companion object {
fun getExtensionsFor(psiElement: PsiElement): GradleExtensionsSettings.GradleExtensionsData? {
val project = psiElement.project
@@ -29,8 +29,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter;
import org.jetbrains.plugins.gradle.model.GradleExtensions;
import org.jetbrains.plugins.gradle.model.GradleProperty;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -79,13 +81,24 @@ public class GradleExtensionsSettings implements PersistentStateComponent<Gradle
GradleProject gradleProject = new GradleProject();
for (Map.Entry<String, GradleExtensions> entry : extensions.entrySet()) {
GradleExtensionsData extensionsData = new GradleExtensionsData();
for (org.jetbrains.plugins.gradle.model.GradleExtension extension : entry.getValue().list()) {
GradleExtensions gradleExtensions = entry.getValue();
for (org.jetbrains.plugins.gradle.model.GradleExtension extension : gradleExtensions.getExtensions()) {
GradleExtension gradleExtension = new GradleExtension();
gradleExtension.name = extension.getName();
gradleExtension.rootTypeFqn = extension.getRootTypeFqn();
gradleExtension.rootTypeFqn = extension.getTypeFqn();
gradleExtension.namedObjectTypeFqn = extension.getNamedObjectTypeFqn();
extensionsData.extensions.add(gradleExtension);
}
for (GradleProperty property : gradleExtensions.getGradleProperties()) {
GradleProp gradleProp = new GradleProp();
gradleProp.name = property.getName();
gradleProp.typeFqn = property.getTypeFqn();
Serializable value = property.getValue();
if(value != null) {
gradleProp.value = value.toString();
}
extensionsData.properties.add(gradleProp);
}
gradleProject.extensions.put(entry.getKey(), extensionsData);
}
@@ -129,6 +142,9 @@ public class GradleExtensionsSettings implements PersistentStateComponent<Gradle
@Property(surroundWithTag = false)
@AbstractCollection(surroundWithTag = false)
public List<GradleExtension> extensions = new SmartList<>();
@Property(surroundWithTag = false)
@AbstractCollection(surroundWithTag = false)
public List<GradleProp> properties = new SmartList<>();
}
@Tag("ext")
@@ -140,4 +156,14 @@ public class GradleExtensionsSettings implements PersistentStateComponent<Gradle
@Attribute("namedObjectTypeFqn")
public String namedObjectTypeFqn;
}
@Tag("p")
public static class GradleProp {
@Attribute("name")
public String name;
@Attribute("typeFqn")
public String typeFqn;
@Nullable
@Attribute("val")
public String value;
}
}
@@ -24,11 +24,7 @@ import java.io.Serializable;
* @author Vladislav.Soroka
* @since 11/16/2016
*/
public interface GradleExtension extends Serializable {
@NotNull
String getName();
@NotNull
String getRootTypeFqn();
public interface GradleExtension extends GradleProperty {
@Nullable
String getNamedObjectTypeFqn();
}
@@ -15,6 +15,8 @@
*/
package org.jetbrains.plugins.gradle.model;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.util.List;
@@ -23,5 +25,9 @@ import java.util.List;
* @since 11/16/2016
*/
public interface GradleExtensions extends Serializable {
List<GradleExtension> list();
@NotNull
List<GradleExtension> getExtensions();
@NotNull
List<GradleProperty> getGradleProperties();
}
@@ -0,0 +1,36 @@
/*
* 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.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
/**
* @author Vladislav.Soroka
* @since 11/16/2016
*/
public interface GradleProperty extends Serializable {
@NotNull
String getName();
@NotNull
String getTypeFqn();
@Nullable
Serializable getValue();
}
@@ -22,37 +22,19 @@ import org.jetbrains.annotations.Nullable;
* @author Vladislav.Soroka
* @since 11/16/2016
*/
public class DefaultGradleExtension implements GradleExtension {
public class DefaultGradleExtension extends DefaultGradleProperty implements GradleExtension {
private static final long serialVersionUID = 1L;
@NotNull
private final String myName;
@NotNull
private final String myRootTypeFqn;
@Nullable
private final String myNamedObjectTypeFqn;
public DefaultGradleExtension(@NotNull String name, @NotNull String rootTypeFqn, @Nullable String namedObjectTypeFqn) {
myName = name;
myRootTypeFqn = rootTypeFqn;
public DefaultGradleExtension(@NotNull String name, @NotNull String typeFqn, @Nullable String namedObjectTypeFqn) {
super(name, typeFqn, null);
myNamedObjectTypeFqn = namedObjectTypeFqn;
}
public DefaultGradleExtension(GradleExtension extension) {
this(extension.getName(), extension.getRootTypeFqn(), extension.getNamedObjectTypeFqn());
this(extension.getName(), extension.getTypeFqn(), extension.getNamedObjectTypeFqn());
}
@NotNull
@Override
public String getName() {
return myName;
}
@NotNull
@Override
public String getRootTypeFqn() {
return myRootTypeFqn;
}
@Nullable
@Override
public String getNamedObjectTypeFqn() {
@@ -15,6 +15,8 @@
*/
package org.jetbrains.plugins.gradle.model;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@@ -22,20 +24,34 @@ import java.util.List;
* @author Vladislav.Soroka
* @since 11/16/2016
*/
public class DefaultGradleExtensions extends ArrayList<GradleExtension> implements GradleExtensions {
public class DefaultGradleExtensions implements GradleExtensions {
private static final long serialVersionUID = 1L;
@NotNull
private final List<GradleExtension> myExtensions = new ArrayList<GradleExtension>();
@NotNull
private final List<GradleProperty> myGradleProperties = new ArrayList<GradleProperty>();
public DefaultGradleExtensions() {
}
public DefaultGradleExtensions(GradleExtensions extensions) {
for (GradleExtension extension : extensions.list()) {
add(new DefaultGradleExtension(extension));
for (GradleExtension extension : extensions.getExtensions()) {
myExtensions.add(new DefaultGradleExtension(extension));
}
for (GradleProperty property : extensions.getGradleProperties()) {
myGradleProperties.add(new DefaultGradleProperty(property));
}
}
@NotNull
@Override
public List<GradleExtension> list() {
return this;
public List<GradleExtension> getExtensions() {
return myExtensions;
}
@NotNull
@Override
public List<GradleProperty> getGradleProperties() {
return myGradleProperties;
}
}
@@ -0,0 +1,63 @@
/*
* 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.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
/**
* @author Vladislav.Soroka
* @since 11/16/2016
*/
public class DefaultGradleProperty implements GradleProperty {
private static final long serialVersionUID = 1L;
@NotNull
private final String myName;
@NotNull
private final String myRootTypeFqn;
@Nullable
private final Serializable myValue;
public DefaultGradleProperty(@NotNull String name, @NotNull String typeFqn, @Nullable Serializable value) {
myName = name;
myRootTypeFqn = typeFqn;
myValue = value;
}
public DefaultGradleProperty(GradleProperty property) {
this(property.getName(), property.getTypeFqn(), property.getValue());
}
@NotNull
@Override
public String getName() {
return myName;
}
@NotNull
@Override
public String getTypeFqn() {
return myRootTypeFqn;
}
@Nullable
@Override
public Serializable getValue() {
return myValue;
}
}
@@ -138,10 +138,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
externalTask.QName = task.name
externalTask.description = task.description
externalTask.group = task.group ?: "other"
def clazzName = task.class.canonicalName
def prefixIndex = clazzName.lastIndexOf('_Decorated')
externalTask.type = prefixIndex == -1 ? clazzName : clazzName.substring(0, prefixIndex)
externalTask.type = ProjectExtensionsDataBuilderImpl.getType(task)
result.put(externalTask.name, externalTask)
}
@@ -22,6 +22,7 @@ import org.gradle.api.internal.plugins.DefaultConvention
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.gradle.model.DefaultGradleExtension
import org.jetbrains.plugins.gradle.model.DefaultGradleExtensions
import org.jetbrains.plugins.gradle.model.DefaultGradleProperty
import org.jetbrains.plugins.gradle.model.GradleExtensions
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
@@ -41,27 +42,28 @@ class ProjectExtensionsDataBuilderImpl implements ModelBuilderService {
Object buildAll(String modelName, Project project) {
DefaultGradleExtensions result = new DefaultGradleExtensions()
def conventions = project.extensions as DefaultConvention
conventions.extraProperties.properties.each { name, value ->
String typeFqn = getType(value)
result.gradleProperties.add(new DefaultGradleProperty(
name, typeFqn, value.toString()))
}
for (it in conventions.findAll()) {
def convention = it as DefaultConvention
convention.asMap.each { name, value ->
if(name == 'idea') return
def rootClazz = value.getClass()?.canonicalName
def rootDecorIndex = rootClazz?.lastIndexOf('_Decorated')
def rootTypeFqn = !rootDecorIndex || rootDecorIndex == -1 ? rootClazz : rootClazz.substring(0, rootDecorIndex)
def rootTypeFqn = getType(value)
def namedObjectTypeFqn = null as String
if (value instanceof NamedDomainObjectCollection) {
NamedDomainObjectCollection objectCollection = (NamedDomainObjectCollection)value
def objectCollection = (NamedDomainObjectCollection)value
if(!objectCollection.isEmpty()) {
def namedObjectClazz = objectCollection.first().getClass()?.canonicalName
def namedObjectDecorIndex = namedObjectClazz?.lastIndexOf('_Decorated')
namedObjectTypeFqn = !namedObjectDecorIndex || namedObjectDecorIndex == -1 ? namedObjectClazz :
namedObjectClazz.substring(0, namedObjectDecorIndex)
namedObjectTypeFqn = getType(objectCollection.first())
}
}
result.add(new DefaultGradleExtension(name, rootTypeFqn, namedObjectTypeFqn))
result.extensions.add(new DefaultGradleExtension(name, rootTypeFqn, namedObjectTypeFqn))
}
}
return result.isEmpty() ? null : result
return result.extensions.isEmpty() && result.gradleProperties.isEmpty() ? null : result
}
@Override
@@ -71,4 +73,10 @@ class ProjectExtensionsDataBuilderImpl implements ModelBuilderService {
).withDescription(
"Unable to resolve some context data of gradle scripts. Some codeInsight features inside *.gradle files can be unavailable.")
}
static String getType(object) {
def clazz = object.getClass()?.canonicalName
def decorIndex = clazz?.lastIndexOf('_Decorated')
!decorIndex || decorIndex == -1 ? clazz : clazz.substring(0, decorIndex)
}
}