Skip to content

Commit e0e3bd3

Browse files
committed
fix: version in-memory source snapshots
1 parent fad7221 commit e0e3bd3

7 files changed

Lines changed: 49 additions & 36 deletions

File tree

src/main/java/org/javacs/Parser.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.sun.source.util.*;
66
import java.io.IOException;
77
import java.nio.file.*;
8-
import java.time.Instant;
98
import java.util.*;
109
import java.util.logging.Logger;
1110
import java.util.regex.Pattern;
@@ -188,7 +187,7 @@ private static int indexOf(CharSequence contents, String name, int start) {
188187
private static final DocCommentTree EMPTY_DOC = makeEmptyDoc();
189188

190189
private static DocCommentTree makeEmptyDoc() {
191-
var file = new SourceFileObject(Paths.get("/Foo.java"), "/** */ class Foo { }", Instant.now());
190+
var file = new SourceFileObject(Paths.get("/Foo.java"), "/** */ class Foo { }", SourceFileObject.now());
192191
var task =
193192
(JavacTask)
194193
COMPILER.getTask(

src/main/java/org/javacs/SourceFileObject.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import java.io.*;
44
import java.net.URI;
55
import java.nio.file.Path;
6-
import java.time.Instant;
6+
import java.util.concurrent.atomic.AtomicLong;
77
import javax.lang.model.element.Modifier;
88
import javax.lang.model.element.NestingKind;
99
import javax.tools.JavaFileObject;
@@ -13,20 +13,31 @@ public class SourceFileObject implements JavaFileObject {
1313
final Path path;
1414
/** contents is the text in this file, or null if we should use the text in FileStore */
1515
final String contents;
16-
/** if contents is set, the modified time of contents */
17-
final Instant modified;
16+
/** if contents is set, the modified version of contents in monotonic nanoseconds */
17+
final long modified;
18+
private static final AtomicLong LAST_NOW = new AtomicLong();
1819

1920
public SourceFileObject(Path path) {
20-
this(path, null, Instant.EPOCH);
21+
this(path, null, 0);
2122
}
2223

23-
public SourceFileObject(Path path, String contents, Instant modified) {
24+
public SourceFileObject(Path path, String contents, long modified) {
2425
if (!FileStore.isJavaFile(path)) throw new RuntimeException(path + " is not a java source");
2526
this.path = path;
2627
this.contents = contents;
2728
this.modified = modified;
2829
}
2930

31+
public static long now() {
32+
while (true) {
33+
var previous = LAST_NOW.get();
34+
var candidate = Math.max(System.nanoTime(), previous + 1);
35+
if (LAST_NOW.compareAndSet(previous, candidate)) {
36+
return candidate;
37+
}
38+
}
39+
}
40+
3041
@Override
3142
public boolean equals(Object other) {
3243
if (other.getClass() != SourceFileObject.class) return false;
@@ -117,7 +128,7 @@ public Writer openWriter() {
117128
@Override
118129
public long getLastModified() {
119130
if (contents != null) {
120-
return modified.toEpochMilli();
131+
return modified;
121132
}
122133
var fileModified = FileStore.modified(path);
123134
if (fileModified == null) return 0;

src/main/java/org/javacs/completion/CompletionProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ private int endOfLine(CharSequence contents, int cursor) {
145145

146146
private CompletionList compileAndComplete(Path file, String contents, long cursor) {
147147
var started = Instant.now();
148-
var source = new SourceFileObject(file, contents, Instant.now());
148+
var source = new SourceFileObject(file, contents, SourceFileObject.now());
149149
var partial = partialIdentifier(contents, (int) cursor);
150150
var endsWithParen = endsWithParen(contents, (int) cursor);
151151
try (var task = compiler.compile(List.of(source))) {

src/test/java/org/javacs/BenchmarkParser.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.nio.file.Files;
55
import java.nio.file.Path;
66
import java.nio.file.Paths;
7-
import java.time.Instant;
87
import java.util.concurrent.TimeUnit;
98
import java.util.logging.Logger;
109
import org.openjdk.jmh.annotations.*;
@@ -31,7 +30,7 @@ public void setup() throws IOException {
3130
}
3231

3332
public SourceFileObject source() {
34-
return new SourceFileObject(file, contents, Instant.ofEpochMilli(++version));
33+
return new SourceFileObject(file, contents, ++version);
3534
}
3635

3736
private static void quietBenchmarkLogging() {

src/test/java/org/javacs/BenchmarkPruner.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.io.IOException;
44
import java.nio.file.Files;
55
import java.nio.file.Paths;
6-
import java.time.Instant;
76
import java.util.Collections;
87
import java.util.List;
98
import java.util.Set;
@@ -48,7 +47,7 @@ public SourceFileObject prunedSource() {
4847
}
4948

5049
private SourceFileObject source(String contents) {
51-
return new SourceFileObject(file, contents, Instant.ofEpochMilli(++version));
50+
return new SourceFileObject(file, contents, ++version);
5251
}
5352

5453
private static JavaCompilerService createCompiler() {

src/test/java/org/javacs/CompletionsBase.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,10 @@
55
import java.util.stream.Stream;
66
import org.javacs.lsp.*;
77
import org.junit.Assert;
8-
import org.junit.Before;
98

109
public class CompletionsBase {
1110
protected static JavaLanguageServer server = LanguageServerFixture.getJavaLanguageServer();
1211

13-
@Before
14-
public void resetServer() {
15-
refreshServer();
16-
}
17-
1812
protected void refreshServer() {
1913
server = LanguageServerFixture.getJavaLanguageServer();
2014
}
Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
11
package org.javacs;
22

3-
import static org.hamcrest.Matchers.*;
4-
import static org.junit.Assert.*;
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.containsString;
5+
import static org.hamcrest.Matchers.not;
56

6-
import java.nio.file.*;
7-
import java.util.*;
8-
import org.junit.*;
7+
import java.util.List;
8+
import org.junit.Test;
99

1010
public class JavaCompilerServiceTest {
11-
static {
12-
Main.setRootFormat();
13-
}
14-
15-
private JavaCompilerService compiler =
16-
new JavaCompilerService(Collections.emptySet(), Collections.emptySet(), Collections.emptySet());
11+
@Test
12+
public void compileDoesNotReuseStaleInMemorySourceForSamePathAndNewVersion() {
13+
var compiler = LanguageServerFixture.getCompilerProvider();
14+
var file = LanguageServerFixture.DEFAULT_WORKSPACE_ROOT.resolve("src/org/javacs/example/CacheKeyRegression.java");
15+
var firstModified = SourceFileObject.now();
16+
var secondModified = SourceFileObject.now();
17+
var first =
18+
new SourceFileObject(
19+
file,
20+
"package org.javacs.example; class CacheKeyRegression { int first; }",
21+
firstModified);
22+
var second =
23+
new SourceFileObject(
24+
file,
25+
"package org.javacs.example; class CacheKeyRegression { int second; }",
26+
secondModified);
1727

18-
static Path simpleProjectSrc() {
19-
return Paths.get("src/test/examples/simple-project").normalize();
20-
}
28+
try (var compile = compiler.compile(List.of(first))) {
29+
assertThat(compile.root().toString(), containsString("first"));
30+
}
2131

22-
@Before
23-
public void setWorkspaceRoot() {
24-
FileStore.setWorkspaceRoots(Set.of(simpleProjectSrc()));
32+
try (var compile = compiler.compile(List.of(second))) {
33+
assertThat(compile.root().toString(), containsString("second"));
34+
assertThat(compile.root().toString(), not(containsString("first")));
35+
}
2536
}
2637
}

0 commit comments

Comments
 (0)