diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 882b7c7d4..8544f6138 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -43,6 +43,7 @@
+
diff --git a/app/src/main/assets/data/common/tooling-api-all.jar b/app/src/main/assets/data/common/tooling-api-all.jar
index d744ce9d3..a6df2085e 100644
Binary files a/app/src/main/assets/data/common/tooling-api-all.jar and b/app/src/main/assets/data/common/tooling-api-all.jar differ
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt
index e0b2afce6..f97cbea6d 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt
@@ -75,7 +75,7 @@ object FileManager : EventReceiver {
fun getReader(file: Path): BufferedReader {
val document = getActiveDocument(file)
if (document != null) {
- return document.content.reader().buffered()
+ return document.reader()
}
return createFileReader(file)
@@ -84,7 +84,7 @@ object FileManager : EventReceiver {
fun getInputStream(file: Path): InputStream {
val document = getActiveDocument(file)
if (document != null) {
- return document.content.byteInputStream().buffered()
+ return document.inputStream()
}
return createFileInputStream(file)
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt
index 25d2f714c..1e5b9bcf6 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt
@@ -19,12 +19,12 @@ package com.itsaky.androidide.projects.api
import android.text.TextUtils
import com.itsaky.androidide.tooling.api.model.GradleTask
-import com.itsaky.androidide.utils.ClassTrie
+import com.itsaky.androidide.utils.BootClasspathProvider
import com.itsaky.androidide.utils.ClasspathReader
import com.itsaky.androidide.utils.DocumentUtils
import com.itsaky.androidide.utils.ILogger
-import com.itsaky.androidide.utils.SourceClassTrie
import com.itsaky.androidide.utils.SourceClassTrie.SourceNode
+import com.itsaky.androidide.utils.StopWatch
import java.io.File
import java.nio.file.Path
@@ -97,6 +97,7 @@ abstract class ModuleProject(
fun indexSourcesAndClasspaths() {
log.info("Indexing sources and classpaths for project:", path)
+ var watch = StopWatch("Indexing sources")
var count = 0
getCompileSourceDirectories().forEach {
val sourceDir = it.toPath()
@@ -110,12 +111,20 @@ abstract class ModuleProject(
}
}
- log.debug("Sources indexed for project: '$path'. Found $count source files.")
+ watch.log()
+ log.debug("Found $count source files.")
+ watch = StopWatch("Indexing classpaths")
val paths = getCompileClasspaths().filter { it.exists() }
- val topLevelClasses = com.itsaky.androidide.utils.ClasspathReader.listClasses(paths).filter { it.isTopLevel }
+ val topLevelClasses = ClasspathReader.listClasses(paths).filter { it.isTopLevel }
topLevelClasses.forEach { this.compileClasspathClasses.append(it.name) }
- log.debug("Classpaths indexed for project: '$path'. Found ${topLevelClasses.size} classpaths.")
+
+ watch.log()
+ log.debug("Found ${topLevelClasses.size} classpaths.")
+
+ if (this is AndroidModule) {
+ BootClasspathProvider.update(bootClassPaths.map { it.path })
+ }
}
fun getSourceFilesInDir(dir: Path): List =
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt
index 7571e7a81..b1412ff74 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveDocument.kt
@@ -18,6 +18,9 @@
package com.itsaky.androidide.projects.models
import com.itsaky.androidide.models.Range
+import com.itsaky.androidide.utils.DocumentUtils
+import java.io.BufferedInputStream
+import java.io.BufferedReader
import java.nio.file.Path
import java.time.Instant
@@ -33,4 +36,32 @@ open class ActiveDocument(
var changDelta: Int,
val version: Int,
val modified: Instant
-)
+) {
+
+ companion object {
+
+ @JvmStatic
+ fun create(
+ file: Path,
+ content: String,
+ changeRange: Range,
+ changDelta: Int,
+ version: Int,
+ modified: Instant
+ ): ActiveDocument {
+ if (DocumentUtils.isJavaFile(file)) {
+ return ActiveJavaDocument(file, content, changeRange, changDelta, version, modified)
+ }
+
+ return ActiveDocument(file, content, changeRange, changDelta, version, modified)
+ }
+ }
+
+ fun inputStream(): BufferedInputStream {
+ return content.byteInputStream().buffered()
+ }
+
+ fun reader(): BufferedReader {
+ return content.reader().buffered()
+ }
+}
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveJavaDocument.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveJavaDocument.kt
new file mode 100644
index 000000000..a36043429
--- /dev/null
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/models/ActiveJavaDocument.kt
@@ -0,0 +1,40 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.projects.models
+
+import com.itsaky.androidide.models.Range
+import com.itsaky.androidide.projects.util.StringSearch
+import java.nio.file.Path
+import java.time.Instant
+
+/**
+ * An active java document.
+ *
+ * @author Akash Yadav
+ */
+class ActiveJavaDocument(
+ file: Path,
+ content: String,
+ changeRange: Range,
+ changDelta: Int,
+ version: Int,
+ modified: Instant
+) : ActiveDocument(file, content, changeRange, changDelta, version, modified) {
+
+ val packageName: String = StringSearch.packageName(reader())
+}
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java
index 0695b4cd1..b2fa2698f 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java
@@ -17,8 +17,10 @@
package com.itsaky.androidide.projects.util;
+import androidx.annotation.Nullable;
+
import com.itsaky.androidide.projects.FileManager;
-import com.itsaky.androidide.projects.models.ActiveDocument;
+import com.itsaky.androidide.projects.models.ActiveJavaDocument;
import com.itsaky.androidide.utils.Cache;
import java.io.BufferedReader;
@@ -33,7 +35,6 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
import java.util.logging.Logger;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
// Translated from https://golang.org/src/strings/search.go
@@ -44,9 +45,12 @@ import java.util.regex.Pattern;
// https://www.cs.utexas.edu/~moore/publications/fstrpos.pdf (note: this aged
// document uses 1-based indexing)
public class StringSearch {
+ private static final ByteBuffer SEARCH_BUFFER = ByteBuffer.allocateDirect(1024 * 1024);
+ private static final Logger LOG = Logger.getLogger("main");
+ private static final Cache cacheContainsClass = new Cache<>();
+ private static final Cache cacheContainsInterface = new Cache<>();
// pattern is the string that we are searching for in the text.
private final byte[] pattern;
-
// badCharSkip[b] contains the distance between the last byte of pattern
// and the rightmost occurrence of b in pattern. If b is not in pattern,
// badCharSkip[b] is len(pattern).
@@ -56,7 +60,6 @@ public class StringSearch {
// the matching char could be in alignment.
// TODO 256 is not coloring
private final int[] badCharSkip = new int[256];
-
// goodSuffixSkip[i] defines how far we can shift the matching frame given
// that the suffix pattern[i+1:] matches, but the byte pattern[i] does
// not. There are two cases to consider:
@@ -115,72 +118,6 @@ public class StringSearch {
}
}
- public int next(String text) {
- return next(text.getBytes());
- }
-
- private int next(byte[] text) {
- return next(ByteBuffer.wrap(text));
- }
-
- private int next(ByteBuffer text) {
- return next(text, 0);
- }
-
- private int next(ByteBuffer text, int startingAfter) {
- int i = startingAfter + pattern.length - 1;
- while (i < text.limit()) {
- // Compare backwards from the end until the first unmatching character.
- int j = pattern.length - 1;
- while (j >= 0 && text.get(i) == pattern[j]) {
- i--;
- j--;
- }
- if (j < 0) {
- return i + 1; // match
- }
- i += Math.max(badCharSkip[text.get(i) + 128], goodSuffixSkip[j]);
- }
- return -1;
- }
-
- private boolean isWordChar(byte b) {
- char c = (char) (b + 128);
- return Character.isAlphabetic(c) || Character.isDigit(c) || c == '$' || c == '_';
- }
-
- private boolean startsWord(ByteBuffer text, int offset) {
- if (offset == 0) return true;
- return !isWordChar(text.get(offset - 1));
- }
-
- private boolean endsWord(ByteBuffer text, int offset) {
- if (offset + 1 >= text.limit()) return true;
- return !isWordChar(text.get(offset + 1));
- }
-
- private boolean isWord(ByteBuffer text, int offset) {
- return startsWord(text, offset) && endsWord(text, offset + pattern.length - 1);
- }
-
- public int nextWord(String text) {
- return nextWord(text.getBytes());
- }
-
- private int nextWord(byte[] text) {
- return nextWord(ByteBuffer.wrap(text));
- }
-
- private int nextWord(ByteBuffer text) {
- int i = 0;
- while (true) {
- i = next(text, i);
- if (i == -1) return -1;
- if (isWord(text, i)) return i;
- i++;
- }
- }
-
private boolean hasPrefix(byte[] s, Slice prefix) {
for (int i = 0; i < prefix.length(); i++) {
if (s[i] != prefix.get(i)) return false;
@@ -198,17 +135,6 @@ public class StringSearch {
return i;
}
- private static final ByteBuffer SEARCH_BUFFER = ByteBuffer.allocateDirect(1024 * 1024);
-
- private static String tryGetActiveDocContent(Path file) {
- final ActiveDocument document = FileManager.INSTANCE.getActiveDocument(file);
- if (document != null) {
- return document.getContent();
- }
-
- return null;
- }
-
// TODO cache the progress made by searching shorter queries
public static boolean containsWordMatching(Path java, String query) {
String text = tryGetActiveDocContent(java);
@@ -232,48 +158,14 @@ public class StringSearch {
}
}
- public static boolean containsWord(Path java, String query) {
- StringSearch search = new StringSearch(query);
- String text = tryGetActiveDocContent(java);
- if (text != null) {
- return search.nextWord(text.getBytes()) != -1;
+ @Nullable
+ private static String tryGetActiveDocContent(Path file) {
+ final var doc = FileManager.INSTANCE.getActiveDocument(file);
+ if (doc != null) {
+ return doc.getContent();
}
- try (FileChannel channel = FileChannel.open(java)) {
- // Read up to 1 MB of data from file
- int limit = Math.min((int) channel.size(), SEARCH_BUFFER.capacity());
- SEARCH_BUFFER.position(0);
- SEARCH_BUFFER.limit(limit);
- channel.read(SEARCH_BUFFER);
- SEARCH_BUFFER.position(0);
- return search.nextWord(SEARCH_BUFFER) != -1;
- } catch (NoSuchFileException e) {
- LOG.warning(e.getMessage());
- return false;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- private static boolean containsString(Path java, String query) {
- StringSearch search = new StringSearch(query);
- String text = tryGetActiveDocContent(java);
- if (text != null) {
- return search.next(text.getBytes()) != -1;
- }
- try (FileChannel channel = FileChannel.open(java)) {
- // Read up to 1 MB of data from file
- int limit = Math.min((int) channel.size(), SEARCH_BUFFER.capacity());
- SEARCH_BUFFER.position(0);
- SEARCH_BUFFER.limit(limit);
- channel.read(SEARCH_BUFFER);
- SEARCH_BUFFER.position(0);
- return search.next(SEARCH_BUFFER) != -1;
- } catch (NoSuchFileException e) {
- LOG.warning(e.getMessage());
- return false;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ return null;
}
/**
@@ -330,7 +222,27 @@ public class StringSearch {
return Character.isAlphabetic(c) || Character.isDigit(c) || c == '_' || c == '$';
}
- private static Cache cacheContainsClass = new Cache<>();
+ public static boolean containsWord(Path java, String query) {
+ StringSearch search = new StringSearch(query);
+ String text = tryGetActiveDocContent(java);
+ if (text != null) {
+ return search.nextWord(text.getBytes()) != -1;
+ }
+ try (FileChannel channel = FileChannel.open(java)) {
+ // Read up to 1 MB of data from file
+ int limit = Math.min((int) channel.size(), SEARCH_BUFFER.capacity());
+ SEARCH_BUFFER.position(0);
+ SEARCH_BUFFER.limit(limit);
+ channel.read(SEARCH_BUFFER);
+ SEARCH_BUFFER.position(0);
+ return search.nextWord(SEARCH_BUFFER) != -1;
+ } catch (NoSuchFileException e) {
+ LOG.warning(e.getMessage());
+ return false;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
public static boolean containsClass(Path file, String simpleName) {
if (cacheContainsClass.needs(file, simpleName)) {
@@ -340,8 +252,6 @@ public class StringSearch {
return cacheContainsClass.get(file, simpleName);
}
- private static Cache cacheContainsInterface = new Cache<>();
-
public static boolean containsInterface(Path file, String simpleName) {
if (cacheContainsInterface.needs(file, simpleName)) {
cacheContainsInterface.load(
@@ -371,12 +281,24 @@ public class StringSearch {
}
public static String packageName(Path file) {
- Pattern packagePattern = Pattern.compile("^package +(.*);");
- Pattern startOfClass = Pattern.compile("^[\\w ]*class +\\w+");
- try (BufferedReader lines = FileManager.INSTANCE.getReader(file)) {
- for (String line = lines.readLine(); line != null; line = lines.readLine()) {
- if (startOfClass.matcher(line).find()) return "";
- Matcher matchPackage = packagePattern.matcher(line);
+ final var doc = FileManager.INSTANCE.getActiveDocument(file);
+ if (doc instanceof ActiveJavaDocument) {
+ return ((ActiveJavaDocument) doc).getPackageName();
+ }
+
+ return packageName(FileManager.INSTANCE.getReader(file));
+ }
+
+ public static String packageName(final BufferedReader reader) {
+ try (reader) {
+ final var packagePattern = Pattern.compile("^package +(.*);");
+ final var startOfClass = Pattern.compile("^[\\w ]*class +\\w+");
+ for (var line = reader.readLine(); line != null; line = reader.readLine()) {
+ if (startOfClass.matcher(line).find()) {
+ return "";
+ }
+
+ final var matchPackage = packagePattern.matcher(line);
if (matchPackage.matches()) {
return matchPackage.group(1);
}
@@ -384,6 +306,7 @@ public class StringSearch {
} catch (IOException e) {
throw new RuntimeException(e);
}
+
// TODO fall back on parsing file
return "";
}
@@ -410,18 +333,98 @@ public class StringSearch {
return cursor + column;
}
+ private static boolean containsString(Path java, String query) {
+ StringSearch search = new StringSearch(query);
+ String text = tryGetActiveDocContent(java);
+ if (text != null) {
+ return search.next(text.getBytes()) != -1;
+ }
+ try (FileChannel channel = FileChannel.open(java)) {
+ // Read up to 1 MB of data from file
+ int limit = Math.min((int) channel.size(), SEARCH_BUFFER.capacity());
+ SEARCH_BUFFER.position(0);
+ SEARCH_BUFFER.limit(limit);
+ channel.read(SEARCH_BUFFER);
+ SEARCH_BUFFER.position(0);
+ return search.next(SEARCH_BUFFER) != -1;
+ } catch (NoSuchFileException e) {
+ LOG.warning(e.getMessage());
+ return false;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int next(String text) {
+ return next(text.getBytes());
+ }
+
+ private int next(byte[] text) {
+ return next(ByteBuffer.wrap(text));
+ }
+
+ private int next(ByteBuffer text) {
+ return next(text, 0);
+ }
+
+ private int next(ByteBuffer text, int startingAfter) {
+ int i = startingAfter + pattern.length - 1;
+ while (i < text.limit()) {
+ // Compare backwards from the end until the first unmatching character.
+ int j = pattern.length - 1;
+ while (j >= 0 && text.get(i) == pattern[j]) {
+ i--;
+ j--;
+ }
+ if (j < 0) {
+ return i + 1; // match
+ }
+ i += Math.max(badCharSkip[text.get(i) + 128], goodSuffixSkip[j]);
+ }
+ return -1;
+ }
+
+ public int nextWord(String text) {
+ return nextWord(text.getBytes());
+ }
+
+ private int nextWord(byte[] text) {
+ return nextWord(ByteBuffer.wrap(text));
+ }
+
+ private int nextWord(ByteBuffer text) {
+ int i = 0;
+ while (true) {
+ i = next(text, i);
+ if (i == -1) return -1;
+ if (isWord(text, i)) return i;
+ i++;
+ }
+ }
+
+ private boolean isWord(ByteBuffer text, int offset) {
+ return startsWord(text, offset) && endsWord(text, offset + pattern.length - 1);
+ }
+
+ private boolean startsWord(ByteBuffer text, int offset) {
+ if (offset == 0) return true;
+ return !isWordChar(text.get(offset - 1));
+ }
+
+ private boolean isWordChar(byte b) {
+ char c = (char) (b + 128);
+ return Character.isAlphabetic(c) || Character.isDigit(c) || c == '$' || c == '_';
+ }
+
+ private boolean endsWord(ByteBuffer text, int offset) {
+ if (offset + 1 >= text.limit()) return true;
+ return !isWordChar(text.get(offset + 1));
+ }
+
private static class Slice {
private final byte[] target;
private int from, until;
- int length() {
- return until - from;
- }
-
- byte get(int i) {
- return target[from + i];
- }
-
Slice(byte[] target, int from) {
this(target, from, target.length);
}
@@ -431,7 +434,13 @@ public class StringSearch {
this.from = from;
this.until = until;
}
- }
- private static final Logger LOG = Logger.getLogger("main");
+ int length() {
+ return until - from;
+ }
+
+ byte get(int i) {
+ return target[from + i];
+ }
+ }
}
diff --git a/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java b/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java
index 4972cb6c8..e609a402c 100644
--- a/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java
+++ b/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java
@@ -141,11 +141,22 @@ public class ProjectReader {
builder.setProjectType(type);
final var module = builder.buildAndroidModule();
+ tryFillNamespaces(android, module);
addTasks(gradle, module);
return module;
}
+ private static void tryFillNamespaces(final AndroidProject android, final AndroidModule module) {
+ try {
+ module.setNamespace(android.getNamespace());
+ module.setAndroidTestNamespace(android.getAndroidTestNamespace());
+ module.setTestFixturesNamespace(android.getTestFixturesNamespace());
+ } catch (Throwable err) {
+ log("Unable to get namespaces of module: '" + module.projectPath + "'.", err.getMessage());
+ }
+ }
+
private static void addTasks(GradleProject gradle, IdeGradleProject project) {
for (final var task : gradle.getTasks()) {
project.tasks.add(buildGradleTaskModel(project, task));
diff --git a/build-tools/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/model/AndroidModule.kt b/build-tools/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/model/AndroidModule.kt
index 22bef3719..7e113f433 100644
--- a/build-tools/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/model/AndroidModule.kt
+++ b/build-tools/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/model/AndroidModule.kt
@@ -29,11 +29,11 @@ import com.itsaky.androidide.builder.model.DefaultViewBindingOptions
import com.itsaky.androidide.tooling.api.IProject.Type
import com.itsaky.androidide.tooling.api.IProject.Type.Android
import com.itsaky.androidide.tooling.api.messages.result.SimpleVariantData
+import org.eclipse.lemminx.dom.DOMParser
+import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager
import java.io.File
import java.io.Serializable
import java.util.concurrent.*
-import org.eclipse.lemminx.dom.DOMParser
-import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager
/**
* Default implementation of [AndroidProject].
@@ -180,6 +180,13 @@ open class AndroidModule(
}
private fun findPackageName() {
+
+ if (this.namespace.isNotBlank()) {
+ this.packageName = namespace
+ this.shouldLookupPackage = false
+ return
+ }
+
if (mainSourceSet == null) {
shouldLookupPackage = false
return
@@ -197,10 +204,14 @@ open class AndroidModule(
val manifest = document.children.first { it.nodeName == "manifest" }
if (manifest == null) {
shouldLookupPackage = false
+ return
}
val packageAttr = manifest.attributes.getNamedItem("package")
- this.packageName = packageAttr.nodeValue
+ if (packageAttr != null) {
+ this.packageName = packageAttr.nodeValue
+ }
+
this.shouldLookupPackage = false
}
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java
index 593eb456c..ed72326b2 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java
@@ -95,7 +95,7 @@ public class CompileBatch implements AutoCloseable {
}
void updatePositions(CompilationUnitTree tree, boolean allowDuplicate) {
- final StopWatch positionWatch = new StopWatch("Scan method positions");
+ final StopWatch watch = new StopWatch("Scan method positions");
final List> positions = new ArrayList<>();
new MethodRangeScanner(this.task).scan(tree, positions);
final String path = new File(tree.getSourceFile().toUri()).getAbsolutePath();
@@ -105,7 +105,7 @@ public class CompileBatch implements AutoCloseable {
"Duplicate CompilationUnitTree for file:" + tree.getSourceFile().toUri());
}
- positionWatch.log();
+ watch.log();
}
private ReusableCompiler.Borrow batchTask(
diff --git a/shared/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java b/shared/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java
index 76a5b5487..0ebc53c17 100644
--- a/shared/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java
+++ b/shared/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java
@@ -44,7 +44,7 @@ public class BootClasspathProvider {
* the cache.
*/
public static synchronized boolean update(Collection classpaths) {
- final var start = System.currentTimeMillis();
+ final var watch = new StopWatch("Indexing " + classpaths.size() + " bootclasspaths");
var count = 0;
for (final var classpath : classpaths) {
if (bootClasspathClasses.containsKey(classpath)) {
@@ -67,8 +67,7 @@ public class BootClasspathProvider {
count += classes.size();
}
- LOG.info(
- "Indexed", count, "boot classpath classes in", System.currentTimeMillis() - start, "ms");
+ watch.log();
return count > 0;
}
diff --git a/tests/test-home/.androidide/init/model.jar b/tests/test-home/.androidide/init/model.jar
index 7471622eb..8a698a9cc 100644
Binary files a/tests/test-home/.androidide/init/model.jar and b/tests/test-home/.androidide/init/model.jar differ