Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 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