All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cflint.plugins.core.LiteralChecker Maven / Gradle / Ivy

Go to download

A static code analysis tool for ColdFusion (in the spirit of FindBugs and Lint). With CFLint, you are able to analyze your ColdFusion code base for code violations.

There is a newer version: 1.5.0
Show newest version
package com.cflint.plugins.core;

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

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

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

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

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

    protected Map globalLiterals = new HashMap();
    protected Map functionListerals = new HashMap();

    // 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) {
        final String repeatThreshold = getParameter("Maximum");
        final String maxWarnings = getParameter("MaxWarnings");
        final String warningScope = getParameter("WarningScope");        
        if (repeatThreshold != null) {
            threshold = Integer.parseInt(repeatThreshold);
        }

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

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

            if (isCommon(name)) {
                return;
            }

            final 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, final Map literals,
            final 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) {
    	if (!isSpecial(name.toLowerCase()) ){
    		context.addUniqueMessage("LOCAL_LITERAL_VALUE_USED_TOO_OFTEN", name, this, lineNo);
    	}
    }

    /**
     * Checks if the literal is a special case that should not fire the literal checker rule
     * @param name
     * @return
     */
    private boolean isSpecial(String name) {
    	//Empty literals do not flag
    	if(name == null || name.length()==0){
    		return true;
    	}
    	//Punctuation literals excepted (Look for absense of a word character)
    	if(!name.matches(".*\\w.*")){
    		return true;
    	}
    	//Exclude datatype for cfquery/cfproc
    	if(name.startsWith("cf_sql_")){
    		return true;
    	}
    	//Check ignore words list from the configuration
    	return getParameterAsList("IgnoreWords").contains(name.toLowerCase());
	}

	public void magicGlobalValue(final String name, final int lineNo, final Context context, final BugList bugs) {
		if (!isSpecial(name.toLowerCase()) ){
	    	context.addUniqueMessage("GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN", name, this, lineNo);
    	}
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy