Skip to content

Commit

Permalink
Merge branch 'dev' into naming
Browse files Browse the repository at this point in the history
Conflicts:
	src/main/resources/cflint.definition.xml
  • Loading branch information
justinmclean committed Oct 21, 2015
2 parents 84e5241 + b6ae000 commit 0aa29d5
Show file tree
Hide file tree
Showing 9 changed files with 427 additions and 43 deletions.
24 changes: 20 additions & 4 deletions src/main/java/com/cflint/CFLint.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
import org.antlr.runtime.RecognitionException;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;

import cfml.CFSCRIPTLexer;
import cfml.parsing.CFMLParser;
import cfml.parsing.CFMLSource;
import cfml.parsing.cfml.ErrorEvent;
import cfml.parsing.cfml.IErrorObserver;
import cfml.parsing.cfscript.CFAssignmentExpression;
import cfml.parsing.cfscript.CFBinaryExpression;
import cfml.parsing.cfscript.CFExpression;
Expand Down Expand Up @@ -165,6 +164,7 @@ public CFLint(ConfigRuntime configuration,final CFLintScanner... bugsScanners) {
allowedExtensions.add(cfcExtension);
allowedExtensions.add(cfmExtenstion);
}
cfmlParser.setErrorReporter(this);
}

public void scan(final String folder) {
Expand Down Expand Up @@ -806,7 +806,13 @@ public void syntaxError(Recognizer<?, ?> recognizer,
Object offendingSymbol, int line, int charPositionInLine,
String msg, org.antlr.v4.runtime.RecognitionException e) {
final String file = currentFile == null ? "" : currentFile + "\r\n";
//System.err.println(file + "----syntax error ---" + line + " : " + charPositionInLine);
String expression=null;
if(offendingSymbol instanceof Token){
expression = ((Token) offendingSymbol).getText();
if(expression.length() > 50){
expression=expression.substring(1,40) + "...";
}
}
if(!currentElement.isEmpty()){
Element elem = currentElement.peek();
if(line == 1){
Expand All @@ -816,7 +822,17 @@ public void syntaxError(Recognizer<?, ?> recognizer,
line = elem.getSource().getRow(elem.getBegin()) + line - 1;
}
}
fireCFLintException(e,PARSE_ERROR,currentFile,line,charPositionInLine,"",offendingSymbol==null?"":offendingSymbol.toString());
if(recognizer instanceof Parser && ((Parser)recognizer).getExpectedTokens().contains(65)){
bugs.add(new BugInfo.BugInfoBuilder().setMessageCode("MISSING_SEMI")
.setFilename(file).setMessage("End of statement(;) expected instead of " + expression).setSeverity("ERROR")
.setExpression(expression)
.setLine(line).setColumn(charPositionInLine)
.build());

}else{

fireCFLintException(e,PARSE_ERROR,file,line,charPositionInLine,"",msg);
}
}
public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex,
int stopIndex, boolean exact, java.util.BitSet ambigAlts,
Expand Down
88 changes: 52 additions & 36 deletions src/main/java/com/cflint/main/CFLintMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

import javax.swing.JFileChooser;
import javax.swing.JList;
Expand Down Expand Up @@ -57,12 +58,14 @@ public class CFLintMain {
boolean showprogress= false;
boolean progressUsesThread=true;
private String configfile = null;
private Boolean stdIn = false;
private Boolean stdOut = false;

public static void main(final String[] args) throws ParseException, IOException, TransformerException, JAXBException {
//PropertyConfigurator.configure("/log4j.properties");
//DOMConfigurator.configure(CFLintFilter.class.getResource("/log4j.xml").getFile());
//Logger.getLogger("net.htmlparser.jericho");

final Options options = new Options();
// add t option
options.addOption("includeRule", true, "specify rules to include");
Expand All @@ -76,7 +79,7 @@ public static void main(final String[] args) throws ParseException, IOException,
options.addOption("verbose", false, "verbose");
options.addOption("showprogress", false, "show progress bar");
options.addOption("singlethread", false, "show progress bar");

options.addOption("logerror", false, "log parsing errors as bugs");
options.addOption("e", false, "log parsing errors as bugs");
options.addOption("q", false, "quiet");
Expand All @@ -95,7 +98,9 @@ public static void main(final String[] args) throws ParseException, IOException,
options.addOption("textfile", true, "specify the output text file (default: cflint-results.txt)");
options.addOption("extensions", true, "specify the extensions of the CF source files (default: .cfm,.cfc)");
options.addOption("configfile", true, "specify the location of the config file");

options.addOption("stdin", false, "use stdin for file input");
options.addOption("stdout", false, "output to stdout only");


final CommandLineParser parser = new GnuParser();
final CommandLine cmd = parser.parse(options, args);
Expand Down Expand Up @@ -163,7 +168,7 @@ public static void main(final String[] args) throws ParseException, IOException,
if (cmd.hasOption("extensions")) {
main.extensions = cmd.getOptionValue("extensions");
}

if (cmd.hasOption("includeRule")) {
main.includeCodes = cmd.getOptionValue("includeRule").split(",");
}
Expand All @@ -172,11 +177,8 @@ public static void main(final String[] args) throws ParseException, IOException,
}
main.showprogress=cmd.hasOption("showprogress") || (!cmd.hasOption("showprogress") && cmd.hasOption("ui"));
main.progressUsesThread=!cmd.hasOption("singlethread");
// for (final Option option : cmd.getOptions()) {
// if(main.verbose){
// System.out.println("Option " + option.getOpt() + " => " + option.getValue());
// }
// }
main.stdIn = cmd.hasOption("stdin");
main.stdOut = cmd.hasOption("stdout");
if (main.isValid()) {
main.execute();
if (cmd.hasOption("ui")) {
Expand Down Expand Up @@ -209,7 +211,7 @@ private void open() throws IOException {
if (jsonOutput) {
Desktop.getDesktop().open(new File(jsonOutFile));
return;
}
}
}

private void ui() {
Expand Down Expand Up @@ -266,7 +268,7 @@ private void execute() throws IOException, TransformerException, JAXBException {
try{
cflint.setAllowedExtensions(Arrays.asList(extensions.trim().split(",")));
}catch(Exception e){
System.out.println("Unable to use extensions (" + extensions + ") using default instead. " + e.getMessage());
System.err.println("Unable to use extensions (" + extensions + ") using default instead. " + e.getMessage());
}
}
CFLintFilter filter = CFLintFilter.createFilter(verbose);
Expand All @@ -279,7 +281,7 @@ private void execute() throws IOException, TransformerException, JAXBException {
filter = CFLintFilter.createFilter(new String(b),verbose);
}
}

if (excludeCodes != null && excludeCodes.length > 0) {
filter.excludeCode(excludeCodes);
}
Expand All @@ -289,51 +291,59 @@ private void execute() throws IOException, TransformerException, JAXBException {
cflint.getBugs().setFilter(filter);
for (final String scanfolder : folder) {
cflint.scan(scanfolder);
// for(BugInfo bi: cflint.getBugs()){
// System.out.println(bi);
// }
}
if (xmlOutput) {
if(verbose){
System.out.println("Style:" + xmlstyle);
if (stdIn) {
StringBuilder source = new StringBuilder();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String nextLine = scanner.nextLine();
source.append(nextLine);
source.append(System.lineSeparator());
}
scanner.close();
cflint.process(source.toString(), "source.cfc");
}
if (xmlOutput) {
Writer xmlwriter = stdOut ? new OutputStreamWriter(System.out) : new FileWriter(xmlOutFile);
if ("findbugs".equalsIgnoreCase(xmlstyle)) {
if(verbose){
System.out.println("Writing findbugs style to " + xmlOutFile);
if(verbose) {
display("Writing XML findbugs style" + (stdOut ? "." : " to " + xmlOutFile));
}
new XMLOutput().outputFindBugs(cflint.getBugs(), new FileWriter(xmlOutFile));
new XMLOutput().outputFindBugs(cflint.getBugs(), xmlwriter);
} else {
if(verbose){
System.out.println("Writing " + xmlOutFile);
if(verbose) {
display("Writing XML" + (stdOut ? "." : " to " + xmlOutFile));
}
new XMLOutput().output(cflint.getBugs(), new FileWriter(xmlOutFile));
new XMLOutput().output(cflint.getBugs(), xmlwriter);
}
}
if (textOutput) {
if(textOutFile != null){
if(verbose){
System.out.println("Writing " + textOutFile);
if(verbose) {
display("Writing text" + (stdOut ? "." : " to " + textOutFile));
}
}
Writer textwriter = textOutFile != null?new FileWriter(textOutFile):new OutputStreamWriter(System.out);
Writer textwriter = stdOut ? new OutputStreamWriter(System.out) : new FileWriter(textOutFile);
new TextOutput().output(cflint.getBugs(), textwriter);

}
if (htmlOutput) {
try {
if(verbose){
System.out.println("Writing " + htmlOutFile);
if(verbose) {
display("Writing HTML" + (stdOut ? "." : " to " + htmlOutFile));
}
new HTMLOutput(htmlStyle).output(cflint.getBugs(), new FileWriter(htmlOutFile));
Writer htmlwriter = stdOut ? new OutputStreamWriter(System.out) : new FileWriter(htmlOutFile);
new HTMLOutput(htmlStyle).output(cflint.getBugs(), htmlwriter);
} catch (final TransformerException e) {
throw new IOException(e);
}
}
if (jsonOutput) {
if(verbose){
System.out.println("Writing " + jsonOutFile);
if(verbose) {
display("Writing JSON" + (stdOut ? "." : " to " + jsonOutFile));
}
new JSONOutput().output(cflint.getBugs(), new FileWriter(jsonOutFile));
Writer jsonwriter = stdOut ? new OutputStreamWriter(System.out) : new FileWriter(jsonOutFile);
new JSONOutput().output(cflint.getBugs(), jsonwriter);
}
if (includeCodes != null) {
cflint.getBugs().getFilter().includeCode(includeCodes);
Expand All @@ -342,10 +352,16 @@ private void execute() throws IOException, TransformerException, JAXBException {
cflint.getBugs().getFilter().excludeCode(excludeCodes);
}
}

private void display(String text) {
if (verbose) {
System.out.println(text);
}
}

private boolean isValid() {
if (folder.isEmpty()) {
System.err.println("Set -scanFolder");
if (folder.isEmpty() && !stdIn) {
System.err.println("Set -scanFolder or -stdin");
return false;
}
return true;
Expand Down
114 changes: 114 additions & 0 deletions src/main/java/com/cflint/plugins/core/LiteralChecker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.cflint.plugins.core;

import java.util.Map;
import java.util.HashMap;

import ro.fortsoft.pf4j.Extension;
import cfml.parsing.cfscript.CFExpression;
import cfml.parsing.cfscript.CFFunctionExpression;
import cfml.parsing.cfscript.CFLiteral;
import cfml.parsing.cfscript.script.CFCompDeclStatement;
import cfml.parsing.cfscript.script.CFExpressionStatement;
import cfml.parsing.cfscript.script.CFScriptStatement;


import com.cflint.BugInfo;
import com.cflint.BugList;
import com.cflint.plugins.CFLintScannerAdapter;
import com.cflint.plugins.Context;

@Extension
public class LiteralChecker extends CFLintScannerAdapter {
final String severity = "WARNING";
final protected int REPEAT_THRESHOLD = 3;
final protected int WARNING_THRESHOLD = 5;

protected int threshold = REPEAT_THRESHOLD;
protected int warningThreshold = WARNING_THRESHOLD;

protected Map<String, Integer> globalLiterals = new HashMap<String, Integer>();
protected Map<String, Integer> functionListerals = new HashMap<String, Integer>();

// May want to consider resetting literal map on new components but this way it
// detects duplicated literals across files which is useful

@Override
public void expression(final CFExpression expression, final Context context, final BugList bugs) {
String repeatThreshold = getParameter("maximum");
String maxWarnings = getParameter("maxWarnings");
String warningScope = getParameter("warningScope");

if (repeatThreshold != null) {
threshold = Integer.parseInt(repeatThreshold);
}

if (maxWarnings != null) {
warningThreshold = Integer.parseInt(maxWarnings);
}

if (expression instanceof CFLiteral) {
CFLiteral literal = (CFLiteral) expression;
String name = literal.Decompile(0).replace("'","");

if (isCommon(name)) {
return;
}

int lineNo = literal.getLine() + context.startLine() - 1;

if (warningScope == null || warningScope.equals("global")) {
literalCount(name, lineNo, globalLiterals, true, context, bugs);
}
else if (warningScope.equals("local")) {
literalCount(name, lineNo, functionListerals, false, context, bugs);
}
}
}

@Override
public void expression(final CFScriptStatement expression, final Context context, final BugList bugs) {
if (expression instanceof CFCompDeclStatement) {
functionListerals.clear();
}
}

protected void literalCount(final String name, final int lineNo, Map<String, Integer> literals, boolean global, final Context context, final BugList bugs) {
int count = 1;

if (literals.get(name) == null) {
literals.put(name, count);
}
else {
count = literals.get(name);
count++;
literals.put(name, count);
}

if (count > threshold && (warningThreshold == -1 || (count - threshold) <= warningThreshold)) {
if (global) {
magicGlobalValue(name, lineNo, context, bugs);
}
else {
magicLocalValue(name, lineNo, context, bugs);
}
}
}

protected boolean isCommon(final String name) {
return name.equals("1") || name.equals("0") || name.equals("") || name.equals("true") || name.equals("false");
}

public void magicLocalValue(final String name, final int lineNo, final Context context, final BugList bugs) {
bugs.add(new BugInfo.BugInfoBuilder().setLine(lineNo).setMessageCode("LOCAL_LITERAL_VALUE_USED_TOO_OFTEN")
.setSeverity(severity).setFilename(context.getFilename())
.setMessage("Literal " + name + " occurs several times in the same file. Consider giving it a name and not hard coding values.")
.build());
}

public void magicGlobalValue(final String name, final int lineNo, final Context context, final BugList bugs) {
bugs.add(new BugInfo.BugInfoBuilder().setLine(lineNo).setMessageCode("GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN")
.setSeverity(severity).setFilename(context.getFilename())
.setMessage("Literal " + name + " occurs several times in one or more files. Consider giving it a name and not hard coding values.")
.build());
}
}
10 changes: 9 additions & 1 deletion src/main/resources/cflint.definition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@
<severity>INFO</severity>
</message>
</ruleImpl>
<ruleImpl name="LiteralChecker" className="LiteralChecker">
<message code="LOCAL_LITERAL_VALUE_USED_TOO_OFTEN">
<severity>WARNING</severity>
</message>
<message code="GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN">
<severity>WARNING</severity>
</message>
</ruleImpl>
<ruleImpl name="VariableNameChecker" className="VariableNameChecker">
<message code="VAR_INVALID_NAME">
<severity>INFO</severity>
Expand Down Expand Up @@ -247,6 +255,6 @@
</message>
<message code="METHOD_HAS_PREFIX_OR_POSTFIX">
<severity>INFO</severity>
</message>
</message>
</ruleImpl>
</CFLint-Plugin>
Loading

0 comments on commit 0aa29d5

Please sign in to comment.