Skip to content

Commit

Permalink
Fix support ? in parameter let section
Browse files Browse the repository at this point in the history
Fixes redhat-developer#906

Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
angelozerr committed Jul 21, 2023
1 parent 85b64e3 commit 9fe2885
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class Parameter extends Node implements JavaTypeInfoProvider {

private ParametersContainer container;

private boolean hasDefaultValue; // #let name?="foo"

public Parameter(int start, int end) {
super(start, end);
this.startName = start;
Expand Down Expand Up @@ -109,9 +111,11 @@ public String getName() {
if (name == null) {
int endName = getEndName();
Section section = getOwnerSection();
if (section != null && section.getSectionKind() == SectionKind.LET) {
if (section != null
&& (section.getSectionKind() == SectionKind.LET || section.getSectionKind() == SectionKind.SET)) {
String text = getOwnerTemplate().getText();
if (text.charAt(endName - 1) == '?') {
hasDefaultValue = true;
// ex : {#let name?"=main"}
// name? --> name
endName--;
Expand Down Expand Up @@ -241,4 +245,17 @@ public boolean isOptional() {
Expression expression = getJavaTypeExpression();
return expression != null ? expression.isOptional() : false;
}

/**
* Returns true if the parameter uses '?' to assign value (ex : #let
* name?="foo")
* which means that name has default value and false other.
*
* @return true if the parameter uses '?' to assign value (ex : #let
* name?="foo")
* which means that name has default value and false other.
*/
public boolean hasDefaultValue() {
return hasDefaultValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,38 @@ private List<String> createBody() {
*/
public static void generateUserTagParameter(UserTagParameter parameter, boolean snippetsSupported, int index,
StringBuilder snippet) {
// Generate parameter name
snippet.append(parameter.getName());
snippet.append("=");
snippet.append("\"");

// Generate parameter value
String value = parameter.getName();
char quote = '"';
String defaultValue = parameter.getDefaultValue();
if (defaultValue != null && !defaultValue.isEmpty()) {
value = defaultValue;
// there is a default value, remove the quote if needed
char start = defaultValue.charAt(0);
if (start == '"' || start == '\'') {
quote = start;
value = value.substring(1, value.length() - (value.endsWith(start + "") ? 1 : 0));
} else {
quote = (char) -1;
}
}

if (quote != -1) {
snippet.append(quote);
}

if (snippetsSupported) {
SnippetsBuilder.placeholders(index, parameter.getName(), snippet);
SnippetsBuilder.placeholders(index, value, snippet);
} else {
snippet.append(parameter.getName());
snippet.append(value);
}
if (quote != -1) {
snippet.append(quote);
}
snippet.append("\"");

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,21 @@ public class UserTagParameter {

private boolean required;

private String defaultValue;

public UserTagParameter(String name) {
this.name = name;
}

/**
* Returns the user tag parameter name.
*
* @return the user tag parameter name.
*/
public String getName() {
return name;
}

/**
* Set the required flag.
*
Expand All @@ -45,12 +56,14 @@ public Boolean isRequired() {
return required;
}

/**
* Returns the user tag parameter name.
*
* @return the user tag parameter name.
*/
public String getName() {
return name;
public String getDefaultValue() {
return defaultValue;
}

public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
if (defaultValue != null) {
setRequired(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,26 @@ public class UserTagParameterCollector extends ASTVisitor {

private final Map<String, UserTagParameter> parameters;

private final List<List<String>> optionalParameterNamesStack;

private final List<List<String>> ignoreParameterNamesStack;
private final List<List<ParamInfo>> parameterNamesStack;

private List<String> globalVariables;

private static class ParamInfo {
public final String name;
public final boolean assigned; // true if parameter comes from a #let, #set and false otherwise.
public final String defaultValue; // ex : name?="foo", the default value is "foo"

public ParamInfo(String name, boolean assigned, String defaultValue) {
this.name = name;
this.assigned = assigned;
this.defaultValue = defaultValue;
}
}

public UserTagParameterCollector(QuteProject project) {
this.project = project;
this.parameters = new LinkedHashMap<>();
this.optionalParameterNamesStack = new ArrayList<>();
this.ignoreParameterNamesStack = new ArrayList<>();
this.parameterNamesStack = new ArrayList<>();
}

@Override
Expand All @@ -68,69 +77,66 @@ public boolean visit(IfSection node) {

@Override
public void endVisit(IfSection node) {
removeOptionalStack();
removeParameterStack();
super.endVisit(node);
}

private void addOptionalStack(Section node) {
List<String> optionalParameterNames = null;
List<ParamInfo> optionalParameterNames = null;
List<Parameter> parameters = node.getParameters();
for (Parameter parameter : parameters) {
String name = parameter.getName();
if (!StringUtils.isEmpty(name) && (parameter.isOptional())) {
if (optionalParameterNames == null) {
optionalParameterNames = new ArrayList<>();
}
optionalParameterNames.add(name);
optionalParameterNames.add(new ParamInfo(name, false, null));
}
}
optionalParameterNamesStack
parameterNamesStack
.add(optionalParameterNames != null ? optionalParameterNames : Collections.emptyList());
}

private void removeOptionalStack() {
optionalParameterNamesStack.remove(optionalParameterNamesStack.size() - 1);
private void removeParameterStack() {
parameterNamesStack.remove(parameterNamesStack.size() - 1);
}

public boolean visit(LetSection node) {
addIgnoreStack(node);
addAssignedParameterStack(node);
return super.visit(node);
}

@Override
public void endVisit(LetSection node) {
removeIgnoreStack();
removeParameterStack();
super.endVisit(node);
}

public boolean visit(SetSection node) {
addIgnoreStack(node);
addAssignedParameterStack(node);
return super.visit(node);
}

@Override
public void endVisit(SetSection node) {
removeIgnoreStack();
removeParameterStack();
super.endVisit(node);
}

private void addIgnoreStack(Section node) {
List<String> ignoreParameterNames = null;
private void addAssignedParameterStack(Section node) {
List<ParamInfo> declaredParameterNames = null;
List<Parameter> parameters = node.getParameters();
for (Parameter parameter : parameters) {
String name = parameter.getName();
String defaultValue = parameter.hasDefaultValue() ? parameter.getValue() : null;
if (!StringUtils.isEmpty(name)) {
if (ignoreParameterNames == null) {
ignoreParameterNames = new ArrayList<>();
if (declaredParameterNames == null) {
declaredParameterNames = new ArrayList<>();
}
ignoreParameterNames.add(name);
declaredParameterNames.add(new ParamInfo(name, true, defaultValue));
}
}
ignoreParameterNamesStack.add(ignoreParameterNames != null ? ignoreParameterNames : Collections.emptyList());
}

private void removeIgnoreStack() {
ignoreParameterNamesStack.remove(ignoreParameterNamesStack.size() - 1);
parameterNamesStack.add(declaredParameterNames != null ? declaredParameterNames : Collections.emptyList());
}

@Override
Expand All @@ -147,28 +153,37 @@ public boolean visit(MethodPart node) {
@Override
public boolean visit(ObjectPart node) {
if (isValid(node)) {
String partName = node.getPartName();

for (List<String> ignoreNames : ignoreParameterNamesStack) {
if (ignoreNames.contains(partName)) {
return super.visit(node);
}
String partName = node.getPartName(); // {foo}

// Get the parameter info from the parameter stack
ParamInfo paramInfo = getParamInfo(partName);
if (paramInfo != null && paramInfo.assigned && paramInfo.defaultValue == null) {
// The part name (foo) is defined in parent section #let, #set
// which have not default value
// {#let foo="bar"}
// {foo}
// It is not a user tag parameter.
return super.visit(node);
}

// Here we are in several usecase:
// 1. foo is not declared in none parent section -> user tag parameter is
// required
// 2. foo is declared in #if section -> user tag parameter is optional
// 3. foo is declared in #let section with default value (#let foo?="bar") ->
// user tag parameter is optional and have a defaut value

// Get or create the user tag parameter
UserTagParameter parameter = parameters.get(partName);
if (parameter == null) {
parameter = new UserTagParameter(partName);
parameter.setDefaultValue(paramInfo != null ? paramInfo.defaultValue : null);
parameters.put(partName, parameter);
}
// Compute required flag if needed
if (!parameter.isRequired()) {
boolean ignore = false;
for (List<String> optionalNames : optionalParameterNamesStack) {
if (optionalNames.contains(partName)) {
ignore = true;
}
}

// Compute user tag parameter required flag if needed
if (!parameter.isRequired() && parameter.getDefaultValue() == null) {
boolean ignore = paramInfo != null && !paramInfo.assigned;
if (!ignore) {
boolean required = true;
Parts parts = node.getParent();
Expand All @@ -191,6 +206,17 @@ public boolean visit(ObjectPart node) {
return super.visit(node);
}

private ParamInfo getParamInfo(String partName) {
for (List<ParamInfo> params : parameterNamesStack) {
for (ParamInfo paramInfo : params) {
if (paramInfo.name.equals(partName)) {
return paramInfo;
}
}
}
return null;
}

public boolean isValid(ObjectPart node) {
if (node.getNamespace() != null) {
// ex : {uri:Login....}
Expand Down
Loading

0 comments on commit 9fe2885

Please sign in to comment.