From 3cc6310beb94d31e3cd61a7de57c6dd2c477e488 Mon Sep 17 00:00:00 2001 From: ryaneberly Date: Wed, 1 Jun 2016 08:06:50 -0400 Subject: [PATCH] report source of stack overflow errors --- src/main/java/com/cflint/CFLint.java | 2178 +++++++++-------- .../exceptions/CFLintExceptionListener.java | 2 +- .../DefaultCFLintExceptionListener.java | 2 +- 3 files changed, 1094 insertions(+), 1088 deletions(-) diff --git a/src/main/java/com/cflint/CFLint.java b/src/main/java/com/cflint/CFLint.java index 6b433d643..adf8d9534 100644 --- a/src/main/java/com/cflint/CFLint.java +++ b/src/main/java/com/cflint/CFLint.java @@ -1,1086 +1,1092 @@ -package com.cflint; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.StringReader; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.ResourceBundle; -import java.util.Stack; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.antlr.runtime.BitSet; -import org.antlr.runtime.IntStream; -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 com.cflint.BugInfo.BugInfoBuilder; -import com.cflint.config.CFLintConfig; -import com.cflint.config.CFLintPluginInfo; -import com.cflint.config.CFLintPluginInfo.PluginInfoRule; -import com.cflint.config.CFLintPluginInfo.PluginInfoRule.PluginMessage; -import com.cflint.config.ConfigRuntime; -import com.cflint.config.ConfigUtils; -import com.cflint.listeners.ProgressMonitorListener; -import com.cflint.listeners.ScanProgressListener; -import com.cflint.plugins.CFLintScanner; -import com.cflint.plugins.CFLintStructureListener; -import com.cflint.plugins.Context; -import com.cflint.plugins.Context.ContextMessage; -import com.cflint.plugins.exceptions.CFLintExceptionListener; -import com.cflint.plugins.exceptions.DefaultCFLintExceptionListener; -import com.cflint.tools.CFLintFilter; - -import cfml.CFSCRIPTParser; -import cfml.parsing.CFMLParser; -import cfml.parsing.CFMLSource; -import cfml.parsing.cfscript.CFAssignmentExpression; -import cfml.parsing.cfscript.CFBinaryExpression; -import cfml.parsing.cfscript.CFExpression; -import cfml.parsing.cfscript.CFFullVarExpression; -import cfml.parsing.cfscript.CFFunctionExpression; -import cfml.parsing.cfscript.CFIdentifier; -import cfml.parsing.cfscript.CFLiteral; -import cfml.parsing.cfscript.CFNestedExpression; -import cfml.parsing.cfscript.CFStatement; -import cfml.parsing.cfscript.CFStringExpression; -import cfml.parsing.cfscript.CFUnaryExpression; -import cfml.parsing.cfscript.CFVarDeclExpression; -import cfml.parsing.cfscript.script.CFCompDeclStatement; -import cfml.parsing.cfscript.script.CFCompoundStatement; -import cfml.parsing.cfscript.script.CFExpressionStatement; -import cfml.parsing.cfscript.script.CFForInStatement; -import cfml.parsing.cfscript.script.CFForStatement; -import cfml.parsing.cfscript.script.CFFuncDeclStatement; -import cfml.parsing.cfscript.script.CFFunctionParameter; -import cfml.parsing.cfscript.script.CFIfStatement; -import cfml.parsing.cfscript.script.CFParsedStatement; -import cfml.parsing.cfscript.script.CFReturnStatement; -import cfml.parsing.cfscript.script.CFScriptStatement; -import cfml.parsing.reporting.IErrorReporter; -import cfml.parsing.reporting.ParseException; -import net.htmlparser.jericho.Element; -import net.htmlparser.jericho.Source; - -public class CFLint implements IErrorReporter { - - private static final String FILE_ERROR = "FILE_ERROR"; - private static final String PARSE_ERROR = "PARSE_ERROR"; - public static final String PLUGIN_ERROR = "PLUGIN_ERROR:"; - final CFMLParser cfmlParser = new CFMLParser(); - - - StackHandler handler = new StackHandler(); - boolean inFunction = false; - boolean inAssignment = false; - boolean inComponent = false; - BugList bugs; - List extensions = new ArrayList(); - List allowedExtensions = new ArrayList(); - boolean verbose = false; - boolean logError = false; - boolean quiet = false; - boolean showProgress = false; - boolean progressUsesThread = true; - - // constants - final String cfcExtension = ".cfc"; - final String cfmExtenstion = ".cfm"; - final String resourceBundleName = "com.cflint.cflint"; - final String allowedExtensionsName = "allowedextensions"; - final String progressMonitorName = "CFLint"; - - private String currentFile; - List scanProgressListeners = new ArrayList(); - List exceptionListeners = new ArrayList(); - - ConfigRuntime configuration; - private Stack currentElement = new Stack(); - - public CFLint() throws IOException { - this((CFLintConfig)null); - } - public CFLint(CFLintConfig configFile) throws IOException { - final CFLintPluginInfo pluginInfo = ConfigUtils.loadDefaultPluginInfo(); - configuration = new ConfigRuntime(configFile,pluginInfo); - for(PluginInfoRule ruleInfo:configuration.getRules()){ - addScanner(ConfigUtils.loadPlugin(ruleInfo)); - } - final CFLintFilter filter = CFLintFilter.createFilter(verbose); - bugs = new BugList(filter); - if(exceptionListeners.isEmpty()){ - addExceptionListener(new DefaultCFLintExceptionListener(bugs)); - } - try { - allowedExtensions.addAll(Arrays.asList(ResourceBundle.getBundle(resourceBundleName) - .getString(allowedExtensionsName).split(","))); - } catch (final Exception e) { - allowedExtensions.add(cfcExtension); - allowedExtensions.add(cfmExtenstion); - } - cfmlParser.setErrorReporter(this); - } - public CFLint(final CFLintScanner... bugsScanners) { - this(null,bugsScanners); - } - @Deprecated - public CFLint(ConfigRuntime configuration,final CFLintScanner... bugsScanners) { - super(); - this.configuration=configuration; - // DictionaryPreferences dprefs = new DictionaryPreferences(); - // dprefs.setDictionaryDir("C:\\projects\\cfml.dictionary-master\\dictionary"); - // DictionaryManager.initDictionaries(dprefs); - - for (final CFLintScanner scanner : bugsScanners) { - extensions.add(scanner); - if(configuration != null){ - PluginInfoRule ruleInfo = configuration.getRuleByClass(scanner.getClass()); - if(ruleInfo != null){ - ruleInfo.setPluginInstance(scanner); - } - } - } - CFLintFilter filter; - try { - filter = CFLintFilter.createFilter(verbose); - bugs = new BugList(filter); - } catch (IOException e1) { - e1.printStackTrace(); - } - if(exceptionListeners.isEmpty()){ - addExceptionListener(new DefaultCFLintExceptionListener(bugs)); - } - try { - allowedExtensions.addAll(Arrays.asList(ResourceBundle.getBundle(resourceBundleName) - .getString(allowedExtensionsName).split(","))); - } catch (final Exception e) { - allowedExtensions.add(cfcExtension); - allowedExtensions.add(cfmExtenstion); - } - cfmlParser.setErrorReporter(this); - } - - public void scan(final String folder) { - final File f = new File(folder); - if (showProgress) { - final ProgressMonitorListener progressMonitorListener = new ProgressMonitorListener(progressMonitorName); - addScanProgressListener(progressMonitorListener); - if (progressUsesThread) { - new Thread(new Runnable() { - - public void run() { - prescan(f,0,progressMonitorListener); - } - }).start(); - }else{ - prescan(f,0,progressMonitorListener); - } - } - scan(f); - fireClose(); - } - - private int prescan(File folderOrFile, int counter,final ProgressMonitorListener progressMonitorListener) { - if (folderOrFile.isDirectory()) { - for (final File file : folderOrFile.listFiles()) { - counter=prescan(file,counter,progressMonitorListener); - } - if(counter>10){ - - progressMonitorListener.setTotalToProcess(counter); - } - return counter; - } else if (!folderOrFile.isHidden() && checkExtension(folderOrFile)) { - return counter+1; - }else{ - return counter; - } - } - - public void scan(final File folderOrFile) { - if (folderOrFile.isDirectory()) { - for (final File file : folderOrFile.listFiles()) { - scan(file); - } - } else if (!folderOrFile.isHidden() && checkExtension(folderOrFile)) { - final String src = load(folderOrFile); - // System.out.println("processing " + file); - try { - process(src, folderOrFile.getAbsolutePath()); - } catch (final Exception e) { - if (!quiet) { - if (verbose) { - e.printStackTrace(System.err); - }else{ - System.err.println(e.getMessage()); - } - } - /*bugs.add(new BugInfo.BugInfoBuilder().setMessageCode("FILE_ERROR") - .setFilename(folderOrFile.getAbsolutePath()).setMessage(e.getMessage()).setSeverity("ERROR") - .build());*/ - if (logError) { - System.out.println("Logging Error: " + FILE_ERROR); - fireCFLintException(e,FILE_ERROR,folderOrFile.getAbsolutePath(),null,null,null,null); - } - } - } - } - - protected boolean checkExtension(final File file) { - for (final String ext : allowedExtensions) { - if (file.getName().endsWith(ext)) { - return true; - } - } - return false; - } - - static String load(final File file) { - FileInputStream fis = null; - try { - fis = new FileInputStream(file); - final byte[] b = new byte[fis.available()]; - fis.read(b); - return new String(b); - } catch (final Exception e) { - return null; - } finally { - try { - if (fis != null) - fis.close(); - } catch (IOException e) { - return null; - } - } - } - - - int parserCounter = 1; - - public void process(final String src, final String filename) throws ParseException, IOException { - fireStartedProcessing(filename); - final CFMLSource cfmlSource = new CFMLSource(src); - final List elements = cfmlSource.getChildElements(); - if (elements.isEmpty() && src.contains("component")) { - // Check if pure cfscript - final CFScriptStatement scriptStatement = cfmlParser.parseScript(src); - process(scriptStatement, filename, null, (String)null); - } else { - processStack(elements, " ", filename, null); - } - fireFinishedProcessing(filename); - } - - public void processStack(final List elements, final String space, final String filename, - final CFIdentifier functionName) throws ParseException, IOException { - for (final Element elem : elements) { - final Context context = new Context(filename, elem, functionName, inAssignment, handler); - process(elem,space,context); - } - } - public void processStack(final List elements, final String space, final Context context) throws ParseException, IOException { - for (final Element elem : elements) { - process(elem, space, context.subContext(elem)); - } - } - - - private void process(final Element elem, final String space, Context context) - throws ParseException, IOException { - context.setInComponent(inComponent); - currentElement.push(elem); - - if (elem.getName().equalsIgnoreCase("cfcomponent")) { - inComponent = true; - handler.push("component"); - - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.startComponent(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - - context.setInComponent(true); - context.setComponentName(elem.getAttributeValue("displayname")); - } - else if (elem.getName().equalsIgnoreCase("cffunction")) { - context.setFunctionName(elem.getAttributeValue("name")); - inFunction = true; - handler.push("function"); - - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.startFunction(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - } - - try{ - for (final CFLintScanner plugin : extensions) { - try{ - plugin.element(elem, context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, plugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - if(verbose){ - e.printStackTrace(); - } - reportRule(elem, null, context, plugin, PLUGIN_ERROR + exceptionText(e)); - } - } - if (elem.getName().equalsIgnoreCase("cfset") || elem.getName().equalsIgnoreCase("cfif") - || elem.getName().equalsIgnoreCase("cfelseif")|| elem.getName().equalsIgnoreCase("cfreturn")) { - //final int elemLine = elem.getSource().getRow(elem.getBegin()); - //final int elemColumn = elem.getSource().getColumn(elem.getBegin()); - final Pattern p = Pattern.compile("<\\w+\\s(.*[^/])/?>",Pattern.MULTILINE|Pattern.DOTALL); - final String expr = elem.getFirstStartTag().toString(); - final Matcher m = p.matcher(expr); - if (m.matches()) { - final String cfscript = m.group(1); - try { -// if(elem.getName().equalsIgnoreCase("cfset")){ -// System.out.println("parse: " + cfscript + ";"); -// final CFScriptStatement scriptStatement = cfmlParser.parseScript(cfscript + ";"); -// process(scriptStatement, context.getFilename(), elem, context.getFunctionName()); -// }else{ - final CFExpression expression = cfmlParser.parseCFExpression(cfscript,this); - - if (expression == null) { - throw new NullPointerException("expression is null, parsing error"); - } - process(expression, context.getFilename(), elem, context.getFunctionName()); -// } - } catch (final Exception npe) { - final int line = elem.getSource().getRow(elem.getBegin()); - //final int column = elem.getSource().getColumn(elem.getBegin()); - if (!quiet) { - System.err.println("Error in: " + shortSource(elem.getSource(), line) + " @ " + line + ":"); - if (verbose) { - npe.printStackTrace(System.err); - } - } - /*bugs.add(new BugInfo.BugInfoBuilder().setLine(elemLine).setColumn(elemColumn + column) - .setMessageCode("PARSE_ERROR").setSeverity("ERROR").setExpression(m.group(1)) - .setFilename(filename).setFunction(functionName).setMessage("Unable to parse").build());*/ -// if (logError) { -// System.out.println("Logging Error: " + PARSE_ERROR); -// fireCFLintException(npe,PARSE_ERROR,context.getFilename(),elemLine,elemColumn + column,context.getFunctionName(),m.group(1)); -// } - } - } - - } else if (elem.getName().equalsIgnoreCase("cfargument")) { - final String name = elem.getAttributeValue("name"); - if (name != null) { - handler.addArgument(name); - } - } else if (elem.getName().equalsIgnoreCase("cfscript")) { - final String cfscript = elem.getContent().toString(); - final CFScriptStatement scriptStatement = cfmlParser.parseScript(cfscript); - - process(scriptStatement, context.getFilename(), elem, context.getFunctionName()); - // } else if (elem.getName().equalsIgnoreCase("cfoutput")) { - // final Element parent = CFTool.getNamedParent(elem, "cfoutput"); - // if (parent != null && parent.getAttributeValue("query") != null - // && parent.getAttributeValue("group") == null) { - // final int line = elem.getSource().getRow(elem.getBegin()); - // final int column = elem.getSource().getColumn(elem.getBegin()); - // bugs.add(new - // BugInfo.BugInfoBuilder().setLine(line).setColumn(column).setMessageCode("NESTED_CFOUTPUT") - // .setSeverity("ERROR").setFilename(filename) - // .setMessage("Nested CFOutput, outer CFOutput has @query.").build()); - // } - } else { - } - - if (elem.getName().equalsIgnoreCase("cffunction")) { - processStack(elem.getChildElements(), space + " ", context); - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.endFunction(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - - }catch(Exception e){ - e.printStackTrace(); - } - } - inFunction = false; - handler.pop(); - } else if (elem.getName().equalsIgnoreCase("cfcomponent")) { - processStack(elem.getChildElements(), space + " ", context); - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.endComponent(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - - inComponent = false; - handler.pop(); - } else if (elem.getName().equalsIgnoreCase("cfquery")) { - final List list = elem.getAllElements(); - processStack(list.subList(1, list.size()), space + " ", context); - } else if (elem.getName().equalsIgnoreCase("cfqueryparam")) { - if (elem.getAttributeValue("value") != null) { - //final CFScriptStatement scriptStatement = cfmlParser.parseScript(elem.getAttributeValue("value") + ";"); - //process(scriptStatement, context.getFilename(), elem, context.getFunctionName()); - //TODO this could be 'parsed if the value has a # sign - } - } else { - processStack(elem.getChildElements(), space + " ", context); - } - }finally{ - currentElement.pop(); - } - } - - private List getStructureListeners(final List extensions) { - final List retval = new ArrayList(); - for(CFLintScanner plugin: extensions) - if(plugin instanceof CFLintStructureListener){ - retval.add((CFLintStructureListener) plugin); - } - return retval; - } - private String shortSource(final Source source, final int line) { - final String retval = source == null ? "" : source.toString().trim(); - if (retval.length() < 300) { - return retval; - } - try { - final BufferedReader sr = new BufferedReader(new StringReader(source.toString())); - for (int i = 1; i < line; i++) { - sr.readLine(); - } - return sr.readLine().replaceAll("\t", " "); - } catch (final Exception e) { - } - return retval.substring(0, 300); - } - - public String stripLineComments(final String cfscript) { - return cfscript.replaceAll("//[^\r\n]*\r?\n", "\r\n"); - } - - private void process(final CFScriptStatement expression, final String filename, final Element elem, - final CFIdentifier functionName) { - process(expression,filename,elem,functionName.getName()); - } - private void process(final CFScriptStatement expression, final String filename, final Element elem, - String functionName) { - final Context context = new Context(filename, elem, functionName, inAssignment, handler); - - context.setInComponent(inComponent); - if (expression instanceof CFCompDeclStatement) { - inComponent = true; - //do startComponent notifications - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.startComponent(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - } - else if (expression instanceof CFFuncDeclStatement) { - final CFFuncDeclStatement function = (CFFuncDeclStatement) expression; - functionName = function.getName().getName(); - context.setFunctionName(functionName); - inFunction = true; - handler.push("function"); - for (final CFFunctionParameter param : function.getFormals()) { - handler.addArgument(param.getName()); - } - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.startFunction(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - } - - for (final CFLintScanner plugin : extensions) { - try{ - plugin.expression(expression, context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, expression, context, plugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - if(verbose){ - e.printStackTrace(); - } - reportRule(elem, expression, context, plugin, PLUGIN_ERROR + exceptionText(e)); - } - } - - if (expression instanceof CFCompoundStatement) { - for (final CFScriptStatement statement : ((CFCompoundStatement) expression).getStatements()) { - process(statement, filename, elem, functionName); - } - } else if (expression instanceof CFExpressionStatement) { - process(((CFExpressionStatement) expression).getExpression(), filename, elem, functionName); - } else if (expression instanceof CFCompDeclStatement) { - //process the component declaration - process(((CFCompDeclStatement) expression).getBody(), filename, elem, functionName); - //do endComponent notifications - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.endComponent(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - - inComponent = false; - } else if (expression instanceof CFForStatement) { - process(((CFForStatement) expression).getInit(), filename, elem, functionName); - process(((CFForStatement) expression).getCond(), filename, elem, functionName); - process(((CFForStatement) expression).getNext(), filename, elem, functionName); - process(((CFForStatement) expression).getBody(), filename, elem, functionName); - } else if (expression instanceof CFForInStatement) { - process(((CFForInStatement) expression).getVariable(), filename, elem, functionName); - process(((CFForInStatement) expression).getStructure(), filename, elem, functionName); - process(((CFForInStatement) expression).getBody(), filename, elem, functionName); - } else if (expression instanceof CFIfStatement) { - final CFIfStatement cfif = (CFIfStatement) expression; - process(cfif.getCond(), filename, elem, functionName); - process(cfif.getThenStatement(), filename, elem, functionName); - if (cfif.getElseStatement() != null) { - process(cfif.getElseStatement(), filename, elem, functionName); - } - } else if (expression instanceof CFReturnStatement) { - final CFReturnStatement cfreturn = (CFReturnStatement) expression; - //TODO replace with cfreturn.getExpression() when next cfmlparser is released - Field f; - try { - f = CFReturnStatement.class.getDeclaredField("_ret"); - f.setAccessible(true); - CFExpression subExpression = (CFExpression) f.get(cfreturn); - if(subExpression !=null){ - process(subExpression, filename, elem, functionName); - } - } catch (Exception e) { - } //NoSuchFieldException - - - } else if (expression instanceof CFFuncDeclStatement) { - final CFFuncDeclStatement function = (CFFuncDeclStatement) expression; - process(function.getBody(), filename, elem, function.getName()); - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.endFunction(context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - e.printStackTrace(); - } - } - inFunction = false; - handler.pop(); - } else { - } - } - - /** - * Return the exception message, or its class name - * @param e - * @return - */ - private String exceptionText(Exception e) { - final String msg = e.getMessage(); - if(msg == null || msg.trim().length()==0){ - return e.getClass().toString(); - } - return msg; - } - private void process(final CFExpression expression, final String filename, final Element elem, - final String functionName) { - final Context context = new Context(filename, elem, functionName, inAssignment, handler); - context.setInComponent(inComponent); - - - for (final CFLintScanner plugin : extensions) { - try{ - plugin.expression(expression, context, bugs); - for(final ContextMessage message : context.getMessages()){ - reportRule(elem, expression, context, plugin, message); - } - context.getMessages().clear(); - }catch(Exception e){ - if(verbose){ - e.printStackTrace(); - } - reportRule(elem, expression, context, plugin, PLUGIN_ERROR + exceptionText(e)); - } - } - if (expression instanceof CFUnaryExpression) { - process(((CFUnaryExpression) expression).getSub(), filename, elem, functionName); - }else if (expression instanceof CFNestedExpression) { - process(((CFNestedExpression) expression).getSub(), filename, elem, functionName); - } else if (expression instanceof CFAssignmentExpression) { - inAssignment = true; - process(((CFAssignmentExpression) expression).getLeft(), filename, elem, functionName); - inAssignment = false; - process(((CFAssignmentExpression) expression).getRight(), filename, elem, functionName); - } else if (expression instanceof CFBinaryExpression) { - process(((CFBinaryExpression) expression).getLeft(), filename, elem, functionName); - process(((CFBinaryExpression) expression).getRight(), filename, elem, functionName); - } else if (expression instanceof CFFunctionExpression) { - final CFFunctionExpression cfFunctionExpr = (CFFunctionExpression) expression; - // if ("QueryNew".equalsIgnoreCase(cfFunctionExpr.getName()) && - // cfFunctionExpr.getArgs().size() == 1) { - // bugs.add(new - // BugInfo.BugInfoBuilder().setMessageCode("QUERYNEW_DATATYPE") - // .setMessage("QueryNew statement should specify datatypes.").setVariable("QueryNew") - // .setFunction(functionName).setSeverity("WARNING").setFilename(filename) - // .setExpression(expression.Decompile(0)).build(expression, elem)); - // } - for (final CFExpression expr : cfFunctionExpr.getArgs()) { - process(expr, filename, elem, functionName); - } - } else if (expression instanceof CFIdentifier) { - final String name = ((CFIdentifier) expression).getName(); - handler.checkVariable(name); - // if (inFunction && inAssignment && !handler.checkVariable(name)) { - // bugs.add(new - // BugInfo.BugInfoBuilder().setMessageCode("MISSING_VAR") - // .setMessage("Variable " + name + - // " is not declared with a var statement.").setVariable(name) - // .setFunction(functionName).setSeverity("ERROR").setFilename(filename) - // .setExpression(expression.Decompile(0)).build(expression, elem)); - // } - if(expression instanceof CFFullVarExpression){ - CFFullVarExpression fullVarExpression = (CFFullVarExpression)expression; - for(CFExpression expr: fullVarExpression.getExpressions()){ - if(expr instanceof CFFunctionExpression){ - process(expr,filename,elem,functionName); - } - } - } - } else if (expression instanceof CFVarDeclExpression) { - handler.addVariable(((CFVarDeclExpression) expression).getName()); - process(((CFVarDeclExpression) expression).getInit(), filename, elem, functionName); - } else if (expression instanceof CFStringExpression) { - CFStringExpression stringExpression = (CFStringExpression) expression; - for(CFExpression expr: stringExpression.getSubExpressions()){ - process(expr,filename,elem,functionName); - } - } else if (expression instanceof CFLiteral) { -// if(expression.getToken().getType() == CFSCRIPTLexer.STRING_LITERAL){ -// for(String subExprStr : splitHash(expression.Decompile(0))){ -// try{ -// final CFExpression subExpression = cfmlParser.parseCFExpression(subExprStr,this); -// if (expression == null) { -// throw new NullPointerException("expression is null, parsing error"); -// } -// process(subExpression, filename, elem,functionName); -// } catch (final Exception npe) { -// final int line = elem.getSource().getRow(elem.getBegin()); -// final int column = elem.getSource().getColumn(elem.getBegin()); -// if (!quiet) { -// System.err.println("Error in: " + shortSource(elem.getSource(), line) + " @ " + line + ":"); -// if (verbose) { -// npe.printStackTrace(System.err); -// } -// } -// } -// } -// -// } - // } else if (expression instanceof CFFullVarExpression) { - // if (((CFFullVarExpression) expression).getExpressions().size() == - // 1) { - // process(((CFFullVarExpression) - // expression).getExpressions().get(0), filename, elem, - // functionName); - // } - } - else if (expression instanceof CFStringExpression){ - for(CFExpression expr : ((CFStringExpression) expression).getSubExpressions()){ - process(expr,filename,elem,functionName); - } - } - else { - } - } - - protected void reportRule(final Element elem, final Object expression, final Context context, final CFLintScanner plugin, String msg) { - final String[] exceptionmsg = (msg!=null?msg:"").split(":"); - final String msgcode = exceptionmsg[0].trim(); - final String nameVar = exceptionmsg.length>1?exceptionmsg[1].trim():null; - reportRule(elem, expression,context,plugin,new ContextMessage(msgcode, nameVar)); - } - - public static Element getPreviousSibling(Element element){ - - if(element.getParentElement() != null){ - List parentElements = element.getParentElement().getChildElements(); - int idx = parentElements.indexOf(element); - if(idx > 0){ - return parentElements.get(idx-1); - } - }else if(element.getSource() != null){ - List parentElements = element.getSource().getChildElements(); - int idx = parentElements.indexOf(element); - if(idx > 0){ - return parentElements.get(idx-1); - } - } - return null; - } - - /* - * Check for in the tag hierarchy - */ - protected boolean checkForDisabled(final Element element, - final String msgcode) { - Element elem = element; - while (elem != null) { - Element prevSibling = getPreviousSibling(elem); - if (prevSibling != null && prevSibling.getName().equals("!---")) { - Pattern p = Pattern - .compile(".*---\\s*CFLINT-DISABLE\\s+(.*)\\s*---.*"); - Matcher m = p.matcher(prevSibling.toString().toUpperCase() - .trim()); - if (m.matches()) { - // No message codes in CFLINT-DISABLE - if (m.group(1).trim().length() == 0) { - if (verbose) { - System.out.println("Skipping disabled " + msgcode); - } - return true; - } - // check for matching message codes in CFLINT-DISABLE - for (String skipcode : m.group(1).split(",")) { - skipcode = skipcode.trim(); - if (msgcode.equals(skipcode)) { - if (verbose) { - System.out.println("Skipping disabled " - + msgcode); - } - return true; - } - } - } - } - elem = elem.getParentElement(); - } - return false; - } - - protected void reportRule(final Element elem, final Object expression, final Context context, final CFLintScanner plugin, ContextMessage msg) { - final String msgcode = msg.getMessageCode(); - final String nameVar = msg.getVariable(); - - if(checkForDisabled(elem,msgcode)){ - return; - } - if(configuration == null){ - throw new NullPointerException("Configuration is null"); - } - PluginInfoRule ruleInfo; - if("PLUGIN_ERROR".equals(msgcode)){ - ruleInfo = new PluginInfoRule(); - PluginMessage msgInfo = new PluginMessage("PLUGIN_ERROR"); - msgInfo.setMessageText("Error in plugin: ${variable}"); - msgInfo.setSeverity("ERROR"); - ruleInfo.getMessages().add(msgInfo); - }else{ - ruleInfo = configuration.getRuleForPlugin(plugin); - } - if(ruleInfo == null){ - throw new NullPointerException("Rule not found for " + plugin.getClass().getSimpleName()); - } - final PluginMessage msgInfo = ruleInfo.getMessageByCode(msgcode); - if(configuration == null){ - throw new NullPointerException("Message definition not found for [" + msgcode + "] in " + plugin.getClass().getSimpleName()); - } - BugInfoBuilder bldr = new BugInfo.BugInfoBuilder().setMessageCode(msgcode).setVariable(nameVar) - .setFunction(context.getFunctionName()) - .setFilename(context.getFilename()); - if(msgInfo != null){ - bldr.setSeverity(msgInfo.getSeverity()); - bldr.setMessage(msgInfo.getMessageText()); - }else{ - System.err.println("Message code: " + msgcode + " is not configured correctly."); - bldr.setSeverity("WARNING"); - bldr.setMessage(msgcode); - } - if(expression instanceof CFStatement){ - bldr.setExpression(((CFStatement) expression).Decompile(0)); - } - else if(expression instanceof CFScriptStatement){ - bldr.setExpression(((CFScriptStatement) expression).Decompile(0)); - } - else if(elem != null){ - bldr.setExpression(elem.toString()); - } - bldr.setRuleParameters(ruleInfo.getParameters()); - if (expression instanceof CFExpression){ - bugs.add(bldr.build((CFExpression)expression, elem)); - }else{ - BugInfo bug = bldr.build((CFParsedStatement)expression, elem); - if(msg.getLine() != null){ - bug.setLine(msg.getLine()); - bug.setColumn(0); - } - bugs.add(bug); - } - } - - public BugList getBugs() { - return bugs; - } - - public List getAllowedExtensions() { - return allowedExtensions; - } - - public void setAllowedExtensions(final List allowedExtensions) { - this.allowedExtensions = allowedExtensions; - } - - public void reportError(final String arg0) { - // TODO Auto-generated method stub - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "------4-" + arg0); - - } - - public void reportError(final RecognitionException arg0) { - // TODO Auto-generated method stub - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "-------" + arg0); - - } - - public void reportError(final String[] arg0, final RecognitionException arg1) { - // TODO Auto-generated method stub - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "-------" + arg0); - } - - public void reportError(final IntStream arg0, final RecognitionException arg1, final BitSet arg2) { - // TODO Auto-generated method stub - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "-------" + arg0); - - } - - public void setVerbose(final boolean verbose) { - this.verbose = verbose; - } - - public void setLogError(final boolean logError) { - this.logError = logError; - } - - public void setQuiet(final boolean quiet) { - this.quiet = quiet; - } - - public void addScanProgressListener(final ScanProgressListener scanProgressListener) { - scanProgressListeners.add(scanProgressListener); - } - - protected void fireStartedProcessing(final String srcidentifier) { - currentFile = srcidentifier; - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.startFile(srcidentifier, bugs); - }catch(Exception e){ - e.printStackTrace(); - } - } - for (final ScanProgressListener p : scanProgressListeners) { - p.startedProcessing(srcidentifier); - } - } - - protected void fireFinishedProcessing(final String srcidentifier) { - for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { - try{ - structurePlugin.endFile(srcidentifier, bugs); - }catch(Exception e){ - e.printStackTrace(); - } - } - for (final ScanProgressListener p : scanProgressListeners) { - p.finishedProcessing(srcidentifier); - } - currentFile = null; - } - protected void fireClose() { - for (final ScanProgressListener p : scanProgressListeners) { - p.close(); - } - } - - public void addScanner(CFLintScanner plugin) { - extensions.add(plugin); - } - - public List getScanners() { - return extensions; - } - - public void addExceptionListener(final CFLintExceptionListener exceptionListener) { - exceptionListeners.add(exceptionListener); - } - - protected void fireCFLintException(final Exception e, final String messageCode, final String filename, - final Integer line, final Integer column,final String functionName, final String expression) { - for (final CFLintExceptionListener p : exceptionListeners) { - p.exceptionOccurred(e, messageCode, filename, line, column, functionName, expression); - } - } - - public void setShowProgress(final boolean showProgress) { - this.showProgress = showProgress; - } - - public void setProgressUsesThread(final boolean progressUsesThread) { - this.progressUsesThread = progressUsesThread; - } - 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"; - 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){ - line = elem.getSource().getRow(elem.getBegin()); - charPositionInLine = charPositionInLine + elem.getSource().getColumn(elem.getBegin()); - }else{ - line = elem.getSource().getRow(elem.getBegin()) + line - 1; - } - } - if(recognizer instanceof Parser && ((Parser)recognizer).isExpectedToken(CFSCRIPTParser.SEMICOLON)){ - 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, - ATNConfigSet configs) { -// final String file = currentFile == null ? "" : currentFile + "\r\n"; -// System.out.println(file + "----reportAmbiguity ---"); - } - public void reportAttemptingFullContext(Parser recognizer, DFA dfa, - int startIndex, int stopIndex, java.util.BitSet conflictingAlts, - ATNConfigSet configs) { -// final String file = currentFile == null ? "" : currentFile + "\r\n"; -// System.out.println(file + "----reportAttemptingFullContext ---"); - } - public void reportContextSensitivity(Parser recognizer, DFA dfa, - int startIndex, int stopIndex, int prediction, ATNConfigSet configs) { -// final String file = currentFile == null ? "" : currentFile + "\r\n"; -// System.out.println(file + "----reportContextSensitivity ---"); - } - public void reportError(org.antlr.v4.runtime.RecognitionException re) { - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "----RecognitionException ---" + re.getCtx().getSourceInterval().a + " : " + - re.getCtx().getSourceInterval().b); - } - public void reportError(String[] tokenNames, - org.antlr.v4.runtime.RecognitionException re) { - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "----reportError ---" + re.getCtx().getSourceInterval().a + " : " + - re.getCtx().getSourceInterval().b); - } - public void reportError(org.antlr.v4.runtime.IntStream input, - org.antlr.v4.runtime.RecognitionException re, BitSet follow) { - final String file = currentFile == null ? "" : currentFile + "\r\n"; - System.out.println(file + "----reportError ---" ); - } - - - List splitHash(String input){ - input = input + " "; - List retval = new ArrayList(); - - int start = 0; - int end= -1; - - while(startstart){ - retval.add(input.substring(start, end)); - - } - start = end + 1; - while(start extensions = new ArrayList(); + List allowedExtensions = new ArrayList(); + boolean verbose = false; + boolean logError = false; + boolean quiet = false; + boolean showProgress = false; + boolean progressUsesThread = true; + + // constants + final String cfcExtension = ".cfc"; + final String cfmExtenstion = ".cfm"; + final String resourceBundleName = "com.cflint.cflint"; + final String allowedExtensionsName = "allowedextensions"; + final String progressMonitorName = "CFLint"; + + private String currentFile; + List scanProgressListeners = new ArrayList(); + List exceptionListeners = new ArrayList(); + + ConfigRuntime configuration; + private Stack currentElement = new Stack(); + + public CFLint() throws IOException { + this((CFLintConfig)null); + } + public CFLint(CFLintConfig configFile) throws IOException { + final CFLintPluginInfo pluginInfo = ConfigUtils.loadDefaultPluginInfo(); + configuration = new ConfigRuntime(configFile,pluginInfo); + for(PluginInfoRule ruleInfo:configuration.getRules()){ + addScanner(ConfigUtils.loadPlugin(ruleInfo)); + } + final CFLintFilter filter = CFLintFilter.createFilter(verbose); + bugs = new BugList(filter); + if(exceptionListeners.isEmpty()){ + addExceptionListener(new DefaultCFLintExceptionListener(bugs)); + } + try { + allowedExtensions.addAll(Arrays.asList(ResourceBundle.getBundle(resourceBundleName) + .getString(allowedExtensionsName).split(","))); + } catch (final Exception e) { + allowedExtensions.add(cfcExtension); + allowedExtensions.add(cfmExtenstion); + } + cfmlParser.setErrorReporter(this); + } + public CFLint(final CFLintScanner... bugsScanners) { + this(null,bugsScanners); + } + @Deprecated + public CFLint(ConfigRuntime configuration,final CFLintScanner... bugsScanners) { + super(); + this.configuration=configuration; + // DictionaryPreferences dprefs = new DictionaryPreferences(); + // dprefs.setDictionaryDir("C:\\projects\\cfml.dictionary-master\\dictionary"); + // DictionaryManager.initDictionaries(dprefs); + + for (final CFLintScanner scanner : bugsScanners) { + extensions.add(scanner); + if(configuration != null){ + PluginInfoRule ruleInfo = configuration.getRuleByClass(scanner.getClass()); + if(ruleInfo != null){ + ruleInfo.setPluginInstance(scanner); + } + } + } + CFLintFilter filter; + try { + filter = CFLintFilter.createFilter(verbose); + bugs = new BugList(filter); + } catch (IOException e1) { + e1.printStackTrace(); + } + if(exceptionListeners.isEmpty()){ + addExceptionListener(new DefaultCFLintExceptionListener(bugs)); + } + try { + allowedExtensions.addAll(Arrays.asList(ResourceBundle.getBundle(resourceBundleName) + .getString(allowedExtensionsName).split(","))); + } catch (final Exception e) { + allowedExtensions.add(cfcExtension); + allowedExtensions.add(cfmExtenstion); + } + cfmlParser.setErrorReporter(this); + } + + public void scan(final String folder) { + final File f = new File(folder); + if (showProgress) { + final ProgressMonitorListener progressMonitorListener = new ProgressMonitorListener(progressMonitorName); + addScanProgressListener(progressMonitorListener); + if (progressUsesThread) { + new Thread(new Runnable() { + + public void run() { + prescan(f,0,progressMonitorListener); + } + }).start(); + }else{ + prescan(f,0,progressMonitorListener); + } + } + scan(f); + fireClose(); + } + + private int prescan(File folderOrFile, int counter,final ProgressMonitorListener progressMonitorListener) { + if (folderOrFile.isDirectory()) { + for (final File file : folderOrFile.listFiles()) { + counter=prescan(file,counter,progressMonitorListener); + } + if(counter>10){ + + progressMonitorListener.setTotalToProcess(counter); + } + return counter; + } else if (!folderOrFile.isHidden() && checkExtension(folderOrFile)) { + return counter+1; + }else{ + return counter; + } + } + + public void scan(final File folderOrFile) { + if (folderOrFile.isDirectory()) { + for (final File file : folderOrFile.listFiles()) { + scan(file); + } + } else if (!folderOrFile.isHidden() && checkExtension(folderOrFile)) { + final String src = load(folderOrFile); + // System.out.println("processing " + file); + try { + process(src, folderOrFile.getAbsolutePath()); + } catch (final Exception e) { + if (!quiet) { + if (verbose) { + e.printStackTrace(System.err); + }else{ + System.err.println(e.getMessage()); + } + } + /*bugs.add(new BugInfo.BugInfoBuilder().setMessageCode("FILE_ERROR") + .setFilename(folderOrFile.getAbsolutePath()).setMessage(e.getMessage()).setSeverity("ERROR") + .build());*/ + if (logError) { + System.out.println("Logging Error: " + FILE_ERROR); + fireCFLintException(e,FILE_ERROR,folderOrFile.getAbsolutePath(),null,null,null,null); + } + } + } + } + + protected boolean checkExtension(final File file) { + for (final String ext : allowedExtensions) { + if (file.getName().endsWith(ext)) { + return true; + } + } + return false; + } + + static String load(final File file) { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + final byte[] b = new byte[fis.available()]; + fis.read(b); + return new String(b); + } catch (final Exception e) { + return null; + } finally { + try { + if (fis != null) + fis.close(); + } catch (IOException e) { + return null; + } + } + } + + + int parserCounter = 1; + + public void process(final String src, final String filename) throws ParseException, IOException { + fireStartedProcessing(filename); + final CFMLSource cfmlSource = new CFMLSource(src); + final List elements = cfmlSource.getChildElements(); + if (elements.isEmpty() && src.contains("component")) { + // Check if pure cfscript + final CFScriptStatement scriptStatement = cfmlParser.parseScript(src); + process(scriptStatement, filename, null, (String)null); + } else { + processStack(elements, " ", filename, null); + } + fireFinishedProcessing(filename); + } + + public void processStack(final List elements, final String space, final String filename, + final CFIdentifier functionName) throws ParseException, IOException { + for (final Element elem : elements) { + final Context context = new Context(filename, elem, functionName, inAssignment, handler); + process(elem,space,context); + } + } + public void processStack(final List elements, final String space, final Context context) throws ParseException, IOException { + for (final Element elem : elements) { + process(elem, space, context.subContext(elem)); + } + } + + + private void process(final Element elem, final String space, Context context) + throws ParseException, IOException { + context.setInComponent(inComponent); + currentElement.push(elem); + + if (elem.getName().equalsIgnoreCase("cfcomponent")) { + inComponent = true; + handler.push("component"); + + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.startComponent(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + + context.setInComponent(true); + context.setComponentName(elem.getAttributeValue("displayname")); + } + else if (elem.getName().equalsIgnoreCase("cffunction")) { + context.setFunctionName(elem.getAttributeValue("name")); + inFunction = true; + handler.push("function"); + + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.startFunction(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + } + + try{ + for (final CFLintScanner plugin : extensions) { + try{ + plugin.element(elem, context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, plugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + if(verbose){ + e.printStackTrace(); + } + reportRule(elem, null, context, plugin, PLUGIN_ERROR + exceptionText(e)); + } + } + if (elem.getName().equalsIgnoreCase("cfset") || elem.getName().equalsIgnoreCase("cfif") + || elem.getName().equalsIgnoreCase("cfelseif")|| elem.getName().equalsIgnoreCase("cfreturn")) { + //final int elemLine = elem.getSource().getRow(elem.getBegin()); + //final int elemColumn = elem.getSource().getColumn(elem.getBegin()); + final Pattern p = Pattern.compile("<\\w+\\s(.*[^/])/?>",Pattern.MULTILINE|Pattern.DOTALL); + final String expr = elem.getFirstStartTag().toString(); + final Matcher m = p.matcher(expr); + if (m.matches()) { + final String cfscript = m.group(1); + try { +// if(elem.getName().equalsIgnoreCase("cfset")){ +// System.out.println("parse: " + cfscript + ";"); +// final CFScriptStatement scriptStatement = cfmlParser.parseScript(cfscript + ";"); +// process(scriptStatement, context.getFilename(), elem, context.getFunctionName()); +// }else{ + final CFExpression expression = cfmlParser.parseCFExpression(cfscript,this); + + if (expression == null) { + throw new NullPointerException("expression is null, parsing error"); + } + process(expression, context.getFilename(), elem, context.getFunctionName()); +// } + } catch (final Exception npe) { + final int line = elem.getSource().getRow(elem.getBegin()); + //final int column = elem.getSource().getColumn(elem.getBegin()); + if (!quiet) { + System.err.println("Error in: " + shortSource(elem.getSource(), line) + " @ " + line + ":"); + if (verbose) { + npe.printStackTrace(System.err); + } + } + /*bugs.add(new BugInfo.BugInfoBuilder().setLine(elemLine).setColumn(elemColumn + column) + .setMessageCode("PARSE_ERROR").setSeverity("ERROR").setExpression(m.group(1)) + .setFilename(filename).setFunction(functionName).setMessage("Unable to parse").build());*/ +// if (logError) { +// System.out.println("Logging Error: " + PARSE_ERROR); +// fireCFLintException(npe,PARSE_ERROR,context.getFilename(),elemLine,elemColumn + column,context.getFunctionName(),m.group(1)); +// } + } + } + + } else if (elem.getName().equalsIgnoreCase("cfargument")) { + final String name = elem.getAttributeValue("name"); + if (name != null) { + handler.addArgument(name); + } + } else if (elem.getName().equalsIgnoreCase("cfscript")) { + final String cfscript = elem.getContent().toString(); + final CFScriptStatement scriptStatement = cfmlParser.parseScript(cfscript); + + process(scriptStatement, context.getFilename(), elem, context.getFunctionName()); + // } else if (elem.getName().equalsIgnoreCase("cfoutput")) { + // final Element parent = CFTool.getNamedParent(elem, "cfoutput"); + // if (parent != null && parent.getAttributeValue("query") != null + // && parent.getAttributeValue("group") == null) { + // final int line = elem.getSource().getRow(elem.getBegin()); + // final int column = elem.getSource().getColumn(elem.getBegin()); + // bugs.add(new + // BugInfo.BugInfoBuilder().setLine(line).setColumn(column).setMessageCode("NESTED_CFOUTPUT") + // .setSeverity("ERROR").setFilename(filename) + // .setMessage("Nested CFOutput, outer CFOutput has @query.").build()); + // } + } else { + } + + if (elem.getName().equalsIgnoreCase("cffunction")) { + processStack(elem.getChildElements(), space + " ", context); + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.endFunction(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + + }catch(Exception e){ + e.printStackTrace(); + } + } + inFunction = false; + handler.pop(); + } else if (elem.getName().equalsIgnoreCase("cfcomponent")) { + processStack(elem.getChildElements(), space + " ", context); + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.endComponent(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + + inComponent = false; + handler.pop(); + } else if (elem.getName().equalsIgnoreCase("cfquery")) { + final List list = elem.getAllElements(); + processStack(list.subList(1, list.size()), space + " ", context); + } else if (elem.getName().equalsIgnoreCase("cfqueryparam")) { + if (elem.getAttributeValue("value") != null) { + //final CFScriptStatement scriptStatement = cfmlParser.parseScript(elem.getAttributeValue("value") + ";"); + //process(scriptStatement, context.getFilename(), elem, context.getFunctionName()); + //TODO this could be 'parsed if the value has a # sign + } + } else { + processStack(elem.getChildElements(), space + " ", context); + } + }finally{ + currentElement.pop(); + } + } + + private List getStructureListeners(final List extensions) { + final List retval = new ArrayList(); + for(CFLintScanner plugin: extensions) + if(plugin instanceof CFLintStructureListener){ + retval.add((CFLintStructureListener) plugin); + } + return retval; + } + private String shortSource(final Source source, final int line) { + final String retval = source == null ? "" : source.toString().trim(); + if (retval.length() < 300) { + return retval; + } + try { + final BufferedReader sr = new BufferedReader(new StringReader(source.toString())); + for (int i = 1; i < line; i++) { + sr.readLine(); + } + return sr.readLine().replaceAll("\t", " "); + } catch (final Exception e) { + } + return retval.substring(0, 300); + } + + public String stripLineComments(final String cfscript) { + return cfscript.replaceAll("//[^\r\n]*\r?\n", "\r\n"); + } + + private void process(final CFScriptStatement expression, final String filename, final Element elem, + final CFIdentifier functionName) { + process(expression,filename,elem,functionName.getName()); + } + private void process(final CFScriptStatement expression, final String filename, final Element elem, + String functionName) { + final Context context = new Context(filename, elem, functionName, inAssignment, handler); + try{ + + context.setInComponent(inComponent); + if (expression instanceof CFCompDeclStatement) { + inComponent = true; + //do startComponent notifications + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.startComponent(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + } + else if (expression instanceof CFFuncDeclStatement) { + final CFFuncDeclStatement function = (CFFuncDeclStatement) expression; + functionName = function.getName().getName(); + context.setFunctionName(functionName); + inFunction = true; + handler.push("function"); + for (final CFFunctionParameter param : function.getFormals()) { + handler.addArgument(param.getName()); + } + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.startFunction(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + } + + for (final CFLintScanner plugin : extensions) { + try{ + plugin.expression(expression, context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, expression, context, plugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + if(verbose){ + e.printStackTrace(); + } + reportRule(elem, expression, context, plugin, PLUGIN_ERROR + exceptionText(e)); + } + } + + if (expression instanceof CFCompoundStatement) { + for (final CFScriptStatement statement : ((CFCompoundStatement) expression).getStatements()) { + process(statement, filename, elem, functionName); + } + } else if (expression instanceof CFExpressionStatement) { + process(((CFExpressionStatement) expression).getExpression(), filename, elem, functionName); + } else if (expression instanceof CFCompDeclStatement) { + //process the component declaration + process(((CFCompDeclStatement) expression).getBody(), filename, elem, functionName); + //do endComponent notifications + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.endComponent(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + + inComponent = false; + } else if (expression instanceof CFForStatement) { + process(((CFForStatement) expression).getInit(), filename, elem, functionName); + process(((CFForStatement) expression).getCond(), filename, elem, functionName); + process(((CFForStatement) expression).getNext(), filename, elem, functionName); + process(((CFForStatement) expression).getBody(), filename, elem, functionName); + } else if (expression instanceof CFForInStatement) { + process(((CFForInStatement) expression).getVariable(), filename, elem, functionName); + process(((CFForInStatement) expression).getStructure(), filename, elem, functionName); + process(((CFForInStatement) expression).getBody(), filename, elem, functionName); + } else if (expression instanceof CFIfStatement) { + final CFIfStatement cfif = (CFIfStatement) expression; + process(cfif.getCond(), filename, elem, functionName); + process(cfif.getThenStatement(), filename, elem, functionName); + if (cfif.getElseStatement() != null) { + process(cfif.getElseStatement(), filename, elem, functionName); + } + } else if (expression instanceof CFReturnStatement) { + final CFReturnStatement cfreturn = (CFReturnStatement) expression; + //TODO replace with cfreturn.getExpression() when next cfmlparser is released + Field f; + try { + f = CFReturnStatement.class.getDeclaredField("_ret"); + f.setAccessible(true); + CFExpression subExpression = (CFExpression) f.get(cfreturn); + if(subExpression !=null){ + process(subExpression, filename, elem, functionName); + } + } catch (Exception e) { + } //NoSuchFieldException + + + } else if (expression instanceof CFFuncDeclStatement) { + final CFFuncDeclStatement function = (CFFuncDeclStatement) expression; + process(function.getBody(), filename, elem, function.getName()); + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.endFunction(context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, null, context, (CFLintScanner)structurePlugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + e.printStackTrace(); + } + } + inFunction = false; + handler.pop(); + } else { + } + }catch(StackOverflowError soe){ + System.err.println("Stack overflow in " + filename); + final int line = context.startLine(); + fireCFLintException(soe,PARSE_ERROR,filename,line,1,"","Stack overflow on " + expression.getClass()); + } + } + + /** + * Return the exception message, or its class name + * @param e + * @return + */ + private String exceptionText(Exception e) { + final String msg = e.getMessage(); + if(msg == null || msg.trim().length()==0){ + return e.getClass().toString(); + } + return msg; + } + private void process(final CFExpression expression, final String filename, final Element elem, + final String functionName) { + final Context context = new Context(filename, elem, functionName, inAssignment, handler); + context.setInComponent(inComponent); + + + for (final CFLintScanner plugin : extensions) { + try{ + plugin.expression(expression, context, bugs); + for(final ContextMessage message : context.getMessages()){ + reportRule(elem, expression, context, plugin, message); + } + context.getMessages().clear(); + }catch(Exception e){ + if(verbose){ + e.printStackTrace(); + } + reportRule(elem, expression, context, plugin, PLUGIN_ERROR + exceptionText(e)); + } + } + if (expression instanceof CFUnaryExpression) { + process(((CFUnaryExpression) expression).getSub(), filename, elem, functionName); + }else if (expression instanceof CFNestedExpression) { + process(((CFNestedExpression) expression).getSub(), filename, elem, functionName); + } else if (expression instanceof CFAssignmentExpression) { + inAssignment = true; + process(((CFAssignmentExpression) expression).getLeft(), filename, elem, functionName); + inAssignment = false; + process(((CFAssignmentExpression) expression).getRight(), filename, elem, functionName); + } else if (expression instanceof CFBinaryExpression) { + process(((CFBinaryExpression) expression).getLeft(), filename, elem, functionName); + process(((CFBinaryExpression) expression).getRight(), filename, elem, functionName); + } else if (expression instanceof CFFunctionExpression) { + final CFFunctionExpression cfFunctionExpr = (CFFunctionExpression) expression; + // if ("QueryNew".equalsIgnoreCase(cfFunctionExpr.getName()) && + // cfFunctionExpr.getArgs().size() == 1) { + // bugs.add(new + // BugInfo.BugInfoBuilder().setMessageCode("QUERYNEW_DATATYPE") + // .setMessage("QueryNew statement should specify datatypes.").setVariable("QueryNew") + // .setFunction(functionName).setSeverity("WARNING").setFilename(filename) + // .setExpression(expression.Decompile(0)).build(expression, elem)); + // } + for (final CFExpression expr : cfFunctionExpr.getArgs()) { + process(expr, filename, elem, functionName); + } + } else if (expression instanceof CFIdentifier) { + final String name = ((CFIdentifier) expression).getName(); + handler.checkVariable(name); + // if (inFunction && inAssignment && !handler.checkVariable(name)) { + // bugs.add(new + // BugInfo.BugInfoBuilder().setMessageCode("MISSING_VAR") + // .setMessage("Variable " + name + + // " is not declared with a var statement.").setVariable(name) + // .setFunction(functionName).setSeverity("ERROR").setFilename(filename) + // .setExpression(expression.Decompile(0)).build(expression, elem)); + // } + if(expression instanceof CFFullVarExpression){ + CFFullVarExpression fullVarExpression = (CFFullVarExpression)expression; + for(CFExpression expr: fullVarExpression.getExpressions()){ + if(expr instanceof CFFunctionExpression){ + process(expr,filename,elem,functionName); + } + } + } + } else if (expression instanceof CFVarDeclExpression) { + handler.addVariable(((CFVarDeclExpression) expression).getName()); + process(((CFVarDeclExpression) expression).getInit(), filename, elem, functionName); + } else if (expression instanceof CFStringExpression) { + CFStringExpression stringExpression = (CFStringExpression) expression; + for(CFExpression expr: stringExpression.getSubExpressions()){ + process(expr,filename,elem,functionName); + } + } else if (expression instanceof CFLiteral) { +// if(expression.getToken().getType() == CFSCRIPTLexer.STRING_LITERAL){ +// for(String subExprStr : splitHash(expression.Decompile(0))){ +// try{ +// final CFExpression subExpression = cfmlParser.parseCFExpression(subExprStr,this); +// if (expression == null) { +// throw new NullPointerException("expression is null, parsing error"); +// } +// process(subExpression, filename, elem,functionName); +// } catch (final Exception npe) { +// final int line = elem.getSource().getRow(elem.getBegin()); +// final int column = elem.getSource().getColumn(elem.getBegin()); +// if (!quiet) { +// System.err.println("Error in: " + shortSource(elem.getSource(), line) + " @ " + line + ":"); +// if (verbose) { +// npe.printStackTrace(System.err); +// } +// } +// } +// } +// +// } + // } else if (expression instanceof CFFullVarExpression) { + // if (((CFFullVarExpression) expression).getExpressions().size() == + // 1) { + // process(((CFFullVarExpression) + // expression).getExpressions().get(0), filename, elem, + // functionName); + // } + } + else if (expression instanceof CFStringExpression){ + for(CFExpression expr : ((CFStringExpression) expression).getSubExpressions()){ + process(expr,filename,elem,functionName); + } + } + else { + } + } + + protected void reportRule(final Element elem, final Object expression, final Context context, final CFLintScanner plugin, String msg) { + final String[] exceptionmsg = (msg!=null?msg:"").split(":"); + final String msgcode = exceptionmsg[0].trim(); + final String nameVar = exceptionmsg.length>1?exceptionmsg[1].trim():null; + reportRule(elem, expression,context,plugin,new ContextMessage(msgcode, nameVar)); + } + + public static Element getPreviousSibling(Element element){ + + if(element.getParentElement() != null){ + List parentElements = element.getParentElement().getChildElements(); + int idx = parentElements.indexOf(element); + if(idx > 0){ + return parentElements.get(idx-1); + } + }else if(element.getSource() != null){ + List parentElements = element.getSource().getChildElements(); + int idx = parentElements.indexOf(element); + if(idx > 0){ + return parentElements.get(idx-1); + } + } + return null; + } + + /* + * Check for in the tag hierarchy + */ + protected boolean checkForDisabled(final Element element, + final String msgcode) { + Element elem = element; + while (elem != null) { + Element prevSibling = getPreviousSibling(elem); + if (prevSibling != null && prevSibling.getName().equals("!---")) { + Pattern p = Pattern + .compile(".*---\\s*CFLINT-DISABLE\\s+(.*)\\s*---.*"); + Matcher m = p.matcher(prevSibling.toString().toUpperCase() + .trim()); + if (m.matches()) { + // No message codes in CFLINT-DISABLE + if (m.group(1).trim().length() == 0) { + if (verbose) { + System.out.println("Skipping disabled " + msgcode); + } + return true; + } + // check for matching message codes in CFLINT-DISABLE + for (String skipcode : m.group(1).split(",")) { + skipcode = skipcode.trim(); + if (msgcode.equals(skipcode)) { + if (verbose) { + System.out.println("Skipping disabled " + + msgcode); + } + return true; + } + } + } + } + elem = elem.getParentElement(); + } + return false; + } + + protected void reportRule(final Element elem, final Object expression, final Context context, final CFLintScanner plugin, ContextMessage msg) { + final String msgcode = msg.getMessageCode(); + final String nameVar = msg.getVariable(); + + if(checkForDisabled(elem,msgcode)){ + return; + } + if(configuration == null){ + throw new NullPointerException("Configuration is null"); + } + PluginInfoRule ruleInfo; + if("PLUGIN_ERROR".equals(msgcode)){ + ruleInfo = new PluginInfoRule(); + PluginMessage msgInfo = new PluginMessage("PLUGIN_ERROR"); + msgInfo.setMessageText("Error in plugin: ${variable}"); + msgInfo.setSeverity("ERROR"); + ruleInfo.getMessages().add(msgInfo); + }else{ + ruleInfo = configuration.getRuleForPlugin(plugin); + } + if(ruleInfo == null){ + throw new NullPointerException("Rule not found for " + plugin.getClass().getSimpleName()); + } + final PluginMessage msgInfo = ruleInfo.getMessageByCode(msgcode); + if(configuration == null){ + throw new NullPointerException("Message definition not found for [" + msgcode + "] in " + plugin.getClass().getSimpleName()); + } + BugInfoBuilder bldr = new BugInfo.BugInfoBuilder().setMessageCode(msgcode).setVariable(nameVar) + .setFunction(context.getFunctionName()) + .setFilename(context.getFilename()); + if(msgInfo != null){ + bldr.setSeverity(msgInfo.getSeverity()); + bldr.setMessage(msgInfo.getMessageText()); + }else{ + System.err.println("Message code: " + msgcode + " is not configured correctly."); + bldr.setSeverity("WARNING"); + bldr.setMessage(msgcode); + } + if(expression instanceof CFStatement){ + bldr.setExpression(((CFStatement) expression).Decompile(0)); + } + else if(expression instanceof CFScriptStatement){ + bldr.setExpression(((CFScriptStatement) expression).Decompile(0)); + } + else if(elem != null){ + bldr.setExpression(elem.toString()); + } + bldr.setRuleParameters(ruleInfo.getParameters()); + if (expression instanceof CFExpression){ + bugs.add(bldr.build((CFExpression)expression, elem)); + }else{ + BugInfo bug = bldr.build((CFParsedStatement)expression, elem); + if(msg.getLine() != null){ + bug.setLine(msg.getLine()); + bug.setColumn(0); + } + bugs.add(bug); + } + } + + public BugList getBugs() { + return bugs; + } + + public List getAllowedExtensions() { + return allowedExtensions; + } + + public void setAllowedExtensions(final List allowedExtensions) { + this.allowedExtensions = allowedExtensions; + } + + public void reportError(final String arg0) { + // TODO Auto-generated method stub + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "------4-" + arg0); + + } + + public void reportError(final RecognitionException arg0) { + // TODO Auto-generated method stub + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "-------" + arg0); + + } + + public void reportError(final String[] arg0, final RecognitionException arg1) { + // TODO Auto-generated method stub + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "-------" + arg0); + } + + public void reportError(final IntStream arg0, final RecognitionException arg1, final BitSet arg2) { + // TODO Auto-generated method stub + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "-------" + arg0); + + } + + public void setVerbose(final boolean verbose) { + this.verbose = verbose; + } + + public void setLogError(final boolean logError) { + this.logError = logError; + } + + public void setQuiet(final boolean quiet) { + this.quiet = quiet; + } + + public void addScanProgressListener(final ScanProgressListener scanProgressListener) { + scanProgressListeners.add(scanProgressListener); + } + + protected void fireStartedProcessing(final String srcidentifier) { + currentFile = srcidentifier; + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.startFile(srcidentifier, bugs); + }catch(Exception e){ + e.printStackTrace(); + } + } + for (final ScanProgressListener p : scanProgressListeners) { + p.startedProcessing(srcidentifier); + } + } + + protected void fireFinishedProcessing(final String srcidentifier) { + for (final CFLintStructureListener structurePlugin : getStructureListeners(extensions)) { + try{ + structurePlugin.endFile(srcidentifier, bugs); + }catch(Exception e){ + e.printStackTrace(); + } + } + for (final ScanProgressListener p : scanProgressListeners) { + p.finishedProcessing(srcidentifier); + } + currentFile = null; + } + protected void fireClose() { + for (final ScanProgressListener p : scanProgressListeners) { + p.close(); + } + } + + public void addScanner(CFLintScanner plugin) { + extensions.add(plugin); + } + + public List getScanners() { + return extensions; + } + + public void addExceptionListener(final CFLintExceptionListener exceptionListener) { + exceptionListeners.add(exceptionListener); + } + + protected void fireCFLintException(final Throwable e, final String messageCode, final String filename, + final Integer line, final Integer column,final String functionName, final String expression) { + for (final CFLintExceptionListener p : exceptionListeners) { + p.exceptionOccurred(e, messageCode, filename, line, column, functionName, expression); + } + } + + public void setShowProgress(final boolean showProgress) { + this.showProgress = showProgress; + } + + public void setProgressUsesThread(final boolean progressUsesThread) { + this.progressUsesThread = progressUsesThread; + } + 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"; + 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){ + line = elem.getSource().getRow(elem.getBegin()); + charPositionInLine = charPositionInLine + elem.getSource().getColumn(elem.getBegin()); + }else{ + line = elem.getSource().getRow(elem.getBegin()) + line - 1; + } + } + if(recognizer instanceof Parser && ((Parser)recognizer).isExpectedToken(CFSCRIPTParser.SEMICOLON)){ + 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, + ATNConfigSet configs) { +// final String file = currentFile == null ? "" : currentFile + "\r\n"; +// System.out.println(file + "----reportAmbiguity ---"); + } + public void reportAttemptingFullContext(Parser recognizer, DFA dfa, + int startIndex, int stopIndex, java.util.BitSet conflictingAlts, + ATNConfigSet configs) { +// final String file = currentFile == null ? "" : currentFile + "\r\n"; +// System.out.println(file + "----reportAttemptingFullContext ---"); + } + public void reportContextSensitivity(Parser recognizer, DFA dfa, + int startIndex, int stopIndex, int prediction, ATNConfigSet configs) { +// final String file = currentFile == null ? "" : currentFile + "\r\n"; +// System.out.println(file + "----reportContextSensitivity ---"); + } + public void reportError(org.antlr.v4.runtime.RecognitionException re) { + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "----RecognitionException ---" + re.getCtx().getSourceInterval().a + " : " + + re.getCtx().getSourceInterval().b); + } + public void reportError(String[] tokenNames, + org.antlr.v4.runtime.RecognitionException re) { + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "----reportError ---" + re.getCtx().getSourceInterval().a + " : " + + re.getCtx().getSourceInterval().b); + } + public void reportError(org.antlr.v4.runtime.IntStream input, + org.antlr.v4.runtime.RecognitionException re, BitSet follow) { + final String file = currentFile == null ? "" : currentFile + "\r\n"; + System.out.println(file + "----reportError ---" ); + } + + + List splitHash(String input){ + input = input + " "; + List retval = new ArrayList(); + + int start = 0; + int end= -1; + + while(startstart){ + retval.add(input.substring(start, end)); + + } + start = end + 1; + while(start