8295401: Error recovery in module-info.java could be improved

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2022-11-30 09:49:51 +00:00
parent 9e80cf9c37
commit b52611bc36
2 changed files with 81 additions and 6 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/parser
test/langtools/tools/javac/parser

@ -3846,15 +3846,16 @@ public class JavacParser implements Parser {
} else if (token.name() == names.provides) {
nextToken();
JCExpression serviceName = qualident(false);
List<JCExpression> implNames;
if (token.kind == IDENTIFIER && token.name() == names.with) {
nextToken();
List<JCExpression> implNames = qualidentList(false);
accept(SEMI);
defs.append(toP(F.at(pos).Provides(serviceName, implNames)));
implNames = qualidentList(false);
} else {
log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.ExpectedStr("'" + names.with + "'"));
skip(false, false, false, false);
implNames = List.nil();
}
accept(SEMI);
defs.append(toP(F.at(pos).Provides(serviceName, implNames)));
} else if (token.name() == names.uses) {
nextToken();
JCExpression service = qualident(false);

@ -23,7 +23,7 @@
/*
* @test
* @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897
* @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401
* @summary tests error and diagnostics positions
* @author Jan Lahoda
* @modules jdk.compiler/com.sun.tools.javac.api
@ -84,7 +84,9 @@ import javax.tools.ToolProvider;
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.DefaultCaseLabelTree;
import com.sun.source.tree.ModuleTree;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.api.JavacTaskPool;
import java.util.Objects;
public class JavacParserTest extends TestCase {
@ -106,7 +108,11 @@ public class JavacParserTest extends TestCase {
private String text;
public MyFileObject(String text) {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
this("Test", text);
}
public MyFileObject(String fileName, String text) {
super(URI.create("myfo:/" + fileName + ".java"), JavaFileObject.Kind.SOURCE);
this.text = text;
}
@ -1989,6 +1995,74 @@ public class JavacParserTest extends TestCase {
}.scan(cut, null);
}
@Test //JDK-8295401
void testModuleInfoProvidesRecovery() throws IOException {
String code = """
module m {
$DIRECTIVE
}
""";
record Test(String directive, int prefix, Kind expectedKind) {}
Test[] tests = new Test[] {
new Test("uses api.api.API;", 4, Kind.USES),
new Test("opens api.api to other.module;", 5, Kind.OPENS),
new Test("exports api.api to other.module;", 7, Kind.EXPORTS),
new Test("provides java.util.spi.ToolProvider with impl.ToolProvider;", 8, Kind.PROVIDES),
};
JavacTaskPool pool = new JavacTaskPool(1);
for (Test test : tests) {
String directive = test.directive();
for (int i = test.prefix(); i < directive.length(); i++) {
String replaced = code.replace("$DIRECTIVE", directive.substring(0, i));
pool.getTask(null, null, d -> {}, List.of(), null, List.of(new MyFileObject(replaced)), task -> {
try {
CompilationUnitTree cut = task.parse().iterator().next();
new TreePathScanner<Void, Void>() {
@Override
public Void visitModule(ModuleTree node, Void p) {
assertEquals("Unexpected directives size: " + node.getDirectives().size(),
node.getDirectives().size(),
1);
assertEquals("Unexpected directive: " + node.getDirectives().get(0).getKind(),
node.getDirectives().get(0).getKind(),
test.expectedKind);
return super.visitModule(node, p);
}
}.scan(cut, null);
return null;
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
});
}
}
String extendedCode = """
module m {
provides ;
provides java.;
provides java.util.spi.ToolProvider with ;
provides java.util.spi.ToolProvider with impl.;
""";
pool.getTask(null, null, d -> {}, List.of(), null, List.of(new MyFileObject("module-info", extendedCode)), task -> {
try {
CompilationUnitTree cut = task.parse().iterator().next();
task.analyze();
new TreePathScanner<Void, Void>() {
@Override
public Void visitModule(ModuleTree node, Void p) {
assertEquals("Unexpected directives size: " + node.getDirectives().size(),
node.getDirectives().size(),
4);
return super.visitModule(node, p);
}
}.scan(cut, null);
return null;
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
});
}
void run(String[] args) throws Exception {
int passed = 0, failed = 0;
final Pattern p = (args != null && args.length > 0)