Skip to content

Commit

Permalink
add new rule "Break before DEFINE etc."
Browse files Browse the repository at this point in the history
  • Loading branch information
jmgrassau committed Sep 9, 2024
1 parent 4428678 commit 98fea0c
Show file tree
Hide file tree
Showing 7 changed files with 548 additions and 289 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.sap.adt.abapcleaner.rules.ddl.position.DdlPositionAssociationRule;
import com.sap.adt.abapcleaner.rules.ddl.position.DdlPositionBracesRule;
import com.sap.adt.abapcleaner.rules.ddl.position.DdlPositionClausesRule;
import com.sap.adt.abapcleaner.rules.ddl.position.DdlPositionDefineRule;
import com.sap.adt.abapcleaner.rules.ddl.position.DdlPositionJoinRule;
import com.sap.adt.abapcleaner.rules.ddl.position.DdlPositionSelectRule;
import com.sap.adt.abapcleaner.rules.ddl.annotations.DdlAnnotationLayoutRule;
Expand All @@ -27,7 +28,7 @@
import java.util.*;

public abstract class Rule {
public static final int RULE_COUNT = 82;
public static final int RULE_COUNT = 83;
public static final int RULE_GROUP_COUNT = 9;

protected static final String LINE_SEP = ABAP.LINE_SEPARATOR;
Expand Down Expand Up @@ -160,6 +161,7 @@ static Rule[] getAllRules(Profile profile) {
new DdlAnnotationNestingRule(profile),

// DDL position
new DdlPositionDefineRule(profile),
new DdlPositionSelectRule(profile),
new DdlPositionJoinRule(profile),
new DdlPositionAssociationRule(profile),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public enum RuleID {
DDL_ANNO_NESTING,

// DDL Positions
DDL_POSITION_DEFINE,
DDL_POSITION_SELECT,
DDL_POSITION_JOIN,
DDL_POSITION_ASSOCIATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ protected boolean breakBefore(Token token, DdlLineBreak lineBreak, boolean empty

// adjust the indent of the supplied Token (or the attached non-annotation comments above it)
int lineBreaksMin = emptyLineIfBreaking ? 2 : 1;
if (token.getPrev() == null && token.getParentCommand().isFirstCommandInCode()) // e.g. for DEFINE
lineBreaksMin = 0;
int lineBreaksMax = 2;
setWhitespaceInclAttachedComments(token, lineBreaksMin, lineBreaksMax, indent, false);
return false; // .addRuleUse() was already called above for all involved commands
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.sap.adt.abapcleaner.rules.ddl.position;

import java.time.LocalDate;

import com.sap.adt.abapcleaner.parser.Code;
import com.sap.adt.abapcleaner.parser.Command;
import com.sap.adt.abapcleaner.parser.Token;
import com.sap.adt.abapcleaner.parser.TokenSearch;
import com.sap.adt.abapcleaner.programbase.IntegrityBrokenException;
import com.sap.adt.abapcleaner.programbase.UnexpectedSyntaxAfterChanges;
import com.sap.adt.abapcleaner.programbase.UnexpectedSyntaxBeforeChanges;
import com.sap.adt.abapcleaner.rulebase.ConfigEnumValue;
import com.sap.adt.abapcleaner.rulebase.ConfigIntValue;
import com.sap.adt.abapcleaner.rulebase.ConfigValue;
import com.sap.adt.abapcleaner.rulebase.Profile;
import com.sap.adt.abapcleaner.rulebase.RuleID;
import com.sap.adt.abapcleaner.rulebase.RuleReference;
import com.sap.adt.abapcleaner.rulebase.RuleSource;
import com.sap.adt.abapcleaner.rulehelpers.RuleForDdlPosition;

public class DdlPositionDefineRule extends RuleForDdlPosition {
private final static RuleReference[] references = new RuleReference[] { new RuleReference(RuleSource.ABAP_CLEANER) };

@Override
public RuleID getID() { return RuleID.DDL_POSITION_DEFINE; }

@Override
public String getDisplayName() { return "Break before DEFINE etc."; }

@Override
public String getDescription() { return "Standardizes line breaks and indentation before DEFINE / EXTEND etc. keywords, entity name and WITH PARAMETERS."; }

@Override
public LocalDate getDateCreated() { return LocalDate.of(2024, 9, 9); }

@Override
public RuleReference[] getReferences() { return references; }

@Override
public String getExample() {
return ""
+ LINE_SEP + "@EndUserText.label: 'Any Description' define"
+ LINE_SEP + " view"
+ LINE_SEP + " entity"
+ LINE_SEP + "C_AnyEntity with"
+ LINE_SEP + "parameters"
+ LINE_SEP + "// comment"
+ LINE_SEP + "P_AnyParam : AnyType,"
+ LINE_SEP + " P_OtherParam : OtherType,"
+ LINE_SEP + " P_ThirdParam : ThirdType"
+ LINE_SEP + ""
+ LINE_SEP + " as select from I_AnyEntity as AnyAlias"
+ LINE_SEP + ""
+ LINE_SEP + " left outer to one join I_OtherEntity as OtherAlias"
+ LINE_SEP + " on AnyAlias.IdField = OtherAlias.IdField"
+ LINE_SEP + ""
+ LINE_SEP + "{"
+ LINE_SEP + " key AnyAlias.AnyKeyField,"
+ LINE_SEP + " OtherAlias.AnyNonKeyField"
+ LINE_SEP + "}";
}

final ConfigEnumValue<DdlLineBreakWithoutNever> configBreakBeforeDefine = new ConfigEnumValue<DdlLineBreakWithoutNever>(this, "BreakBeforeDefine", "Break before DEFINE etc. keywords:", lineBreakSelectionWithoutNever, DdlLineBreakWithoutNever.values(), DdlLineBreakWithoutNever.ALWAYS);
final ConfigIntValue configDefineIndent = new ConfigIntValue(this, "DefineIndent", "Indent if breaking:", "", 0, 0, MAX_INDENT);

final ConfigEnumValue<DdlLineBreak> configBreakBeforeEntityName = new ConfigEnumValue<DdlLineBreak>(this, "BreakBeforeEntityName", "Break before entity name:", lineBreakSelection, DdlLineBreak.values(), DdlLineBreak.NEVER);
final ConfigIntValue configEntityNameIndent = new ConfigIntValue(this, "EntityNameIndent", "Indent if breaking:", "", 0, 2, MAX_INDENT);

final ConfigEnumValue<DdlLineBreak> configBreakBeforeWithParams = new ConfigEnumValue<DdlLineBreak>(this, "BreakBeforeWithParams", "Break before WITH PARAMETERS:", lineBreakSelection, DdlLineBreak.values(), DdlLineBreak.ALWAYS);
final ConfigIntValue configWithParamsIndent = new ConfigIntValue(this, "WithParamsIndent", "Indent if breaking:", "", 0, 2, MAX_INDENT);
final ConfigIntValue configParamsIndent = new ConfigIntValue(this, "ParamsIndent", "Indent of parameters:", "", 0, 4, MAX_INDENT);

private final ConfigValue[] configValues = new ConfigValue[] { configBreakBeforeDefine, configDefineIndent, configBreakBeforeEntityName, configEntityNameIndent, configBreakBeforeWithParams, configWithParamsIndent, configParamsIndent };

@Override
public ConfigValue[] getConfigValues() { return configValues; }

public DdlPositionDefineRule(Profile profile) {
super(profile);
initializeConfiguration();
}

// -------------------------------------------------------------------------

@Override
protected boolean executeOn(Code code, Command command) throws UnexpectedSyntaxBeforeChanges, UnexpectedSyntaxAfterChanges, IntegrityBrokenException {
boolean changed = false;

if (command.isDdlAnnotation())
return false;

Token firstCode = command.getFirstCodeToken();
if (firstCode == null) // pro forma
return false;

DdlLineBreak breakBeforeDefine = getLineBreak(DdlLineBreakWithoutNever.forValue(configBreakBeforeDefine.getValue()));
DdlLineBreak breakBeforeEntityName = DdlLineBreak.forValue(configBreakBeforeEntityName.getValue());
DdlLineBreak breakBeforeWithParams = DdlLineBreak.forValue(configBreakBeforeWithParams.getValue());

// break before DEFINE etc., condense definition keywords and (un)break before entity name
Token entityName = command.getDdlOrDclEntityNameToken();
if (entityName != null) {
boolean emptyLine = (command.getPrev() != null);
changed |= breakBefore(firstCode, breakBeforeDefine, emptyLine, configDefineIndent.getValue());
changed |= condense(firstCode, entityName.getPrevCodeToken());

changed |= breakBefore(entityName, breakBeforeEntityName, false, configEntityNameIndent.getValue());
}

// (un)break before "WITH PARAMETERS"
Token parametersToken = firstCode.getLastTokenOnSiblings(true, TokenSearch.ASTERISK, "WITH", "PARAMETERS");
if (parametersToken != null) {
Token withToken = parametersToken.getPrevCodeSibling();
changed |= breakBefore(withToken, breakBeforeWithParams, false, configWithParamsIndent.getValue());
changed |= condense(withToken, parametersToken);

// set indent of parameters, their annotations and comments
Command paramCommand = command.getFirstChild();
int paramIndent = configParamsIndent.getValue();
while (paramCommand != null) {
// do not move comments at the end of the parameter list, as they probably belong to the following Command
if (paramCommand.isCommentLine() && paramCommand.getNextNonCommentSibling() == null)
break;
paramCommand = setNewIndent(paramCommand, paramIndent);
if (paramCommand == null) // pro forma
break;
paramCommand = paramCommand.getNextSibling();
}
}

return changed;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,8 @@ public class DdlPositionSelectRule extends RuleForDdlPosition {
@Override
public String getExample() {
return ""
+ LINE_SEP + "define view entity C_AnyEntity with"
+ LINE_SEP + "parameters"
+ LINE_SEP + "// comment"
+ LINE_SEP + "P_AnyParam : AnyType,"
+ LINE_SEP + " P_OtherParam : OtherType,"
+ LINE_SEP + " P_ThirdParam : ThirdType as select from I_AnyEntity as AnyAlias"
+ LINE_SEP + "define view entity C_AnyEntity as select"
+ LINE_SEP + "from I_AnyEntity as AnyAlias"
+ LINE_SEP + ""
+ LINE_SEP + " left outer to one join I_OtherEntity as OtherAlias"
+ LINE_SEP + " on AnyAlias.IdField = OtherAlias.IdField"
Expand Down Expand Up @@ -75,13 +71,6 @@ public String getExample() {
+ LINE_SEP + "}";
}

final ConfigEnumValue<DdlLineBreak> configBreakBeforeEntityName = new ConfigEnumValue<DdlLineBreak>(this, "BreakBeforeEntityName", "Break before entity name:", lineBreakSelection, DdlLineBreak.values(), DdlLineBreak.NEVER);
final ConfigIntValue configEntityNameIndent = new ConfigIntValue(this, "EntityNameIndent", "Indent if breaking:", "", 0, 2, MAX_INDENT);

final ConfigEnumValue<DdlLineBreak> configBreakBeforeWithParams = new ConfigEnumValue<DdlLineBreak>(this, "BreakBeforeWithParams", "Break before WITH PARAMETERS:", lineBreakSelection, DdlLineBreak.values(), DdlLineBreak.ALWAYS);
final ConfigIntValue configWithParamsIndent = new ConfigIntValue(this, "WithParamsIndent", "Indent if breaking:", "", 0, 2, MAX_INDENT);
final ConfigIntValue configParamsIndent = new ConfigIntValue(this, "ParamsIndent", "Indent of parameters:", "", 0, 4, MAX_INDENT);

final ConfigEnumValue<DdlLineBreak> configBreakBeforeAsSelectFrom = new ConfigEnumValue<DdlLineBreak>(this, "BreakBeforeAsSelectFrom", "Break before AS SELECT FROM:", lineBreakSelection, DdlLineBreak.values(), DdlLineBreak.ALWAYS);
final ConfigIntValue configAsSelectFromIndent = new ConfigIntValue(this, "AsSelectFromIndent", "Indent if breaking:", "", 0, 2, MAX_INDENT);

Expand All @@ -94,14 +83,7 @@ public String getExample() {
final ConfigEnumValue<DdlLineBreak> configBreakBeforeDataSource = new ConfigEnumValue<DdlLineBreak>(this, "BreakBeforeDataSource", "Break before data source:", lineBreakSelection, DdlLineBreak.values(), DdlLineBreak.NEVER);
final ConfigIntValue configDataSourceIndent = new ConfigIntValue(this, "DataSourceIndent", "Indent if breaking:", "", 0, 4, MAX_INDENT);

private final ConfigValue[] configValues = new ConfigValue[] {
configBreakBeforeEntityName, configEntityNameIndent,
configBreakBeforeWithParams, configWithParamsIndent, configParamsIndent,
configBreakBeforeAsSelectFrom, configAsSelectFromIndent,
configBreakBeforeSelectFrom, configSelectFromIndent,
configBreakBeforeAsProjectionOn, configAsProjectionOnIndent,
configBreakBeforeDataSource, configDataSourceIndent
};
private final ConfigValue[] configValues = new ConfigValue[] { configBreakBeforeAsSelectFrom, configAsSelectFromIndent, configBreakBeforeSelectFrom, configSelectFromIndent, configBreakBeforeAsProjectionOn, configAsProjectionOnIndent, configBreakBeforeDataSource, configDataSourceIndent };

@Override
public ConfigValue[] getConfigValues() { return configValues; }
Expand All @@ -117,45 +99,13 @@ public DdlPositionSelectRule(Profile profile) {
protected boolean executeOn(Code code, Command command) throws UnexpectedSyntaxBeforeChanges, UnexpectedSyntaxAfterChanges, IntegrityBrokenException {
boolean changed = false;

DdlLineBreak breakBeforeEntityName = DdlLineBreak.forValue(configBreakBeforeEntityName.getValue());
DdlLineBreak breakBeforeWithParams = DdlLineBreak.forValue(configBreakBeforeWithParams.getValue());
DdlLineBreak breakBeforeAsSelectFrom = DdlLineBreak.forValue(configBreakBeforeAsSelectFrom.getValue());
DdlLineBreak breakBeforeSelectFrom = DdlLineBreak.forValue(configBreakBeforeSelectFrom.getValue());
DdlLineBreak breakBeforeAsProjectionOn = DdlLineBreak.forValue(configBreakBeforeAsProjectionOn.getValue());

// condense definition keywords and (un)break before entity name
if (breakBeforeEntityName != DdlLineBreak.KEEP_AS_IS) {
Token entityName = command.getDdlOrDclEntityNameToken();
if (entityName != null) {
changed |= condense(command.getFirstCodeToken(), entityName.getPrevCodeToken());
changed |= breakBefore(entityName, breakBeforeEntityName, false, configEntityNameIndent.getValue());
}
}

Token token = command.getFirstCodeToken();

while (token != null) {
// (un)break before "WITH PARAMETERS"
Token parametersToken = token.getLastTokenOnSiblings(true, "WITH", "PARAMETERS");
if (breakBeforeWithParams != DdlLineBreak.KEEP_AS_IS && parametersToken != null) {
changed |= breakBefore(token, breakBeforeWithParams, false, configWithParamsIndent.getValue());
changed |= condense(token, parametersToken);

// set indent of parameters, their annotations and comments
Command paramCommand = command.getFirstChild();
int paramIndent = configParamsIndent.getValue();
while (paramCommand != null) {
// do not move comments at the end of the parameter list, as they probably belong to the following Command
if (paramCommand.isCommentLine() && paramCommand.getNextNonCommentSibling() == null)
break;
paramCommand = setNewIndent(paramCommand, paramIndent);
if (paramCommand == null) // pro forma
break;
paramCommand = paramCommand.getNextSibling();
}
break; // nothing else to be expected in this Command
}

// (un)break before "AS SELECT [DISTINCT] FROM"
Token fromToken = token.getLastTokenOnSiblings(true, "AS", "SELECT", TokenSearch.makeOptional("DISTINCT"), "FROM");
if (breakBeforeAsSelectFrom != DdlLineBreak.KEEP_AS_IS && fromToken != null ) {
Expand Down
Loading

0 comments on commit 98fea0c

Please sign in to comment.