Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #115

Merged
merged 17 commits into from
Oct 21, 2015
Merged

Dev #115

Show file tree
Hide file tree
Changes from all 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
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 @@ -799,7 +799,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 @@ -809,7 +815,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());
}
}
8 changes: 8 additions & 0 deletions src/main/resources/cflint.definition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,12 @@
<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>
</CFLint-Plugin>
2 changes: 1 addition & 1 deletion src/test/java/com/cflint/TestCFBugs_SimpleComplexity.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public void testComplexScriptBased() throws ParseException, IOException {
+ "}\r\n"
+ "}";
cfBugs.process(cfcSrc, "test");
final List<BugInfo> result = cfBugs.getBugs().getBugList().values().iterator().next();
final List<BugInfo> result = cfBugs.getBugs().getBugList().get("FUNCTION_TOO_COMPLEX");
assertEquals(1, result.size());
assertEquals("FUNCTION_TOO_COMPLEX", result.get(0).getMessageCode());
assertEquals(2, result.get(0).getLine());
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/com/cflint/TestComponentLengthChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ public void testBadFunction() throws ParseException, IOException{
"}\r\n" +
"}";
cfBugs.process(cfcSrc,"test");
final List<BugInfo> result = cfBugs.getBugs().getBugList().values().iterator().next();
final List<BugInfo> result = cfBugs.getBugs().getBugList().get("EXCESSIVE_COMPONENT_LENGTH");
assertEquals(1, result.size());
assertEquals("EXCESSIVE_COMPONENT_LENGTH", result.get(0).getMessageCode());
}
Expand Down
Loading