in android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java [182:284]
public Collection<? extends ResourceValue> getVariants(@NotNull ConvertContext context) {
Module module = context.getModule();
if (module == null || module.isDisposed()) return Collections.emptySet();
AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet == null) return Collections.emptySet();
Set<ResourceValue> result = new HashSet<>();
Set<ResourceType> recommendedTypes = getResourceTypes(context);
if (recommendedTypes.contains(ResourceType.BOOL) && recommendedTypes.size() < VALUE_RESOURCE_TYPES.size()) {
// Is this resource reference expected to be a @bool reference? Specifically
// check that it's not allowed to be *all* resource types since that's a fallback
// for when we don't have metadata, and we don't want to show true and false
// as possible completions for things like com.google.android.gms.version
result.add(ResourceValue.literal(VALUE_TRUE));
result.add(ResourceValue.literal(VALUE_FALSE));
}
// hack to check if it is a real id attribute
if (recommendedTypes.contains(ResourceType.ID) && recommendedTypes.size() == 1) {
result.add(ResourceValue.reference(NEW_ID_PREFIX));
}
XmlElement element = context.getXmlElement();
if (element == null) return result;
String value = getValue(element);
assert value != null;
boolean startsWithRefChar = StringUtil.startsWithChar(value, '@');
if (!myQuiet || startsWithRefChar) {
ResourceNamespace namespace = null;
String namespacePrefix = null;
// Retrieve the system prefix depending on the prefix settings ("@android:" or "android:")
Matcher matcher = (myWithPrefix ? PREFIX_NAMESPACE_COLON : NAMESPACE_COLON).matcher(value);
if (matcher.matches()) {
ResourceNamespaceContext namespacesContext = IdeResourcesUtil.getNamespacesContext(element);
namespacePrefix = matcher.group(1);
if (namespacesContext != null) {
namespace = ResourceNamespace.fromNamespacePrefix(namespacePrefix,
namespacesContext.getCurrentNs(),
namespacesContext.getResolver());
} else {
namespace = ResourceNamespace.fromPackageName(namespacePrefix);
}
}
else {
// We don't offer framework resources in completion, unless the string already starts with the framework namespace. But we do offer
// the right prefix, which will cause the framework resources to show up as follow-up completion. These variants are later handled
// in createLookupElement below.
ResourceNamespace.Resolver resolver = IdeResourcesUtil.getNamespaceResolver(element);
String frameworkPrefix = firstNonNull(resolver.uriToPrefix(ResourceNamespace.ANDROID.getXmlNamespaceUri()),
ResourceNamespace.ANDROID.getPackageName());
result.add(ResourceValue.literal(myWithPrefix || startsWithRefChar
? '@' + frameworkPrefix + ':'
: frameworkPrefix + ':'));
}
char prefix = myWithPrefix || startsWithRefChar ? '@' : 0;
if (value.startsWith(NEW_ID_PREFIX)) {
addVariantsForIdDeclaration(context, facet, prefix, value, result);
}
if (myExpandedCompletionSuggestion) {
// We will add the resource type (e.g. @style/) if the current value starts like a reference using @
boolean explicitResourceType = startsWithRefChar || myWithExplicitResourceType;
for (ResourceType type : recommendedTypes) {
// If getResourceTypes decided SAMPLE_DATA belongs here, then this is one of the few exceptions where it can be referenced.
if (type.getCanBeReferenced() || type == ResourceType.SAMPLE_DATA) {
addResourceReferenceValues(facet, element, prefix, type, namespace, result, explicitResourceType, myIncludeDynamicFeatures);
}
}
}
else {
Set<ResourceType> filteringSet =
namespace == ResourceNamespace.ANDROID ? EnumSet.allOf(ResourceType.class) : getResourceTypesInCurrentModule(facet);
for (ResourceType resourceType : ResourceType.values()) {
if (!resourceType.getCanBeReferenced()) {
continue;
}
String typePrefix = getTypePrefix(namespacePrefix, resourceType);
if (value.startsWith(typePrefix)) {
addResourceReferenceValues(facet, element, prefix, resourceType, namespace, result, true, myIncludeDynamicFeatures);
}
else if (recommendedTypes.contains(resourceType) && filteringSet.contains(resourceType)) {
result.add(ResourceValue.literal(typePrefix));
}
}
}
}
if (myAllowAttributeReferences) {
completeAttributeReferences(value, facet, result);
}
ResolvingConverter<String> additionalConverter = getAdditionalConverter(context);
if (additionalConverter != null) {
for (String variant : additionalConverter.getVariants(context)) {
result.add(ResourceValue.literal(variant));
}
}
return result;
}