Skip to content

Commit

Permalink
Fixup full resource resolution, and classpath resolution for preview …
Browse files Browse the repository at this point in the history
…screens.
  • Loading branch information
colinrgodsey committed Mar 30, 2023
1 parent 0908c61 commit 3094cf0
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package com.google.idea.blaze.android.projectsystem;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.android.ide.common.util.PathString;
import com.android.projectmodel.ExternalAndroidLibrary;
import com.android.projectmodel.ExternalLibraryImpl;
Expand All @@ -26,6 +24,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.idea.blaze.android.libraries.UnpackedAars;
import com.google.idea.blaze.android.manifest.ManifestParser;
import com.google.idea.blaze.android.sync.model.AarLibrary;
import com.google.idea.blaze.android.sync.model.AndroidResourceModuleRegistry;
import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
Expand All @@ -43,15 +42,20 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;

import static com.google.common.collect.ImmutableList.toImmutableList;

/** Blaze implementation of {@link AndroidModuleSystem}. */
public class BlazeModuleSystem extends BlazeModuleSystemBase {
Expand Down Expand Up @@ -162,14 +166,26 @@ static ExternalAndroidLibrary toExternalLibrary(
library.aarArtifact));
return null;
}

File resFolder = unpackedAars.getResourceDirectory(decoder, library);
PathString resFolderPathString = resFolder == null ? null : new PathString(resFolder);
PathString manifest = resFolderPathString == null
? null
: resFolderPathString.getParentOrRoot().resolve("AndroidManifest.xml");
String resourcePackage = library.resourcePackage;
if ((resourcePackage == null || resourcePackage == "") && manifest != null) {
try (InputStream is = new FileInputStream(manifest.toFile())) {
ManifestParser.ParsedManifest parsedManifest = ManifestParser.parseManifestFromInputStream(is);
resourcePackage = parsedManifest.packageName;
} catch (IOException ioe) {
logger.warn(
String.format("Could not parse package from manifest in library %s", aarFile.getName()));
return null;
}
}
return new ExternalLibraryImpl(library.key.toString())
.withLocation(new PathString(aarFile))
.withManifestFile(
resFolderPathString == null
? null
: resFolderPathString.getParentOrRoot().resolve("AndroidManifest.xml"))
.withManifestFile(manifest)
.withResFolder(
resFolderPathString == null
? null
Expand All @@ -178,7 +194,7 @@ static ExternalAndroidLibrary toExternalLibrary(
resFolderPathString == null
? null
: resFolderPathString.getParentOrRoot().resolve("R.txt"))
.withPackageName(library.resourcePackage);
.withPackageName(resourcePackage);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ public void registerDependency(GradleCoordinate coordinate, DependencyType type)
}
}

public void clearCache() {
classFileFinder.clearCache();
}

@Nullable
@Override
public GradleCoordinate getRegisteredDependency(GradleCoordinate coordinate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package com.google.idea.blaze.android.projectsystem;

import static java.util.stream.Collectors.joining;

import com.android.tools.idea.projectsystem.ClassFileFinder;
import com.android.tools.idea.projectsystem.ClassFileFinderUtil;
import com.google.common.annotations.VisibleForTesting;
Expand All @@ -25,6 +23,7 @@
import com.google.idea.blaze.android.libraries.RenderJarCache;
import com.google.idea.blaze.android.sync.model.AndroidResourceModule;
import com.google.idea.blaze.android.sync.model.AndroidResourceModuleRegistry;
import com.google.idea.blaze.android.sync.model.idea.BlazeClassJarProvider;
import com.google.idea.blaze.android.targetmaps.TargetToBinaryMap;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
Expand All @@ -34,6 +33,7 @@
import com.google.idea.blaze.base.sync.BlazeSyncModificationTracker;
import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.blaze.base.sync.projectstructure.ModuleFinder;
import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
Expand All @@ -42,9 +42,15 @@
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.jetbrains.annotations.Nullable;

import static java.util.stream.Collectors.joining;

/**
* A {@link ClassFileFinder} that uses deploy JAR like artifacts (called render jar henceforth) for
Expand All @@ -62,6 +68,8 @@
*
* <p>NOTE: Blaze targets that constitutes the resource module will be called "resource target(s)"
* in comments below.
*
* TODO: The role of this class has expanded beyond just render jar resolution. Should rename it.
*/
public class RenderJarClassFileFinder implements ClassFileFinder {
/** Experiment to control whether class file finding from render jars should be enabled. */
Expand All @@ -74,7 +82,7 @@ public class RenderJarClassFileFinder implements ClassFileFinder {
*/
@VisibleForTesting
static final BoolExperiment resolveResourceClasses =
new BoolExperiment("aswb.resolve.resources.render.jar", false);
new BoolExperiment("aswb.resolve.resources.render.jar", true); // needed for previews

private static final Logger log = Logger.getInstance(RenderJarClassFileFinder.class);

Expand All @@ -86,6 +94,8 @@ public class RenderJarClassFileFinder implements ClassFileFinder {
private final Module module;
private final Project project;

private final BlazeClassJarProvider blazeClassJarProvider;

// tracks the binary targets that depend resource targets
// will be recalculated after every sync
private ImmutableSet<TargetKey> binaryTargets = ImmutableSet.of();
Expand All @@ -98,9 +108,12 @@ public class RenderJarClassFileFinder implements ClassFileFinder {
// true if the current module is the .workspace Module
private final boolean isWorkspaceModule;

private Map<String, ModuleCache> moduleCache = new HashMap();

public RenderJarClassFileFinder(Module module) {
this.module = module;
this.project = module.getProject();
this.blazeClassJarProvider = new BlazeClassJarProvider(this.project);
this.isWorkspaceModule = BlazeDataStorage.WORKSPACE_MODULE_NAME.equals(module.getName());
}

Expand Down Expand Up @@ -169,14 +182,43 @@ public VirtualFile findClass(String fqcn) {
for (TargetKey binaryTarget : binaryTargets) {
VirtualFile classFile = getClassFromRenderResolveJar(projectData, fqcn, binaryTarget);
if (classFile != null) {
log.warn(String.format("Found class %s in target %s", fqcn, binaryTarget.toString()));
return classFile;
}
}

// TODO: look into BlazeLightResourceClassService?

VirtualFile moduleClass = findFQCNInModule(fqcn, this.module);
if (moduleClass == null) {
moduleClass = findFQCNInModule(fqcn, null);
}
if (moduleClass != null) {
return moduleClass;
}

log.warn(String.format("Could not find class `%1$s` (module: `%2$s`)", fqcn, module.getName()));
return null;
}

public synchronized void clearCache() {
log.debug("clearing cache");
moduleCache.clear();
}

private synchronized VirtualFile findFQCNInModule(String fqcn, @Nullable Module module) {
if (module == null) {
module = ModuleFinder.getInstance(this.project)
.findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME);
}
ModuleCache cache = moduleCache.get(module.getName());
if (cache == null) {
cache = new ModuleCache(module);
moduleCache.put(module.getName(), cache);
}
return cache.searchForFQCNInModule(fqcn);
}

@VisibleForTesting
static boolean isResourceClass(String fqcn) {
return RESOURCE_CLASS_NAME.matcher(fqcn).matches();
Expand Down Expand Up @@ -268,4 +310,43 @@ private static VirtualFile getJarRootForLocalFile(VirtualFile file) {
public static boolean isEnabled() {
return enabled.getValue();
}

private class ModuleCache {
private final List<File> moduleLibraries;
private Map<String, VirtualFile> packageJarHint = new HashMap();

private ModuleCache(Module module) {
moduleLibraries = blazeClassJarProvider.getModuleExternalLibraries(module);
}

@Nullable
private VirtualFile searchForFQCNInModule(String fqcn) {
String pkg = null;
int pkgIdx = fqcn.lastIndexOf('.');
if (pkgIdx != -1) {
pkg = fqcn.substring(0, pkgIdx);
}
VirtualFile hintJarVF = pkg == null ? null : packageJarHint.get(pkg);
if (hintJarVF != null) {
VirtualFile foundClass = findClassInJar(hintJarVF, fqcn);
if (foundClass != null) {
return foundClass;
}
}
for (File jar : moduleLibraries) {
VirtualFile jarVF = VirtualFileSystemProvider.getInstance().getSystem().findFileByIoFile(jar);
if (jarVF == null) {
continue;
}
VirtualFile foundClass = findClassInJar(jarVF, fqcn);
if (foundClass != null) {
if (pkg != null) {
packageJarHint.put(pkg, jarVF);
}
return foundClass;
}
}
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package com.google.idea.blaze.android.resources;

import static com.google.common.collect.ImmutableSet.toImmutableSet;

import com.android.tools.idea.projectsystem.LightResourceClassService;
import com.android.tools.idea.res.AndroidLightPackage;
import com.google.common.annotations.VisibleForTesting;
Expand All @@ -35,12 +33,15 @@
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.Nullable;

import static com.google.common.collect.ImmutableSet.toImmutableSet;

/** Implementation of {@link LightResourceClassService} set up at Blaze sync time. */
public class BlazeLightResourceClassService implements LightResourceClassService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,30 +469,6 @@ private String createAarLibrary(@NotNull TargetIdeInfo target) {

String libraryKey =
LibraryKey.libraryNameFromArtifactLocation(target.getAndroidAarIdeInfo().getAar());

//TODO: Should not be hardcoded, this is temp workaround, the package should be inferred properly, possibly from the manifest.xml?
if(target.toString().equals("@maven//:androidx_lifecycle_lifecycle_runtime")) {
resourcePackage = "androidx.lifecycle.runtime";
}
if(target.toString().equals("@maven//:androidx_savedstate_savedstate")) {
resourcePackage = "androidx.savedstate";
}
if(target.toString().equals("@maven//:androidx_lifecycle_lifecycle_viewmodel")) {
resourcePackage = "androidx.lifecycle.viewmodel";
}
if(target.toString().equals("@maven//:androidx_compose_ui_ui")) {
resourcePackage = "androidx.compose.ui";
}
if(target.toString().equals("@maven//:androidx_core_core")) {
resourcePackage = "androidx.core";
}
if(target.toString().equals("@maven//:androidx_constraintlayout_constraintlayout")) {
resourcePackage = "androidx.constraintlayout";
}
if(target.toString().equals("@maven//:androidx_appcompat_appcompat")) {
resourcePackage = "androidx.appcompat";
}

if (!aarLibraries.containsKey(libraryKey)) {
// aar_import should only have one jar (a merged jar from the AAR's jars).
LibraryArtifact firstJar = target.getJavaIdeInfo().getJars().iterator().next();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.android.tools.idea.model.ClassJarProvider;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.idea.blaze.android.libraries.RenderJarCache;
import com.google.idea.blaze.android.sync.model.AndroidResourceModuleRegistry;
import com.google.idea.blaze.android.targetmaps.TargetToBinaryMap;
Expand Down Expand Up @@ -194,7 +195,7 @@ public static boolean testIsClassFileOutOfDate(
}

List<File> getAllExternalLibraires(TargetMap targetMap, ArtifactLocationDecoder decoder) {
ImmutableList.Builder<File> results = ImmutableList.builder();
ImmutableSet.Builder<JavaIdeInfo> infos = ImmutableSet.builder();
for (TargetIdeInfo target : targetMap.targets()) {
for (TargetKey dependencyTargetKey :
TransitiveDependencyMap.getInstance(project).getTransitiveDependencies(target.getKey())) {
Expand All @@ -206,19 +207,28 @@ List<File> getAllExternalLibraires(TargetMap targetMap, ArtifactLocationDecoder
// Add all import jars as external libraries.
JavaIdeInfo javaIdeInfo = dependencyTarget.getJavaIdeInfo();
if (javaIdeInfo != null) {
for (LibraryArtifact jar : javaIdeInfo.getJars()) {
ArtifactLocation classJar = jar.getClassJar();
if (classJar != null) {
results.add(
Preconditions.checkNotNull(
OutputArtifactResolver.resolve(project, decoder, classJar),
"Fail to find file %s",
classJar.getRelativePath()));
}
}
infos.add(javaIdeInfo);
}
}
JavaIdeInfo javaIdeInfo = target.getJavaIdeInfo();
if (javaIdeInfo != null) {
infos.add(javaIdeInfo);
}
}
ImmutableList.Builder<File> results = ImmutableList.builder();
for (JavaIdeInfo javaIdeInfo : infos.build()) {
for (LibraryArtifact jar : javaIdeInfo.getJars()) {
ArtifactLocation classJar = jar.getClassJar();
if (classJar != null) {
results.add(
Preconditions.checkNotNull(
OutputArtifactResolver.resolve(project, decoder, classJar),
"Fail to find file %s",
classJar.getRelativePath()));
}
}
}

return results.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.google.common.util.concurrent.MoreExecutors;
import com.google.idea.blaze.android.manifest.ManifestParser;
import com.google.idea.blaze.android.manifest.ParsedManifestService;
import com.google.idea.blaze.android.projectsystem.BlazeModuleSystem;
import com.google.idea.blaze.android.projectview.GeneratedAndroidResourcesSection;
import com.google.idea.blaze.android.resources.BlazeLightResourceClassService;
import com.google.idea.blaze.android.sync.importer.BlazeAndroidWorkspaceImporter;
Expand Down Expand Up @@ -358,6 +359,7 @@ private static void updateInMemoryState(
configAndroidJava8Libs);
rClassBuilder.addRClass(modulePackage, module);
sourcePackages.remove(modulePackage);
BlazeModuleSystem.getInstance(module).clearCache();
}

rClassBuilder.addWorkspacePackages(sourcePackages);
Expand Down

0 comments on commit 3094cf0

Please sign in to comment.