diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java index 402e3f452..0b69721bd 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.function.Function; @@ -166,12 +167,15 @@ IFunction makeParseTreeGetter(Evaluator e) { return e.getFunctionValueFactory().function(getParseTreeType, (t, u) -> { ISourceLocation resolvedLocation = Locations.toClientLocation((ISourceLocation) t[0]); try { - var tree = rascalTextDocumentService.getFile(resolvedLocation).getLastTreeWithoutErrors(); + var tree = rascalTextDocumentService.getFile(resolvedLocation).getCurrentTreeAsync(false).get(); if (tree != null) { return tree.get(); } - } catch (ResponseErrorException e1) { - // File is not open in the IDE + } catch (ResponseErrorException | ExecutionException e1) { + // File is not open in the IDE | Parse threw an exception + // In either case, fall through and try a direct parse + } catch (InterruptedException e1) { + Thread.currentThread().interrupt(); } // Parse the source file try (var reader = URIResolverRegistry.getInstance().getCharacterReader(resolvedLocation)) { diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/IDECheckerWrapper.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/IDECheckerWrapper.rsc index d8ffd1074..7437ee279 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/IDECheckerWrapper.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/IDECheckerWrapper.rsc @@ -36,6 +36,7 @@ import Location; import analysis::graphs::Graph; import util::FileSystem; import util::Monitor; +import util::ParseErrorRecovery; import util::Reflective; import lang::rascal::\syntax::Rascal; @@ -53,28 +54,49 @@ import lang::rascalcore::check::ModuleLocations; } map[loc, set[Message]] checkFile(loc l, set[loc] workspaceFolders, start[Module](loc file) getParseTree, PathConfig(loc file) getPathConfig) = job("Rascal check", map[loc, set[Message]](void(str, int) step) { - checkForImports = [getParseTree(l)]; + start[Module] openFile; + try { + openFile = getParseTree(l); + } catch ParseError(loc err): { + return (l: {error("Cannot typecheck this module, since it has parse error(s).", err)}); + } + if (hasParseErrors(openFile)) { + // We cannot typecheck this file, since it has type errors. Do not return any errors, since the parse triggered by the IDE will take care of that. + return (); + } + openFileHeader = openFile.top.header.name; + + checkForImports = [openFile]; checkedForImports = {}; initialProject = inferProjectRoot(l); rel[loc, loc] dependencies = {}; step("Dependency graph", 1); - job("Building dependency graph", bool (void (str, int) step2) { + parseMsgs = job("Building dependency graph", map[loc, set[Message]] (void (str, int) step2) { while (tree <- checkForImports) { step2("Calculating imports for ", 1); currentSrc = tree.src.top; currentProject = inferProjectRoot(currentSrc); if (currentProject in workspaceFolders && currentProject.file notin {"rascal", "rascal-lsp"}) { for (i <- tree.top.header.imports, i has \module) { + modName = ""; try { - ml = locateRascalModule("", getPathConfig(currentProject), getPathConfig, workspaceFolders); + ml = locateRascalModule(modName, getPathConfig(currentProject), getPathConfig, workspaceFolders); if (ml.extension == "rsc", mlpt := getParseTree(ml), mlpt.src.top notin checkedForImports) { + if (hasParseErrors(mlpt)) { + return (l: {error("Cannot typecheck this module, since a dependency has parse error(s).", openFileHeader.src, + causes=[error("Has a parse error around this position.", e.src) | Tree e <- findBestParseErrors(mlpt)]) + }); + } checkForImports += mlpt; jobTodo("Building dependency graph"); dependencies += ; } - } catch _: { + } catch ParseError(loc err): { + return (l: {error("Cannot typecheck this module, since a dependency has parse error(s).", openFileHeader.src, causes=[error("Has parse error(s).", err)])}); + } catch e: { + println("Exception while building dependency graph at : "); ;// Continue } } @@ -82,9 +104,14 @@ map[loc, set[Message]] checkFile(loc l, set[loc] workspaceFolders, start[Module] checkedForImports += currentSrc; checkForImports -= tree; } - return true; + + return (); }, totalWork=1); + if (() != parseMsgs) { + return parseMsgs; + } + cyclicDependencies = {p | <- (dependencies - ident(carrier(dependencies)))+}; if (cyclicDependencies != {}) { return (l : {error("Cyclic dependencies detected between projects {}. This is not supported. Fix your project setup.", l)});