Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ set[loc] picoDefinitionService([*_, Id use, *_, start[Program] input]) = { def.s

@synopsis{If a variable is not defined, we list a fix of fixes to replace it with a defined variable instead.}
list[CodeAction] prepareNotDefinedFixes(loc src, rel[str, loc] defs)
= [action(title="Change to <existing<0>>", edits=[changed(src.top, [replace(src, existing<0>)])]) | existing <- defs];
= [CodeAction::action(title="Change to <existing<0>>", edits=[changed(src.top, [replace(src, existing<0>)])]) | existing <- defs];

@synopsis{Finds a declaration that the cursor is on and proposes to remove it.}
list[CodeAction] picoCodeActionService([*_, IdType x, *_, start[Program] program])
= [action(command=removeDecl(program, x, title="remove <x>"))];
= [CodeAction::action(command=removeDecl(program, x, title="remove <x>"))];

default list[CodeAction] picoCodeActionService(Focus _focus) = [];

Expand Down
7 changes: 7 additions & 0 deletions rascal-lsp/src/main/rascal/library/util/LanguageServer.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,13 @@ Provides extra context for all contained ((util::LanguageServer::TextEdit))s at
}
data FileSystemChange(str label = "", str description = "", bool needsConfirmation = false);

@synopsis{Shorthand for file changes, with additional context for LSP.}
@description{
Provides extra context for all contained ((util::LanguageServer::TextEdit))s at once.
}
FileSystemChange changed(list[TextEdit] edits:[replace(loc l, str _), *_], str label = "", str description = "", bool needsConfirmation = false)
= changed(l.top, edits, label=label, description=description, needsConfirmation=needsConfirmation);

@synopsis{A Command is a parameter to a CommandExecutor function.}
@description{
Commands can be any closed term a() pure value without open variables or function/closure values embedded in it). Add any constructor you need to express the execution parameters
Expand Down
3 changes: 2 additions & 1 deletion rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module lang::rascal::lsp::Templates
import IO;
import Location;
import String;
import util::LanguageServer;
import util::PathConfig;
import util::Reflective;

Expand All @@ -53,7 +54,7 @@ list[FileSystemChange] newModuleTemplates(list[loc] newFiles, PathConfig(loc) ge
if (isBlank(f)) {
// If the file is empty, add a module header
edits += changed([replace(resetRange(f), "module <name>\n\n")], label = "Empty module", description = "", needsConfirmation = true);
} else if (m := parseModuleWithSpaces(f)) {
} else if (start[Module] m := parseModuleWithSpaces(f)) {
// If an existing module was pasted, replace the module name
edits += changed([replace(m.top.header.name.src, name)], label = "Moved module", description = "", needsConfirmation = true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import String;
import lang::rascal::\syntax::Rascal;

import lang::rascalcore::check::Checker;
import lang::rascalcore::check::ATypeBase;
import lang::rascalcore::check::BasicRascalConfig;

import lang::rascal::lsp::refactor::rename::Common;
Expand All @@ -69,6 +70,8 @@ import util::LanguageServer;
import util::Maybe;
import util::Reflective;

import analysis::diff::edits::TextEdits;

private bool isQualifiedUse(loc use, Define _:<_, str id, _, _, _, _>) = size(id) != use.length;

void rascalCheckCausesOverlappingDefinitions(set[Define] currentDefs, str newName, Tree tr, TModel tm, Renamer r) {
Expand Down Expand Up @@ -136,7 +139,7 @@ void rascalCheckCausesOverlappingDefinitions(set[Define] currentDefs, str newNam

void rascalCheckLegalNameByRole(Define _:<_, _, _, role, at, dt>, str name, Renamer r) {
escName = normalizeEscaping(name);
<t, desc> = asType(role, dt);
<t, desc> = asRoleType(role, dt);
if (tryParseAs(t, escName) is nothing) {
r.msg(error(at, "<escName> is not a valid <desc>"));
}
Expand Down Expand Up @@ -215,7 +218,7 @@ Tree findCursorInTree(Tree t, loc cursorLoc) {
}

@synopsis{Due to how the focus list is computed and the grammar for concrete syntax, we cannot easily find the exact name that the cursor is at.}
list[Tree] extendFocusWithConcreteSyntax([Concrete c, *tail], loc cursorLoc) = [findCursorInTree(c, cursorLoc), c, *tail];
list[Tree] extendFocusWithConcreteSyntax([Concrete c, *Tree tail], loc cursorLoc) = [findCursorInTree(c, cursorLoc), c, *tail];
default list[Tree] extendFocusWithConcreteSyntax(list[Tree] cursor, loc _) = cursor;

data AugmentComponents = augmentUses() | augmentDefs();
Expand All @@ -229,7 +232,7 @@ TModel getConditionallyAugmentedTModel(loc l, set[Define] defs, set[AugmentCompo
: r.getConfig().tmodelForLoc(l);

public Edits rascalRenameSymbol(loc cursorLoc, list[Tree] cursor, str newName, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) {
ModuleStatus ms = moduleStatus({}, {}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig());
ModuleStatus ms = moduleStatus({}, {}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig());

TModel tmodelForTree(Tree tr) = tmodelForLoc(tr.src.top);

Expand Down Expand Up @@ -354,7 +357,7 @@ tuple[set[loc], set[loc], set[loc]] findOccurrenceFiles(set[Define] defs, list[T
escNewName = normalizeEscaping(newName);
for (<role, dt> <- defs<idRole, defInfo>) {
hasError = false;
<t, desc> = asType(role, dt);
<t, desc> = asRoleType(role, dt);
if (tryParseAs(t, escNewName) is nothing) {
hasError = true;
r.msg(error(cursor[0], "\'<escNewName>\' is not a valid <desc>"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ Tree parseAsOrEmpty(type[&T <: Tree] T, str name) =

private tuple[Tree, Tree] escapePair(type[&T <: Tree] T, str n) = <parseAsOrEmpty(T, n), parseAsOrEmpty(T, forceEscapeSingleName(n))>;

private set[&T] escapeSet(type[&T <: Tree] T, str n) {
set[&T] res = {};
if (just(&T t) := tryParseAs(T, n)) {
private set[&T <: Tree] escapeSet(type[&T <: Tree] T, str n) {
set[&T <: Tree] res = {};
if (just(&T <: Tree t) := tryParseAs(T, n)) {
res += t;
}
if (just(&T t) := tryParseAs(T, forceEscapeSingleName(n))) {
if (just(&T <: Tree t) := tryParseAs(T, forceEscapeSingleName(n))) {
res += t;
}
return res;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ set[Define] findAdditionalConstructorDefinitions(set[Define] cursorDefs, Tree tr
}

// ADT constructors
tuple[type[Tree] as, str desc] asType(constructorId(), defType(acons(aadt(_, _, dataSyntax()), _, _))) = <#Name, "data constructor name">;
tuple[type[Tree] as, str desc] asRoleType(constructorId(), defType(acons(aadt(_, _, dataSyntax()), _, _))) = <#Name, "data constructor name">;
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ TModel augmentFieldUses(Tree tr, TModel tm, TModel(loc) getModel) {
}

// Positional fields
tuple[type[Tree] as, str desc] asType(fieldId(), _) = <#NonterminalLabel, "field name">;
tuple[type[Tree] as, str desc] asRoleType(fieldId(), _) = <#NonterminalLabel, "field name">;

// Keyword fields
tuple[type[Tree] as, str desc] asType(keywordFieldId(), _) = <#Name, "keyword field name">;
tuple[type[Tree] as, str desc] asRoleType(keywordFieldId(), _) = <#Name, "keyword field name">;

bool isUnsupportedCursor(list[Tree] _: [*_, Name n1, *_, (Expression) `<Expression _> has <Name n2>`, *_], Renamer _) = (n1 := n2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ set[Define] findAdditionalDefinitions(set[Define] cursorDefs:{<_, _, _, function
set[Define] findAdditionalFunctionDefinitions(set[Define] cursorDefs, TModel tm) =
{tm.definitions[d] | loc d <- (tm.defines<idRole, defined>)[functionId()], rascalMayOverloadSameName(cursorDefs.defined + d, tm.definitions)};

tuple[type[Tree] as, str desc] asType(functionId(), _) = <#Name, "function name">;
tuple[type[Tree] as, str desc] asRoleType(functionId(), _) = <#Name, "function name">;
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import util::Util;

import lang::rascal::\syntax::Rascal;
import lang::rascalcore::check::BasicRascalConfig;
import lang::rascalcore::check::AType;

import Location;

Expand All @@ -61,13 +62,13 @@ void renameDefinitionUnchecked(Define d: <_, _, _, lexicalId(), _, _>, loc _, st
}

// Non-terminals
tuple[type[Tree] as, str desc] asType(nonterminalId(), _) = <#Nonterminal, "production name">;
tuple[type[Tree] as, str desc] asRoleType(nonterminalId(), _) = <#Nonterminal, "production name">;

// Lexicals
tuple[type[Tree] as, str desc] asType(lexicalId(), _) = <#Nonterminal, "production name">;
tuple[type[Tree] as, str desc] asRoleType(lexicalId(), _) = <#Nonterminal, "production name">;

// Grammar constructors
tuple[type[Tree] as, str desc] asType(constructorId(), defType(acons(aadt(_, _, syntaxRole), _, _))) = <#NonterminalLabel, "grammar constructor name">
tuple[type[Tree] as, str desc] asRoleType(constructorId(), defType(acons(aadt(_, _, syntaxRole), _, _))) = <#NonterminalLabel, "grammar constructor name">
when !syntaxRole is dataSyntax;

TModel augmentExceptProductions(Tree tr, TModel tm, TModel(loc) tmodelForLoc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import util::PathConfig;
import util::Reflective;
import util::Util;

tuple[type[Tree] as, str desc] asType(moduleId(), _) = <#QualifiedName, "module name">;
tuple[type[Tree] as, str desc] asRoleType(moduleId(), _) = <#QualifiedName, "module name">;

tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{<_, str defName, _, moduleId(), loc d, _>}, list[Tree] cursor, str newName, Tree(loc) getTree, Renamer r) {
set[loc] useFiles = {};
Expand All @@ -72,38 +72,39 @@ tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{
} catch _: {;}

for (loc f <- getSourceFiles(r)) {
m = getTree(f);
mtree = getTree(f);

bool markedNew = false;
bool markedUse = false;

top-down-break visit (m.top.header.imports) {
case modNameTree: {
// Import of exact module name
useFiles += f;
markedUse = true;
}
}
bottom-up-break visit(m) {
case QualifiedName qn: {
// Import of redundantly escaped module name
qnSize = size(asNames(qn));
if (qnSize == modNameNumberOfNames && modName == normalizeEscaping("<qn>")) {
if(Module m := mtree.top){
top-down-break visit (m.header.imports) {
case modNameTree: {
// Import of exact module name
useFiles += f;
markedUse = true;
}
else if (qnSize == modNameNumberOfNames + 1 || qnSize == newModNameNumberOfNames + 1) {
qualPref = qualifiedPrefix(qn);
if (qualPref.name == modName || normalizeEscaping(qualPref.name) == modName) {
}
bottom-up-break visit(m) {
case QualifiedName qn: {
// Import of redundantly escaped module name
qnSize = size(asNames(qn));
if (qnSize == modNameNumberOfNames && modName == normalizeEscaping("<qn>")) {
useFiles += f;
markedUse = true;
}
else if (qualPref.name == newModName || normalizeEscaping(qualPref.name) == newModName) {
newFiles += f;
markedNew = true;
else if (qnSize == modNameNumberOfNames + 1 || qnSize == newModNameNumberOfNames + 1) {
qualPref = qualifiedPrefix(qn);
if (qualPref.name == modName || normalizeEscaping(qualPref.name) == modName) {
useFiles += f;
markedUse = true;
}
else if (qualPref.name == newModName || normalizeEscaping(qualPref.name) == newModName) {
newFiles += f;
markedNew = true;
}
}
if (markedUse && markedNew) continue;
}
if (markedUse && markedNew) continue;
}
}
}
Expand All @@ -130,7 +131,7 @@ void renameDefinitionUnchecked(Define d:<_, currentName, _, moduleId(), _, _>, l
}
}

void renameAdditionalUses(set[Define] _:{<_, moduleName, _, moduleId(), modDef, _>}, str newName, TModel tm, Renamer r) {
void renameAdditionalUses(set[Define] _:{<_, moduleName, _, moduleId(), loc modDef, _>}, str newName, TModel tm, Renamer r) {
// We get the module location from the uses. If there are no uses, this is skipped.
// That's intended, since this function is only supposed to rename uses.
if ({loc u, *_} := tm.useDef<0>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import util::Maybe;

bool isFormalId(IdRole role) = role in formalRoles;

tuple[type[Tree] as, str desc] asType(IdRole idRole, _) = <#Name, "formal parameter name"> when isFormalId(idRole);
tuple[type[Tree] as, str desc] asRoleType(IdRole idRole, _) = <#Name, "formal parameter name"> when isFormalId(idRole);

tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{<loc scope, _, _, IdRole role, _, _>}, list[Tree] cursor, str newName, Tree(loc) _, Renamer _) =
<{scope.top}, {scope.top}, singleNameFilter(newName)(cursor[-1]) ? {scope.top} : {}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ public set[Define] findAdditionalDataLikeDefinitions(set[Define] defs, TModel tm
};
}

tuple[type[Tree] as, str desc] asType(aliasId(), _) = <#Name, "type name">;
tuple[type[Tree] as, str desc] asType(annoId(), _) = <#Name, "annotation name">;
tuple[type[Tree] as, str desc] asType(dataId(), _) = <#Name, "ADT name">;
tuple[type[Tree] as, str desc] asType(typeVarId(), _) = <#Name, "type variable name">;
tuple[type[Tree] as, str desc] asRoleType(aliasId(), _) = <#Name, "type name">;
tuple[type[Tree] as, str desc] asRoleType(annoId(), _) = <#Name, "annotation name">;
tuple[type[Tree] as, str desc] asRoleType(dataId(), _) = <#Name, "ADT name">;
tuple[type[Tree] as, str desc] asRoleType(typeVarId(), _) = <#Name, "type variable name">;

alias Environment = tuple[TModel tm, map[str, loc] defs];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,21 @@ import analysis::typepal::TModel;
import util::Maybe;

// Variables
tuple[type[Tree] as, str desc] asType(variableId(), _) = <#Name, "variable name">;
tuple[type[Tree] as, str desc] asRoleType(variableId(), _) = <#Name, "variable name">;

tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{<loc scope, _, _, variableId(), _, _>}, list[Tree] cursor, str newName, Tree(loc) _, Renamer _) =
<{scope.top}, {scope.top}, singleNameFilter(newName)(cursor[-1]) ? {scope.top} : {}>;

// Global variables
tuple[type[Tree] as, str desc] asType(moduleVariableId(), _) = <#Name, "variable name">;
tuple[type[Tree] as, str desc] asRoleType(moduleVariableId(), _) = <#Name, "variable name">;

tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{<loc scope, _, _, moduleVariableId(), _, defType(_, vis=privateVis())>}, list[Tree] cursor, str newName, Tree(loc) getTree, Renamer r) {
<curUseFiles, newFiles> = filterFiles(getSourceFiles(r), "<cursor[0]>", newName, getTree);
return <{scope.top}, curUseFiles, newFiles>;
}

// Pattern variables
tuple[type[Tree] as, str desc] asType(patternVariableId(), _) = <#Name, "pattern variable name">;
tuple[type[Tree] as, str desc] asRoleType(patternVariableId(), _) = <#Name, "pattern variable name">;

tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{<loc scope, _, _, patternVariableId(), _, _>}, list[Tree] cursor, str newName, Tree(loc) _, Renamer _) =
<{scope.top}, {scope.top}, singleNameFilter(newName)(cursor[-1]) ? {scope.top} : {}>;
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import List;
import Set;
import util::Benchmark;
import util::Math;
import Message;
import analysis::diff::edits::TextEdits;

loc rascalProj(loc projDir) = projDir + "rascal";
Expand Down Expand Up @@ -66,9 +67,9 @@ map[str, num] benchmarks(loc projDir) = benchmark((
// , "[rascal] nonterminal label": run(rascalProj(projDir), "src/org/rascalmpl/library/lang/rascal/syntax/Rascal.rsc", "lhs", newName = "lefthandside", libs = [typepalLib])
), safeRuns(3, intMedian, realTimeOf));

num(void()) safeRuns(int numRuns, num(list[num]) aggregate, int(void()) measure) = int(void() f) {
num(void()) safeRuns(int numRuns, num(list[num]) aggregate, int(void()) measure) = num(void() f) {
try {
return aggregate([measure(f) | _ <- [0..numRuns]]);
return aggregate([n | _ <- [0..numRuns], num n := measure(f)]);
} catch e: {
println("[ERROR] <e>");
return -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Set;
import lang::rascal::lsp::refactor::Rename;
import lang::rascal::tests::rename::TestUtils;
import lang::rascalcore::check::Checker;
import analysis::diff::edits::TextEdits;

test bool deepModule() = testRenameOccurrences({
byText("some::path::to::Foo", "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ Edits testProjectOnDisk(loc projectDir, str file, str oldName, int occurrence =
);
}
// extension for Rascal compiler
pcfg = pcfg[resources = pcfg.bin];
pcfg = pcfg[resources = [pcfg.bin]];
return getEdits(projectDir + file, {projectDir}, occurrence, oldName, newName, PathConfig(_) { return pcfg; });
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,6 @@ bool testRenameOccurrences(set[TestModule] modules, str oldName = "foo", str new
for (mm <- modules, cursorOcc <- (mm.nameOccs - mm.skipCursors)) {
success = success && testProject(modules, "Test_<mm.name>_<cursorOcc>", bool(set[TestModule] modulesByLocation, loc testDir, PathConfig pcfg) {
<cursor, focus> = findCursor([m.file | m <- modulesByLocation, m.name == mm.name][0], oldName, cursorOcc);

println("Renaming \'<oldName>\' from <focus[0].src>");
<edits, msgs> = rascalRenameSymbol(cursor, focus, newName, toSet(pcfg.srcs), PathConfig(loc _) { return pcfg; });

throwMessagesIfError(msgs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ test bool dataTypesInIIModuleStructure() = testRenameOccurrences({
'bool func(Foo foo) = foo == g();", {})
}, oldName = "Foo", newName = "Bar");

test bool asType() = testRenameOccurrences({0, 1}, "
test bool asRoleType() = testRenameOccurrences({0, 1}, "
'str s = \"text\";
'if (t := [Foo] s) {
' str u = t;
Expand Down
2 changes: 1 addition & 1 deletion rascal-lsp/src/main/rascal/lsp/util/Util.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ bool isPrefixOf(loc prefix, loc l) = l.scheme == prefix.scheme
@synopsis{
Try to parse string `name` as reified type `begin` and return whether this succeeded.
}
Maybe[&T] tryParseAs(type[&T <: Tree] begin, str name, bool allowAmbiguity = false) {
Maybe[&T <: Tree] tryParseAs(type[&T <: Tree] begin, str name, bool allowAmbiguity = false) {
try {
return just(parse(begin, name, allowAmbiguity = allowAmbiguity));
} catch ParseError(_): {
Expand Down
Loading