blob: c6075392b89195f8cb0b93e734380788d0bee653 [file] [log] [blame]
package org.jetbrains.android.augment;
import com.android.resources.ResourceType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbService;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.source.PsiExtensibleClass;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.dom.converters.ResourceReferenceConverter;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidPsiAugmentProvider extends PsiAugmentProvider {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.augment.AndroidPsiAugmentProvider");
@SuppressWarnings("unchecked")
@NotNull
@Override
public <Psi extends PsiElement> List<Psi> getAugments(@NotNull PsiElement element, @NotNull Class<Psi> type) {
if ((type != PsiClass.class && type != PsiField.class) ||
!(element instanceof PsiExtensibleClass)) {
return Collections.emptyList();
}
final PsiExtensibleClass aClass = (PsiExtensibleClass)element;
final String className = aClass.getName();
final boolean rClassAugment = AndroidUtils.R_CLASS_NAME.equals(className)
&& type == PsiClass.class;
if (DumbService.isDumb(element.getProject())) {
if (rClassAugment) {
LOG.debug("R_CLASS_AUGMENT: empty because of dumb mode");
}
return Collections.emptyList();
}
final AndroidFacet facet = AndroidFacet.getInstance(element);
if (facet == null) {
if (rClassAugment) {
LOG.debug("R_CLASS_AUGMENT: empty because no facet");
}
return Collections.emptyList();
}
final PsiFile containingFile = element.getContainingFile();
if (containingFile == null) {
if (rClassAugment) {
LOG.debug("R_CLASS_AUGMENT: empty because of no containing file");
}
return Collections.emptyList();
}
if (type == PsiClass.class) {
if (AndroidUtils.R_CLASS_NAME.equals(className) &&
AndroidResourceUtil.isRJavaFile(facet, containingFile)) {
final Set<String> existingInnerClasses = getOwnInnerClasses(aClass);
final Set<String> types = ResourceReferenceConverter.getResourceTypesInCurrentModule(facet);
final List<Psi> result = new ArrayList<Psi>();
for (String resType : types) {
if (!existingInnerClasses.contains(resType)) {
final AndroidLightClass resClass = new ResourceTypeClass(facet, resType, aClass);
result.add((Psi)resClass);
}
}
if (rClassAugment) {
LOG.debug("R_CLASS_AUGMENT: " + result.size() + " classes added");
}
return result;
}
else if (AndroidUtils.MANIFEST_CLASS_NAME.equals(className) &&
AndroidResourceUtil.isManifestJavaFile(facet, containingFile)) {
return Arrays.asList((Psi)new PermissionClass(facet, aClass),
(Psi)new PermissionGroupClass(facet, aClass));
}
if (rClassAugment) {
LOG.debug("R_CLASS_AUGMENT: empty because containing file is not actual R.java file");
}
}
else if (type == PsiField.class && !(aClass instanceof AndroidLightClass)) {
// extend existing inner classes, not provided by this augment (ex. they can be generated by maven)
final PsiClass parentClass = aClass.getContainingClass();
if (parentClass != null &&
AndroidUtils.R_CLASS_NAME.equals(parentClass.getName()) &&
AndroidResourceUtil.isRJavaFile(facet, containingFile)) {
final String resClassName = aClass.getName();
if (resClassName != null && ResourceType.getEnum(resClassName) != null) {
final Set<String> existingFields = getOwnFields(aClass);
final PsiField[] newFields = ResourceTypeClass.buildLocalResourceFields(facet, resClassName, aClass);
final List<Psi> result = new ArrayList<Psi>();
for (PsiField field : newFields) {
if (!existingFields.contains(field.getName())) {
result.add((Psi)field);
}
}
return result;
}
}
}
return Collections.emptyList();
}
@NotNull
private static Set<String> getOwnInnerClasses(@NotNull PsiExtensibleClass aClass) {
final Set<String> result = new HashSet<String>();
for (PsiClass innerClass : aClass.getOwnInnerClasses()) {
result.add(innerClass.getName());
}
return result;
}
@NotNull
private static Set<String> getOwnFields(@NotNull PsiExtensibleClass aClass) {
final Set<String> result = new HashSet<String>();
for (PsiField field : aClass.getOwnFields()) {
result.add(field.getName());
}
return result;
}
}