use of org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager in project android by JetBrains.
the class AndroidDslContributor method process.
@Override
public boolean process(@NotNull List<String> callStack, @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @NotNull PsiElement place) {
// The Android DSL within a Gradle build script looks something like this:
// android {
// compileSdkVersion 18
// buildToolsVersion "19.0.0"
//
// defaultConfig {
// minSdkVersion 8
// }
//
// buildTypes {
// release {
// runProguard false
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
// }
// }
//
// lintOptions {
// quiet true
// }
// }
// This method receives a callstack leading to a particular symbol, e.g. android.compileSdkVersion, or
// android.buildTypes.release.runProguard. Based on the given call stack, we have to resolve either to a particular class or to a
// particular setter within the class.
//
// The blocks are processed top down i.e. android is resolved before any symbols within the android closure are resolved.
// When a particular symbol is resolved, the resolution is cached as user data of that PsiElement under CONTRIBUTOR_KEY.
// All symbols inside the android block first attempt to determine their parent method, and look at the parent contributor.
// Depending on the parent contributor (method or class), the symbols are resolved to be either method calls of a class or
// new domain objects.
// There are two issues that necessitate this custom processing: 1. Groovy doesn't know what the block corresponding to
// 'android' with a closure means i.e. it doesn't know that it is an extension provided by the android Gradle plugin.
// 2. Once it understands that 'android' is a closure of a certain type, it still stumbles over methods that take in
// either an Action<T> or a Action<NamedDomainObject<T>>. So most of the code simply tries to match the former to a method
// that takes a closure<T> and the latter to be a closure that defines objects with closure<T>
// we only care about symbols within the android closure
String topLevel = ContainerUtil.getLastItem(callStack, null);
if (!DSL_ANDROID.equals(topLevel)) {
return true;
}
GroovyPsiManager psiManager = GroovyPsiManager.getInstance(place.getProject());
// top level android block
if (callStack.size() == 1) {
String fqcn = resolveAndroidExtension(place.getContainingFile());
PsiClass contributorClass = fqcn == null ? null : findClassByName(place.getProject(), place.getResolveScope(), fqcn);
if (contributorClass != null) {
String qualifiedName = contributorClass.getQualifiedName();
if (qualifiedName == null) {
qualifiedName = fqcn;
}
// resolve 'android' as a method that takes a closure
resolveToMethodWithClosure(place, contributorClass, qualifiedName, processor, state);
cacheContributorInfo(place, contributorClass);
}
return true;
}
// For all blocks within android, we first figure out who contributed the parent block.
PsiElement parentContributor = getParentContributor(place);
if (parentContributor == null) {
return true;
}
// if the parent object is a class, then process the current identifier as a method of the parent class
if (parentContributor instanceof PsiClass) {
PsiMethod method = findAndProcessContributingMethod(callStack.get(0), processor, state, place, (PsiClass) parentContributor);
cacheContributorInfo(place, method);
return true;
}
// This is similar to case 2, we just need to make sure that debug is resolved as a variable of type AndroidSourceSet
if (!(parentContributor instanceof PsiMethod)) {
return true;
}
// determine the type variable present in the parent method
ParametrizedTypeExtractor typeExtractor = getTypeExtractor((PsiMethod) parentContributor);
if (typeExtractor == null) {
Logger.getInstance(AndroidDslContributor.class).info("inside the closure of a method, but unable to extract the closure parameter's type.");
return true;
}
if (typeExtractor.hasNamedDomainObjectContainer()) {
// this symbol must be a NamedDomainObject<T>
// so define a it as a method with the given name (place.getText()) with an argument Closure<T>
String namedDomainObject = typeExtractor.getNamedDomainObject();
// because hasNamedDomainObjectContainer()
assert namedDomainObject != null : typeExtractor.getCanonicalType();
PsiClass contributorClass = findClassByName(place.getProject(), place.getResolveScope(), namedDomainObject);
if (contributorClass != null) {
String qualifiedName = contributorClass.getQualifiedName();
if (qualifiedName == null) {
qualifiedName = namedDomainObject;
}
resolveToMethodWithClosure(place, contributorClass, qualifiedName, processor, state);
cacheContributorInfo(place, contributorClass);
}
return true;
}
if (typeExtractor.isClosure()) {
// the parent method was of type Action<T>, so this is simply a method of class T
String clz = typeExtractor.getClosureType();
// because typeExtractor.isClosure()
assert clz != null : typeExtractor.getCanonicalType();
PsiClass contributorClass = findClassByName(place.getProject(), place.getResolveScope(), clz);
if (contributorClass == null) {
return true;
}
PsiMethod method = findAndProcessContributingMethod(callStack.get(0), processor, state, place, contributorClass);
cacheContributorInfo(place, method);
}
return true;
}
use of org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager in project intellij-community by JetBrains.
the class NamedDomainObjectCollectionTypeEnhancer method getReferenceType.
@Override
public PsiType getReferenceType(GrReferenceExpression ref, @Nullable PsiElement resolved) {
if (resolved != null)
return null;
GrExpression qualifierExpression = ref.getQualifierExpression();
if (qualifierExpression == null)
return null;
PsiType namedDomainCollectionType = GradleResolverUtil.getTypeOf(qualifierExpression);
if (!InheritanceUtil.isInheritor(namedDomainCollectionType, GradleCommonClassNames.GRADLE_API_NAMED_DOMAIN_OBJECT_COLLECTION)) {
return null;
}
PsiElement qResolved;
if (qualifierExpression instanceof GrReferenceExpression) {
qResolved = ((GrReferenceExpression) qualifierExpression).resolve();
} else if (qualifierExpression instanceof GrMethodCall) {
qResolved = ((GrMethodCall) qualifierExpression).resolveMethod();
} else {
return null;
}
String key = ref.getReferenceName();
if (key == null)
return null;
for (GroovyMapContentProvider provider : GroovyMapContentProvider.EP_NAME.getExtensions()) {
PsiType type = provider.getValueType(qualifierExpression, qResolved, key);
if (type != null) {
return type;
}
}
if (namedDomainCollectionType instanceof PsiClassReferenceType) {
final PsiClassReferenceType referenceType = (PsiClassReferenceType) namedDomainCollectionType;
final String fqName = TypesUtil.getQualifiedName(referenceType);
if (GradleCommonClassNames.GRADLE_API_SOURCE_SET_CONTAINER.equals(fqName)) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject());
return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_SOURCE_SET, ref.getResolveScope());
} else if (GradleCommonClassNames.GRADLE_API_CONFIGURATION_CONTAINER.equals(fqName)) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject());
return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_CONFIGURATION, ref.getResolveScope());
} else if (GradleCommonClassNames.GRADLE_API_TASK_CONTAINER.equals(fqName)) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject());
return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_TASK, ref.getResolveScope());
} else if (GradleCommonClassNames.GRADLE_API_DISTRIBUTION_CONTAINER.equals(fqName)) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject());
return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_DISTRIBUTION, ref.getResolveScope());
} else {
GradleExtensionsSettings.GradleExtensionsData extensionsData = GradleExtensionsContributor.Companion.getExtensionsFor(ref);
if (extensionsData != null) {
for (GradleExtensionsSettings.GradleExtension extension : extensionsData.extensions) {
if (StringUtil.isNotEmpty(extension.namedObjectTypeFqn) && extension.rootTypeFqn.equals(fqName)) {
final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject());
return psiManager.createTypeByFQClassName(extension.namedObjectTypeFqn, ref.getResolveScope());
}
}
}
}
}
return null;
}
Aggregations