mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Added test for 'Add import' action
This commit is contained in:
@@ -25,10 +25,12 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.blankj.utilcode.util.ThreadUtils;
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
@@ -59,12 +61,11 @@ import com.itsaky.lsp.models.ShowDocumentParams;
|
||||
import com.itsaky.lsp.models.SignatureHelp;
|
||||
import com.itsaky.lsp.models.SignatureHelpParams;
|
||||
import com.itsaky.lsp.util.DiagnosticUtil;
|
||||
import com.itsaky.lsp.util.PathUtils;
|
||||
import com.itsaky.toaster.Toaster;
|
||||
import io.github.rosemoe.sora.event.ContentChangeEvent;
|
||||
import io.github.rosemoe.sora.event.SelectionChangeEvent;
|
||||
import io.github.rosemoe.sora.event.Unsubscribe;
|
||||
import io.github.rosemoe.sora.widget.CodeEditor;
|
||||
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -73,7 +74,12 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import io.github.rosemoe.sora.event.ContentChangeEvent;
|
||||
import io.github.rosemoe.sora.event.SelectionChangeEvent;
|
||||
import io.github.rosemoe.sora.event.Unsubscribe;
|
||||
import io.github.rosemoe.sora.widget.CodeEditor;
|
||||
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion;
|
||||
|
||||
public class IDEEditor extends CodeEditor {
|
||||
|
||||
@@ -432,7 +438,8 @@ public class IDEEditor extends CodeEditor {
|
||||
() -> {
|
||||
if (locations.size() == 1) {
|
||||
var location = locations.get(0);
|
||||
if (location.getFile().equals(getFile().toPath())) {
|
||||
if (PathUtils.isSameFile(
|
||||
location.getFile(), getFile().toPath())) {
|
||||
setSelection(location.getRange());
|
||||
return;
|
||||
}
|
||||
@@ -516,7 +523,7 @@ public class IDEEditor extends CodeEditor {
|
||||
} else {
|
||||
if (result.getLocations().size() == 1) {
|
||||
final var loc = result.getLocations().get(0);
|
||||
if (loc.getFile().equals(getFile().toPath())) {
|
||||
if (PathUtils.isSameFile(loc.getFile(), getFile().toPath())) {
|
||||
setSelection(loc.getRange());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.lsp.util
|
||||
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class PathUtils {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun isSameFile(first: Path, second: Path): Boolean {
|
||||
return try {
|
||||
Files.isSameFile(first, second)
|
||||
} catch (e: IOException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.itsaky.lsp.java;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.itsaky.androidide.utils.CharSequenceInputStream;
|
||||
import com.itsaky.androidide.utils.CharSequenceReader;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
@@ -9,6 +11,8 @@ import com.itsaky.lsp.java.utils.StringSearch;
|
||||
import com.itsaky.lsp.models.DocumentChangeEvent;
|
||||
import com.itsaky.lsp.models.DocumentCloseEvent;
|
||||
import com.itsaky.lsp.models.DocumentOpenEvent;
|
||||
import com.itsaky.lsp.util.PathUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
@@ -32,6 +36,7 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
public class FileStore {
|
||||
@@ -42,16 +47,7 @@ public class FileStore {
|
||||
/** javaSources[file] is the javaSources time of a .java source file. */
|
||||
// TODO organize by package name for speed of list(...)
|
||||
private static final TreeMap<Path, Info> javaSources = new TreeMap<>();
|
||||
|
||||
private static class Info {
|
||||
final Instant modified;
|
||||
final String packageName;
|
||||
|
||||
Info(Instant modified, String packageName) {
|
||||
this.modified = modified;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
}
|
||||
private static final Logger LOG = Logger.newInstance("FileStore");
|
||||
|
||||
public static void shutdown() {
|
||||
workspaceRoots.clear();
|
||||
@@ -82,16 +78,6 @@ public class FileStore {
|
||||
}
|
||||
}
|
||||
|
||||
public static class FindJavaSources extends SimpleFileVisitor<Path> {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes _attrs) {
|
||||
if (isJavaFile(file)) {
|
||||
readInfoFromDisk(file);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<Path> all() {
|
||||
return javaSources.keySet();
|
||||
}
|
||||
@@ -137,7 +123,7 @@ public class FileStore {
|
||||
for (Path dir = file.getParent(); dir != null; dir = dir.getParent()) {
|
||||
// Try to find a sibling with a package declaration
|
||||
for (Path sibling : javaSourcesIn(dir)) {
|
||||
if (sibling.equals(file)) {
|
||||
if (PathUtils.isSameFile(sibling, file)) {
|
||||
continue;
|
||||
}
|
||||
String packageName = packageName(sibling);
|
||||
@@ -335,6 +321,26 @@ public class FileStore {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static class Info {
|
||||
final Instant modified;
|
||||
final String packageName;
|
||||
|
||||
Info(Instant modified, String packageName) {
|
||||
this.modified = modified;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FindJavaSources extends SimpleFileVisitor<Path> {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes _attrs) {
|
||||
if (isJavaFile(file)) {
|
||||
readInfoFromDisk(file);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static class VersionedContent {
|
||||
final CharSequence content;
|
||||
final int version;
|
||||
@@ -346,6 +352,4 @@ public class FileStore {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.newInstance("FileStore");
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.itsaky.lsp.java.utils.ScanClassPath;
|
||||
import com.itsaky.lsp.java.utils.StringSearch;
|
||||
import com.itsaky.lsp.java.visitors.FindTypeDeclarations;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
@@ -43,6 +44,7 @@ import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
@@ -52,8 +54,10 @@ public class JavaCompilerService implements CompilerProvider {
|
||||
private static final Cache<String, Boolean> cacheContainsWord = new Cache<>();
|
||||
private static final Cache<Void, List<String>> cacheContainsType = new Cache<>();
|
||||
private static final Logger LOG = Logger.newInstance("JavaCompilerService");
|
||||
protected final ScanClassPath classPathScanner = new ScanClassPath();
|
||||
protected final Set<Path> classPath, docPath;
|
||||
protected final Set<String> jdkClasses = ScanClassPath.jdkTopLevelClasses(), classPathClasses;
|
||||
protected final Set<String> jdkClasses = classPathScanner.jdkTopLevelClasses(),
|
||||
classPathClasses;
|
||||
protected final ReusableCompiler compiler = new ReusableCompiler();
|
||||
protected final SynchronizedTask synchronizedTask = new SynchronizedTask();
|
||||
protected final List<Diagnostic<? extends JavaFileObject>> diagnostics = new ArrayList<>();
|
||||
@@ -69,7 +73,7 @@ public class JavaCompilerService implements CompilerProvider {
|
||||
public JavaCompilerService(Set<Path> classPath, Set<Path> docPath) {
|
||||
this.classPath = Collections.unmodifiableSet(classPath);
|
||||
this.docPath = Collections.unmodifiableSet(docPath);
|
||||
this.classPathClasses = ScanClassPath.classPathTopLevelClasses(classPath);
|
||||
this.classPathClasses = classPathScanner.classPathTopLevelClasses(classPath);
|
||||
this.fileManager = new SourceFileManager();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,18 @@
|
||||
package com.itsaky.lsp.java.compiler;
|
||||
|
||||
import com.itsaky.lsp.java.FileStore;
|
||||
import java.io.*;
|
||||
import com.itsaky.lsp.util.PathUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.Writer;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
import javax.tools.JavaFileObject;
|
||||
@@ -45,11 +53,20 @@ public class SourceFileObject implements JavaFileObject {
|
||||
this.modified = modified;
|
||||
}
|
||||
|
||||
private static Kind kindFromExtension(String name) {
|
||||
for (Kind candidate : Kind.values()) {
|
||||
if (name.endsWith(candidate.extension)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other.getClass() != SourceFileObject.class) return false;
|
||||
SourceFileObject that = (SourceFileObject) other;
|
||||
return this.path.equals(that.path);
|
||||
return PathUtils.isSameFile(this.path, that.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,15 +80,6 @@ public class SourceFileObject implements JavaFileObject {
|
||||
return kindFromExtension(name);
|
||||
}
|
||||
|
||||
private static Kind kindFromExtension(String name) {
|
||||
for (Kind candidate : Kind.values()) {
|
||||
if (name.endsWith(candidate.extension)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNameCompatible(String simpleName, Kind kind) {
|
||||
return path.getFileName().toString().equals(simpleName + kind.extension);
|
||||
|
||||
@@ -19,8 +19,10 @@ package com.itsaky.lsp.java.providers;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.lsp.java.compiler.CompileTask;
|
||||
import com.itsaky.lsp.java.compiler.CompilerProvider;
|
||||
@@ -56,6 +58,9 @@ import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.Trees;
|
||||
import com.sun.tools.javac.api.ClientCodeWrapper;
|
||||
import com.sun.tools.javac.util.JCDiagnostic;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
@@ -68,6 +73,7 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
@@ -79,7 +85,6 @@ import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
public class CodeActionProvider {
|
||||
|
||||
@@ -322,7 +327,11 @@ public class CodeActionProvider {
|
||||
final List<String> classes = compiler.publicTopLevelTypes();
|
||||
|
||||
for (int i = 0; i < classes.size(); i++) {
|
||||
final String klass = classes.get(i);
|
||||
String klass = classes.get(i);
|
||||
if (klass.contains("/")) {
|
||||
klass = klass.replace("/", ".");
|
||||
}
|
||||
|
||||
if (!klass.endsWith("." + simpleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package com.itsaky.lsp.java.providers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.lsp.java.compiler.CompileTask;
|
||||
import com.itsaky.lsp.java.compiler.CompilerProvider;
|
||||
@@ -28,14 +29,18 @@ import com.itsaky.lsp.java.utils.NavigationHelper;
|
||||
import com.itsaky.lsp.models.DefinitionParams;
|
||||
import com.itsaky.lsp.models.DefinitionResult;
|
||||
import com.itsaky.lsp.models.Location;
|
||||
import com.itsaky.lsp.util.PathUtils;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.Trees;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
@@ -100,7 +105,7 @@ public class DefinitionProvider {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (otherFile.get().toUri().equals(file.toUri())) {
|
||||
if (PathUtils.isSameFile(Paths.get(otherFile.get().toUri()), file)) {
|
||||
return findDefinitions(task, element);
|
||||
}
|
||||
task.close();
|
||||
@@ -132,7 +137,7 @@ public class DefinitionProvider {
|
||||
|
||||
SourceFileObject fileAsSource = new SourceFileObject(file);
|
||||
List<JavaFileObject> sources = Arrays.asList(fileAsSource, otherFile.get());
|
||||
if (otherFile.get().toUri().equals(file.toUri())) {
|
||||
if (PathUtils.isSameFile(Paths.get(otherFile.get().toUri()), file)) {
|
||||
sources = Collections.singletonList(fileAsSource);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,15 +18,15 @@
|
||||
package com.itsaky.lsp.java.providers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.itsaky.androidide.app.BaseApplication;
|
||||
|
||||
import com.itsaky.lsp.java.FileStore;
|
||||
import com.itsaky.lsp.java.R;
|
||||
import com.itsaky.lsp.java.compiler.CompileTask;
|
||||
import com.itsaky.lsp.java.visitors.DiagnosticVisitor;
|
||||
import com.itsaky.lsp.models.DiagnosticItem;
|
||||
import com.itsaky.lsp.models.DiagnosticSeverity;
|
||||
import com.itsaky.lsp.models.Position;
|
||||
import com.itsaky.lsp.models.Range;
|
||||
import com.itsaky.lsp.util.PathUtils;
|
||||
import com.sun.source.tree.BlockTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
@@ -37,6 +37,7 @@ import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.SourcePositions;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.Trees;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
@@ -46,6 +47,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.tools.Diagnostic;
|
||||
@@ -74,7 +76,7 @@ public class DiagnosticsProvider {
|
||||
CompilationUnitTree root = null;
|
||||
for (CompilationUnitTree tree : task.roots) {
|
||||
final Path path = Paths.get(tree.getSourceFile().toUri());
|
||||
if (path.equals(file)) {
|
||||
if (PathUtils.isSameFile(path, file)) {
|
||||
root = tree;
|
||||
break;
|
||||
}
|
||||
@@ -132,7 +134,7 @@ public class DiagnosticsProvider {
|
||||
long start = pos.getStartPosition(root, path.getLeaf());
|
||||
long end = pos.getEndPosition(root, path.getLeaf());
|
||||
final DiagnosticItem d = new DiagnosticItem();
|
||||
d.setMessage(BaseApplication.getBaseInstance().getString(R.string.msg_not_thrown, name));
|
||||
d.setMessage(String.format("'%s' is not thrown in the body of the method", name));
|
||||
d.setRange(new Range(getPosition(start, lines), getPosition(end, lines)));
|
||||
d.setCode("unused_throws");
|
||||
d.setSeverity(DiagnosticSeverity.INFO);
|
||||
@@ -172,7 +174,7 @@ public class DiagnosticsProvider {
|
||||
end = start + name.length();
|
||||
}
|
||||
|
||||
String message = BaseApplication.getBaseInstance().getString(R.string.msg_not_used, name);
|
||||
String message = String.format("'%s' is not used", name);
|
||||
String code;
|
||||
DiagnosticSeverity severity;
|
||||
if (leaf instanceof VariableTree) {
|
||||
|
||||
@@ -18,38 +18,48 @@
|
||||
package com.itsaky.lsp.java.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.jrtfs.JrtFileSystemProvider;
|
||||
|
||||
public class ScanClassPath {
|
||||
|
||||
private static final Logger LOG = Logger.newInstance("ScanClassPath");
|
||||
|
||||
public static Set<String> jdkTopLevelClasses() {
|
||||
public Set<String> jdkTopLevelClasses() {
|
||||
LOG.info("Searching for top-level classes in the JDK");
|
||||
|
||||
Set<String> classes = new TreeSet<>();
|
||||
try {
|
||||
final FileSystem fs =
|
||||
new JrtFileSystemProvider()
|
||||
.newFileSystem(URI.create("jrt:/"), Collections.emptyMap());
|
||||
final FileSystem fs = getJRTFileSystem();
|
||||
if (fs == null) {
|
||||
LOG.error("Unable to create an instance of JRTFileSystem");
|
||||
return classes;
|
||||
}
|
||||
|
||||
final Path moduleRoot = fs.getPath("/modules/java.base/");
|
||||
try (Stream<Path> stream = Files.walk(moduleRoot)) {
|
||||
final Iterator<Path> it = stream.iterator();
|
||||
@@ -66,8 +76,8 @@ public class ScanClassPath {
|
||||
} catch (IOException e) {
|
||||
LOG.error("An error occurred while indexing module 'java.base'", e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Unable to create an instance of JRTFileSystem");
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Unable to create an instance of JRTFileSystem", e);
|
||||
}
|
||||
|
||||
LOG.info(
|
||||
@@ -77,14 +87,14 @@ public class ScanClassPath {
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public static Set<String> classPathTopLevelClasses(Set<Path> classPath) {
|
||||
public Set<String> classPathTopLevelClasses(Set<Path> classPath) {
|
||||
LOG.info(
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
"Searching for top-level classes in %d classpath locations",
|
||||
classPath.size()));
|
||||
|
||||
URL[] urls = classPath.stream().map(ScanClassPath::toUrl).toArray(URL[]::new);
|
||||
URL[] urls = classPath.stream().map(this::toUrl).toArray(URL[]::new);
|
||||
ClassLoader classLoader = new URLClassLoader(urls, null);
|
||||
|
||||
ClassPath scanner;
|
||||
@@ -104,7 +114,26 @@ public class ScanClassPath {
|
||||
return classes;
|
||||
}
|
||||
|
||||
private static URL toUrl(@NonNull Path p) {
|
||||
@Nullable
|
||||
@Contract(" -> new")
|
||||
public FileSystem getJRTFileSystem() throws Exception {
|
||||
final URI uri = URI.create("jrt:/");
|
||||
try {
|
||||
// Tests run on the JVM, so we cannot directly access JRTFileSystemProvider
|
||||
// But this method will work
|
||||
return FileSystems.getFileSystem(uri);
|
||||
} catch (Throwable th) {
|
||||
|
||||
// When on ART, JRT file system is not available
|
||||
// So we create an instance of the FS manually
|
||||
final Class<?> klass = Class.forName("jdk.internal.jrtfs.JrtFileSystemProvider");
|
||||
final Method newFs = klass.getMethod("newFileSystem", URI.class, Map.class);
|
||||
newFs.setAccessible(true);
|
||||
return (FileSystem) newFs.invoke(klass.newInstance(), uri, Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
private URL toUrl(@NonNull Path p) {
|
||||
try {
|
||||
return p.toUri().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
@@ -79,7 +79,10 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
|
||||
}
|
||||
|
||||
/** Need RuntimePermission "accessSystemModules" to create or get jrt:/ */
|
||||
private void checkPermission() {}
|
||||
private void checkPermission() {
|
||||
// ANDROIDIDE-CHANGED
|
||||
// Permission granted...
|
||||
}
|
||||
|
||||
private void checkUri(URI uri) {
|
||||
if (!uri.getScheme().equalsIgnoreCase(getScheme())) {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="msg_not_thrown">\'%s\' is not thrown in the body of the method</string>
|
||||
<string name="msg_not_used">\'%s\' wird nicht genutzt</string>
|
||||
</resources>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
|
||||
~ 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
-->
|
||||
<resources>
|
||||
<string name="msg_not_thrown">\'%s\' is not thrown in the body of the method</string>
|
||||
<string name="msg_not_used">\'%s\' n\'est pas utilisé</string>
|
||||
</resources>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<resources>
|
||||
<string name="msg_not_thrown">\'%s\' मेथड की बॉडी में थ्रो नहीं किया गया है</string>
|
||||
<string name="msg_not_used">\'%s\' उपयोग नहीं किया गया है</string>
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="msg_not_thrown">\'%s\' tidak ditaruh kedalam tubuh metode</string>
|
||||
<string name="msg_not_used">\'%s\' tidak digunakan</string>
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="msg_not_thrown">在方法体中 \'%s\' 不会被抛出</string>
|
||||
<string name="msg_not_used">\'%s\' 未被使用</string>
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="msg_not_thrown">\'%s\' is not thrown in the body of the method</string>
|
||||
<string name="msg_not_used">\'%s\' is not used</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.lsp.java.providers
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.itsaky.lsp.api.ILanguageServer
|
||||
import com.itsaky.lsp.api.LoggingTest
|
||||
import com.itsaky.lsp.java.JavaLanguageServerProvider
|
||||
import com.itsaky.lsp.models.CodeActionParams
|
||||
import com.itsaky.lsp.models.DiagnosticItem
|
||||
import com.itsaky.lsp.models.Range
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class JavaCodeActionProviderTest : LoggingTest() {
|
||||
|
||||
private val server: ILanguageServer = JavaLanguageServerProvider.INSTANCE.server();
|
||||
|
||||
override fun getServer(): ILanguageServer = server
|
||||
|
||||
@Test
|
||||
fun testAddImport() {
|
||||
openFile("AddImportAction")
|
||||
val diagnostics = server.analyze(file!!).filter { it.code == "compiler.err.cant.resolve.location" }
|
||||
val actions = actions(diagnostics)
|
||||
assertThat(actions).contains("Import 'java.util.stream.Stream'")
|
||||
}
|
||||
|
||||
private fun actions(diagnostics: List<DiagnosticItem>): List<String> {
|
||||
val params = CodeActionParams(file!!, Range(), diagnostics)
|
||||
return server.codeActions(params).actions.map { it.title }
|
||||
}
|
||||
|
||||
override fun openFile(fileName: String) {
|
||||
super.openFile("actions/${fileName}")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.itsaky.androidide.test;
|
||||
|
||||
public class AddImportAction_template {
|
||||
public static void main(String[] args) {
|
||||
Stream<String> stream = null;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ abstract class CursorDependentTest : LoggingTest() {
|
||||
private val cursorText = "@@cursor@@"
|
||||
|
||||
fun requireCursor(): Int {
|
||||
this.cursor = super.contents!!.indexOf(cursorText)
|
||||
assertThat(cursor).isGreaterThan(-1)
|
||||
return cursor
|
||||
}
|
||||
@@ -60,9 +61,4 @@ abstract class CursorDependentTest : LoggingTest() {
|
||||
val pos = Content(contents!!).indexer.getCharPosition(cursor)
|
||||
return Position(pos.line, pos.column, pos.index)
|
||||
}
|
||||
|
||||
override fun openFile(fileName: String) {
|
||||
super.openFile(fileName)
|
||||
this.cursor = super.contents!!.indexOf(cursorText)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user