Skip to content

Commit

Permalink
cnescatlab#49 cnescatlab#121 Added SH.FLOW.CheckCodeReturn rule, with…
Browse files Browse the repository at this point in the history
… localization

(including case-esac). Tests updated accordingly.
Issue cnescatlab#137 remains valid).
  • Loading branch information
brigittehuynh committed Jul 22, 2018
1 parent 6168528 commit f766090
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 10 deletions.
110 changes: 102 additions & 8 deletions fr.cnes.analysis.tools.shell.rules/lex/SHFLOWCheckCodeReturn.lex
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.EmptyStackException;
import java.util.Stack;

import org.eclipse.core.runtime.Path;

import fr.cnes.analysis.tools.analyzer.datas.AbstractChecker;
import fr.cnes.analysis.tools.analyzer.datas.CheckResult;
import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
import fr.cnes.analysis.tools.shell.metrics.Function;

%%

Expand All @@ -40,19 +43,31 @@ import fr.cnes.analysis.tools.analyzer.exception.JFlexException;
%type List<CheckResult>


%state COMMENT, NAMING, CHECKRET, FINLINE, COMMENTARGS, PIPELINE
%state COMMENT, NAMING, CHECKRET, FINLINE, COMMENTARGS, PIPELINE, BEGINFUNC, STRING_SIMPLE, STRING_DOUBLE

COMMENT_WORD = \#
SPACE = [\ \r\t\f]
FUNCTION = "function"
FUNCT = {VAR}{SPACE}*\(\)
VAR = [a-zA-Z][a-zA-Z0-9\_]*
STRING = \'[^\']*\' | \"[^\"]*\"

FUNCSTART = \{ | \( | \(\( | \[\[ | "if" | "case" | "select" | "for" | "while" | "until"
FUNCEND = \} | \) | \)\) | \]\] | "fi" | "esac" | "done"

STRING_D = \"
IGNORE_STRING_D = [\\][\"]
STRING_S = \'
IGNORE_STRING_S = [\\][\']


%{
private String location = "MAIN PROGRAM";
/* MAINPROGRAM: constant for main program localisation */
private static final String MAINPROGRAM = "MAIN PROGRAM";

String location = MAINPROGRAM;
/* functionLine: the beginning line of the function */
int functionLine = 0;

private String parsedFileName;
/** Map with each function name and if contains a return or not **/
private Map<String,Boolean> functions = new HashMap<String,Boolean>();
Expand All @@ -65,6 +80,8 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/** Last function called **/
private String functionCall = "";

private Stack<Function> functionStack = new Stack<>();

public SHFLOWCheckCodeReturn() {
/** The command 'cd' must be checked as the functions **/
functions.put("awk",true);
Expand Down Expand Up @@ -117,7 +134,23 @@ STRING = \'[^\']*\' | \"[^\"]*\"
this.parsedFileName = file.toString();
this.zzReader = new FileReader(new Path(file.getAbsolutePath()).toOSString());
}


private void endLocation() throws JFlexException {
try{
Function functionFinished = functionStack.pop();
if (!functionStack.empty()) {
/* there is a current function: change location to this function */
location = functionStack.peek().getName();
} else {
/* we are in the main program: change location to main */
location = MAINPROGRAM;
}
}catch(EmptyStackException e){
final String errorMessage = e.getMessage();
throw new JFlexException(this.getClass().getName(), parsedFileName,
errorMessage, yytext(), yyline, yycolumn);
}
}

%}

Expand Down Expand Up @@ -149,7 +182,7 @@ STRING = \'[^\']*\' | \"[^\"]*\"
/************************/
<NAMING>
{
{VAR} {location = yytext(); functions.put(location, false); yybegin(YYINITIAL);}
{VAR} {location = yytext(); functions.put(location, false); yybegin(BEGINFUNC);}
\n {yybegin(YYINITIAL);}
. {}
}
Expand All @@ -160,9 +193,10 @@ STRING = \'[^\']*\' | \"[^\"]*\"
<YYINITIAL>
{
{COMMENT_WORD} {yybegin(COMMENT);}
{FUNCTION} {location = yytext(); yybegin(NAMING);}
{FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); functions.put(location, false);}
{STRING} {}
{STRING_D} {yybegin(STRING_DOUBLE);}
{STRING_S} {yybegin(STRING_SIMPLE);}
{FUNCTION} {yybegin(NAMING);}
{FUNCT} {location = yytext().substring(0,yytext().length()-2).trim(); functions.put(location, false); yybegin(BEGINFUNC);}
{VAR} {Boolean found = functions.get(yytext());
if(found!=null) {
functionCalled=true;
Expand All @@ -173,6 +207,24 @@ STRING = \'[^\']*\' | \"[^\"]*\"
} else {
functionCalled=false;
}}
{FUNCSTART} {
if(!functionStack.empty()){
if(functionStack.peek().getFinisher().equals(Function.finisherOf(yytext()))){
functionStack.peek().addStarterRepetition();
}
}
}
{FUNCEND} {
if(!functionStack.empty()){
if(functionStack.peek().isFinisher(yytext())){
if(functionStack.peek().getStarterRepetition()>0) {
functionStack.peek().removeStarterRepetition();
} else {
endLocation();
}
}
}
}
[^] {}
}

Expand Down Expand Up @@ -237,6 +289,48 @@ STRING = \'[^\']*\' | \"[^\"]*\"
. {}
}

/************************/
/* BEGINFUNC STATE */
/************************/
/*
* This state target is to retrieve the function starter. For more information on fonction starter, have a look on {@link Function} class.
* Pending this starter, the function ender can be defined.
*
*/
<BEGINFUNC>
{
\(\) {}
{FUNCSTART} {
Function function;
function = new Function(location, functionLine, yytext());
functionStack.push(function);
yybegin(YYINITIAL);
}
[^]|{SPACE} {}
}

/*
* The string states are designed to avoid problems due to patterns found in strings.
*/
/************************/
/* STRING_SIMPLE STATE */
/************************/
<STRING_SIMPLE>
{
{IGNORE_STRING_S} {}
{STRING_S} {yybegin(YYINITIAL);}
[^]|{SPACE} {}
}

/************************/
/* STRING_DOUBLE STATE */
/************************/
<STRING_DOUBLE>
{
{IGNORE_STRING_D} {}
{STRING_D} {yybegin(YYINITIAL);}
[^]|{SPACE} {}
}

/************************/
/* ERROR STATE */
Expand Down
5 changes: 5 additions & 0 deletions fr.cnes.analysis.tools.shell.rules/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@
id="fr.cnes.analysis.tools.shell.rules.SHFLOWCheckArguments"
name="SH.FLOW.CheckArguments" languageId="fr.cnes.analysis.tools.languages.shell">
</check>
<check
class="fr.cnes.analysis.tools.shell.rules.SHFLOWCheckCodeReturn"
id="fr.cnes.analysis.tools.shell.rules.SHFLOWCheckCodeReturn"
name="SH.FLOW.CheckCodeReturn" languageId="fr.cnes.analysis.tools.languages.shell">
</check>
<check
class="fr.cnes.analysis.tools.shell.rules.SHFLOWCheckUser"
id="fr.cnes.analysis.tools.shell.rules.SHFLOWCheckUser"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public class TestSHFLOWCheckCodeReturn {
public final static String ERROR_FILE = "error.sh";
public final static String NO_ERROR_FILE = "noError.sh";
public final static int[] LINES = { 29, 32, 34, 35, 40, 44, 46 };
public final static String[] LOCATIONS = { "factorial", "factorial", "factorial", "factorial",
"nettoyer_repertoire", "nettoyer_repertoire", "nettoyer_repertoire" };
public final static String[] LOCATIONS = { "MAIN PROGRAM", "MAIN PROGRAM", "MAIN PROGRAM", "MAIN PROGRAM",
"nettoyer_repertoire", "MAIN PROGRAM", "MAIN PROGRAM" };
public final AbstractChecker rule = new SHFLOWCheckCodeReturn();

/**
Expand Down

0 comments on commit f766090

Please # to comment.