Search in sources :

Example 1 with GroovyPsiManager

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;
}
Also used : GroovyPsiManager(org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager)

Example 2 with GroovyPsiManager

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;
}
Also used : GrMethodCall(org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall) GroovyPsiManager(org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager) GrExpression(org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression) GroovyMapContentProvider(org.jetbrains.plugins.groovy.extensions.GroovyMapContentProvider) PsiElement(com.intellij.psi.PsiElement) PsiClassReferenceType(com.intellij.psi.impl.source.PsiClassReferenceType) PsiType(com.intellij.psi.PsiType) GrReferenceExpression(org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression)

Aggregations

GroovyPsiManager (org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager)2 PsiElement (com.intellij.psi.PsiElement)1 PsiType (com.intellij.psi.PsiType)1 PsiClassReferenceType (com.intellij.psi.impl.source.PsiClassReferenceType)1 GroovyMapContentProvider (org.jetbrains.plugins.groovy.extensions.GroovyMapContentProvider)1 GrExpression (org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression)1 GrMethodCall (org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall)1 GrReferenceExpression (org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression)1