diff --git a/README.md b/README.md index 4b8d8e8f0..1178706ee 100644 --- a/README.md +++ b/README.md @@ -88,17 +88,19 @@ The most simple options for executing CFLint is via the command line. CFLint cur ## Configuration -Alternatively to the commnand line you can supply a global configuration via the -config switch or put .cflintrc files into certain directories. Configuring CFLint this way conceptually allows you to run specific rules in specific parts of your application. +Alternatively to the commannd line you can supply a global configuration via the -configfile switch or put .cflintrc files into certain directories. Configuring CFLint this way conceptually allows you to run specific rules in specific parts of your application. + +CFlint currently supports XML- and JSON-based configuration. XML-based configuration will be deprecated in CFLint 1.3.0 and removed in CFLint 2.0. ### Rules -When CFLint executes, it scans and parses your code (using CFParser). The syntax tree is then being examined against a set of built-in rules. In CFLint those rules are called and implemented as plugins (they live in /src/main/java/com/cflint/plugins). By default all rules will be used against your codebase. This is what a lot of people will do, but using configuration allows you to build a custom scenario to test your code against. +When CFLint executes, it scans and parses your code (using CFParser). The syntax tree is then being examined against a set of built-in rules. In CFLint those rules are called and implemented as plugins (they live in /src/main/java/com/cflint/plugins). By default all rules will be used against your codebase. This is what a lot of people will do, but using configuration allows you to build a custom scenario to test your code against. See RULES.md for more information on rules and their meaning. ### Global configuration The -configfile options can be used to replace the standard global configuration file. -The standard configuration is src/main/resources/cflint.definition.json. Normal usage of CFLint does not normally require replacing this file. +The standard configuration is src/main/resources/cflint.definition.json. Common usage of CFLint usually does not require replacing this file. ### Folder-based configuration @@ -119,15 +121,48 @@ An example .cflintrc file is shown below: - rule allows you add a plugin for this folder that is not listed in the global configuration. See ruleImpl in cflint.definition.json for examples. -- excludes and includes allow you to specify an array of objects describing rules you want to be applied for this directory and its children. In the example above, the only rule to be checked for will be FUNCTION_HINT_MISSING. The messageText and severity properties allow you to customise those values for this specific part of your CFLint run. +- excludes and includes allow you to specify an array of objects describing rules you want to be applied for this directory and its children. In the example above, the only rule to be checked for will be FUNCTION_HINT_MISSING. - inheritParent configures if the rules set in the global or any parent configuration should be inherited as a base set of rules. -- Please note: inheritPlugins and output have been marked deprecated in CFLint 1.2.0 and will be removed in 1.3.0. If you are using .cflintrc files now, please remove the inheritPlugins and output property as soon as possible. Plugin inheritance will going forward always be treated as true, the team can not see a use case in which it should be disabled. The value of the output attribute is ignored. +- Please note: inheritPlugins and output have been marked deprecated in CFLint 1.2.0 and will be removed in 1.3.0. If you are using .cflintrc files now, please remove the inheritPlugins and output properties as soon as possible. Plugin inheritance will going forward always be treated as true, the team can not see a use case in which it should be disabled. The value of the output attribute is ignored. ### Annotation-based configuration -Annotation-based configuration allows you to ignore ... more to come from Kai +Quite often there are scenarios in which you would generally want to run a certain set of rules against your code but in specific cases need to ignore an otherwise valid violation. + +A common example are violations of CFQUERYPARAM_REQ that can't be fixed by applying because your DB server doesn't allow in a certain position (for instance in a SELECT TOP #arguments.numberOfRecords# ... scenario). See [#282](https://github.com/cflint/CFLint/issues/282) for more examples. + +CFLint offers an annotation-based configuration to deal with this and similar scenarios. Annotations can be placed on the component- or function-level in a CFC or inline with code. + +#### Tag-based CFML: + + + +#### CFSCRIPT: + +Ignoring all rules on the current line: + + //cflint ignore:line + +Ignoring a specific rule (or a comma-separated list of rules) on the current line: + + //cflint ignore:MISSING_VAR + +Multiline ignore annotation: + + /* + @CFLintIgnore SOMETHINGELSE,MISSING_VAR,ANOTHERTHINGTOIGNORE + */ +#### Ignoring within SQL: + +Within SQL, you can also use + + + +to ignore a rule violation on the next line. ### Precendence of configuration settings @@ -144,7 +179,6 @@ The configuration rule that is closest to the rule is the one that takes effect. * If an annotation excludes a message, it will not fire regardless of any configuration above it. * If you exclude a rule at the command line level, but a .cflintrc adds it back in, it will fire for source files in that part of the source tree. - ## Creating reports More to come on this and the subsections from Kai @@ -160,8 +194,6 @@ More to come on this and the subsections from Kai ### Text - - ## Integration server support For Jenkins, please look at the Jenkins/Hudson plugin mentioned further below. @@ -170,9 +202,9 @@ Jetbrains' TeamCity has support for Findbugs XML code inspection reports. They c There is support for SonarQube through Stepstone's Sonar ColdFusion plugin mentioned further below. -Other products in the integeration/build server category might work, too. If you're using a specific product that works for you with CFLint please let us know. If you can't get CFLint to work in an environment you use, please let us know as well - we might be able to help. - +There's an NPM wrapper for CLint below. Please be aware that the wrapper seems to come with its own bundled CFLint binary which might not be up to date, which is outside of our control. +Other products in the integeration/build server category might work, too. If you're using a specific product that works for you with CFLint please let us know. If you can't get CFLint to work in an environment you use, please let us know as well - we might be able to help. ## IDE support @@ -180,13 +212,63 @@ Currently there is IDE support for Sublime through a 3rd-party project (see belo There is also support for Adobe's CFBuilder through a 3rd-party project (see below). Users of CFBuilder, please also see the discussion in issue [#327](https://github.com/cflint/CFLint/issues/327). +Users of Atom can integrate with AtomLinter through a 3rd-party project (see below). + Support for Jetbrains' IntelliJ is planned; talk to [@TheRealAgentK](https://github.com/TheRealAgentK) for more info if you're interested. ## Extending CFLint ### Adding custom rules -Some stuff from the Wiki to come + package com.cflint.plugins.core; + + import net.htmlparser.jericho.Element; + import cfml.parsing.cfscript.script.CFFuncDeclStatement; + import cfml.parsing.cfscript.script.CFFunctionParameter; + import cfml.parsing.cfscript.script.CFScriptStatement; + + import com.cflint.BugList; + import com.cflint.plugins.CFLintScannerAdapter; + import com.cflint.plugins.Context; + import com.cflint.tools.CFTool; + + public class ArgDefChecker extends CFLintScannerAdapter { + + @Override + public void expression(final CFScriptStatement expression, final Context context, final BugList bugs) { + if (expression instanceof CFFuncDeclStatement) { + final CFFuncDeclStatement function = (CFFuncDeclStatement) expression; + for (final CFFunctionParameter argument : function.getFormals()) { + // handler.addArgument(param.getName()); + final String name = argument.getName(); + if (!argument.toString().contains("required") && !argument.toString().contains("=")) { + function.getLine(); + function.getColumn(); + context.addMessage("ARG_DEFAULT_MISSING", name); + } + } + } + } + + @Override + public void element(final Element element, final Context context, final BugList bugs) { + if (element.getName().equals("cfargument")) { + final String name = element.getAttributeValue("name"); + final boolean required = CFTool.toBoolean(element.getAttributeValue("required")); + final String defaultExpr = element.getAttributeValue("default"); + if (!required && defaultExpr == null) { + element.getSource().getRow(element.getBegin()); + element.getSource().getColumn(element.getBegin()); + context.addMessage("ARG_DEFAULT_MISSING", name); + } + } + } + } + +Looking at the function `element`, the arguments are: +* element - the current CFML tag +* context - the current file being checked +* bugs - the appending object of violations # Receipes @@ -278,7 +360,9 @@ Please note that the majority of the libraries and projects mentioned here are n - [Jenkins/Hudson plugin](https://github.com/jenkinsci/CFLint-plugin) for CFLint - [SublimeLinter plugin](https://github.com/ckaznocha/SublimeLinter-contrib-CFLint) for CFlint - [CFBuilder plugin](https://github.com/cfjedimaster/CFLint-Extension) for CFLint +- [Atom plugin](https://github.com/ditinc/linter-cflint) for CFLint - [Sonar plugin](https://github.com/stepstone-tech/sonar-coldfusion) +- [NPM wrapper](https://github.com/morgdenn/npm-cflint) - Vim [Syntastic support for CFLint](https://github.com/cflint/cflint-syntastic) diff --git a/RULES.md b/RULES.md index 88bbd3968..70737b6dc 100644 --- a/RULES.md +++ b/RULES.md @@ -1,5 +1,227 @@ List of built-in rules and rule groups ====================================== -from the wiki +## Built-in rules +* ArgDefChecker + * ARG_DEFAULT_MISSING - Optional argument is missing a default value. +* ArgVarChecker + * ARG_VAR_CONFLICT - Variable declared in both var and argument scopes. + * ARG_VAR_MIXED - Variable referenced in local and argument scopes. +* CFSwitchDefaultChecker + * NO_DEFAULT_INSIDE_SWITCH - Missing default switch statement. +* GlobalVarChecker + * GLOBAL_VAR - Global variable exists. +* NestedCFOutput + * NESTED_CFOUTPUT - Nested `cfoutput` with `cfquery` tag. +* OutputParmMissing + * OUTPUT_ATTR - Tag should have `output='false'`. +* QueryParamChecker + * QUERYPARAM_REQ - `SetSql()` statement should use `.addParam()`. + * CFQUERYPARAM_REQ - `cfquery` should use ``. +* TypedQueryNew + * QUERYNEW_DATATYPE - QueryNew statement should specify datatypes. +* VarScoper + * MISSING_VAR - Variable is not declared with a var statement. +* CFDumpChecker + * AVOID_USING_CFDUMP_TAG - Avoid use of `cfdump` tags. +* CFExecuteChecker + * AVOID_USING_CFEXECUTE_TAG - Avoid use of `cfexecute` tags. +* CFAbortChecker + * AVOID_USING_CFABORT_TAG - Avoid use of `cfabort` tags. +* AbortChecker + * AVOID_USING_ABORT - Avoid use of abort statements. +* CFInsertChecker + * AVOID_USING_CFINSERT_TAG - Avoid use of `cfinsert` tags. +* CFModuleChecker + * AVOID_USING_CFMODULE_TAG - Avoid use of `cfmodule` tags. +* CFUpdateChecker + * AVOID_USING_CFUPDATE_TAG - Avoid use of `cfupdate` tags. +* CFIncludeChecker + * AVOID_USING_CFINCLUDE_TAG - Avoid use of `cfinclude` tags. +* ComponentHintChecker + * COMPONENT_HINT_MISSING - Component is missing a hint. +* FunctionHintChecker + * FUNCTION_HINT_MISSING - Function is missing a hint. +* ArgumentHintChecker + * ARG_HINT_MISSING - Argument is missing a hint. +* ArgumentTypeChecker + * ARG_TYPE_MISSING - Component is missing a type. + * ARG_TYPE_ANY - Component is of type any. +* FunctionLengthChecker + * EXCESSIVE_FUNCTION_LENGTH - Method is too long. +* ComponentLengthChecker + * EXCESSIVE_COMPONENT_LENGTH - Component is too long. +* FunctionTypeChecker + * FUNCTION_TYPE_MISSING - Function is missing a return type. + * FUNCTION_TYPE_ANY - Function has a return type of any. +* TooManyArgumentsChecker + * EXCESSIVE_ARGUMENTS - Function has too many arguments. +* TooManyFunctionsChecker + * EXCESSIVE_FUNCTIONS - Too many functions. +* SimpleComplexityChecker + * FUNCTION_TOO_COMPLEX - Function is too complex. +* WriteDumpChecker + * AVOID_USING_WRITEDUMP - Avoid use of `writedump` statements. +* StructNewChecker + * AVOID_USING_STRUCTNEW - Avoid use of `structnew` statements. Use `{}` instead. +* IsDebugModeChecker + * AVOID_USING_ISDEBUGMODE - Avoid use of `isdebugmode` statements. +* ArrayNewChecker + * AVOID_USING_ARRAYNEW - Avoid use of `arraynew` statements. Use `[]` instead. +* ComplexBooleanExpressionChecker + * COMPLEX_BOOLEAN_CHECK - Complex boolean expression. +* BooleanExpressionChecker + * EXPLICIT_BOOLEAN_CHECK - Checking boolean expression explicitly. +* VariableNameChecker + * VAR_INVALID_NAME - Variable has invalid name. + * VAR_ALLCAPS_NAME - Variable name is allcaps. + * VAR_TOO_SHORT - Variable name is too short. + * VAR_TOO_LONG - Variable name is too long. + * VAR_TOO_WORDY - Variable name contain too many words. + * VAR_IS_TEMPORARY - Variable name looks temporary. + * VAR_HAS_PREFIX_OR_POSTFIX - Variable name has prefix or postfix. +* ArgumentNameChecker + * ARGUMENT_INVALID_NAME - Argument has invalid name. + * ARGUMENT_ALLCAPS_NAME - Argument name is allcaps. + * ARGUMENT_TOO_SHORT - Argument name is too short. + * ARGUMENT_TOO_LONG - Argument name is too long. + * ARGUMENT_TOO_WORDY - Argument name contain too many words. + * ARGUMENT_IS_TEMPORARY - Argument name looks temporary. + * ARGUMENT_HAS_PREFIX_OR_POSTFIX - Argument name has prefix or postfix. +* MethodNameChecker + * METHOD_INVALID_NAME - Method has invalid name. + * METHOD_ALLCAPS_NAME - Method name is allcaps. + * METHOD_TOO_SHORT - Method name is too short. + * METHOD_TOO_LONG - Method name is too long. + * METHOD_TOO_WORDY - Method name contain too many words. + * METHOD_IS_TEMPORARY - Method name looks temporary. + * METHOD_HAS_PREFIX_OR_POSTFIX - Method name has prefix or postfix. +* ComponentNameChecker + * COMPONENT_INVALID_NAME - Component has invalid name. + * COMPONENT_ALLCAPS_NAME - Component name is allcaps. + * COMPONENT_TOO_SHORT - Component name is too short. + * COMPONENT_TOO_LONG - Component name is too long. + * COMPONENT_TOO_WORDY - Component name contain too many words. + * COMPONENT_IS_TEMPORARY - Component name looks temporary. + * COMPONENT_HAS_PREFIX_OR_POSTFIX - Component name has prefix or postfix. +* FileCaseChecker + * FILE_SHOULD_START_WITH_LOWERCASE - CFM File starts with upper case. +* CreateObjectChecker + * AVOID_USING_CREATEOBJECT - Avoid use of `creatobject` statements. +* CFDebugAttributeChecker + * AVOID_USING_DEBUG_ATTR - Avoid use of debug attribute. +* UnusedLocalVarChecker + * UNUSED_LOCAL_VARIABLE - Unused local variable. +* UnusedArgumentChecker + * UNUSED_METHOD_ARGUMENT - Unused method argument. +* CFCompareVsAssignChecker + * COMPARE_INSTEAD_OF_ASSIGN - Using comparison where assignment was probably meant. + +Also: + +* UnknownCategory + * AVOID_EMPTY_FILES - Reports on empty (and therefore probably unnecessary) files. + +## Rule Groups + +### BugProne + * ARG_VAR_CONFLICT : ERROR + * NO_DEFAULT_INSIDE_SWITCH : WARNING + * NESTED_CFOUTPUT : ERROR + * OUTPUT_ATTR : INFO + * MISSING_VAR : ERROR + * COMPARE_INSTEAD_OF_ASSIGN : WARNING + +### Correctness + * ARG_DEFAULT_MISSING : WARNING + * ARG_TYPE_ANY : WARNING + * ARG_TYPE_MISSING : WARNING + * ARG_VAR_MIXED : INFO + * QUERYNEW_DATATYPE : WARNING + * UNUSED_LOCAL_VARIABLE : INFO + * UNUSED_METHOD_ARGUMENT : INFO + * UNQUOTED_STRUCT_KEY : WARNING + * USE_DISPLAY_NAME : INFO + +### BadPractice + * AVOID_USING_ABORT : INFO + * AVOID_USING_CFABORT_TAG : INFO + * AVOID_USING_CFDUMP_TAG : WARNING + * AVOID_USING_CFEXECUTE_TAG : WARNING + * AVOID_USING_CFINSERT_TAG : WARNING + * AVOID_USING_CFMODULE_TAG : WARNING + * AVOID_USING_CFUPDATE_TAG : WARNING + * AVOID_USING_WRITEDUMP : INFO + * GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN : WARNING + * GLOBAL_VAR : WARNING + * LOCAL_LITERAL_VALUE_USED_TOO_OFTEN : WARNING + * SQL_SELECT_STAR : WARNING + * AVOID_USING_DEBUG_ATTR : WARNING + * AVOID_USING_CFSETTING_DEBUG : WARNING + * AVOID_USING_CFINCLUDE_TAG : WARNING + * AVOID_USING_ISDEBUGMODE : WARNING + * AVOID_EMPTY_FILES : WARNING + +### Security + * CFQUERYPARAM_REQ : WARNING + * QUERYPARAM_REQ : WARNING + +### CodeStyle + * ARG_HINT_MISSING : INFO + * COMPONENT_HINT_MISSING : WARNING + * FUNCTION_HINT_MISSING : INFO + * FUNCTION_TYPE_ANY : INFO + * FUNCTION_TYPE_MISSING : WARNING + * ARG_HINT_MISSING_SCRIPT : INFO + +### ModernSyntax + * AVOID_USING_ARRAYNEW : INFO + * AVOID_USING_STRUCTNEW : INFO + * AVOID_USING_CREATEOBJECT : INFO + +### Complexity + * COMPLEX_BOOLEAN_CHECK : WARNING + * EXCESSIVE_FUNCTIONS : WARNING + * EXCESSIVE_ARGUMENTS : WARNING + * EXPLICIT_BOOLEAN_CHECK : INFO + * EXCESSIVE_COMPONENT_LENGTH : WARNING + * EXCESSIVE_FUNCTION_LENGTH : WARNING + * FUNCTION_TOO_COMPLEX : WARNING + +### Naming + * METHOD_HAS_PREFIX_OR_POSTFIX : INFO + * METHOD_INVALID_NAME : INFO + * METHOD_IS_TEMPORARY : INFO + * METHOD_TOO_SHORT : INFO + * METHOD_TOO_LONG : INFO + * METHOD_TOO_WORDY : INFO + * VAR_ALLCAPS_NAME : INFO + * VAR_HAS_PREFIX_OR_POSTFIX : INFO + * VAR_INVALID_NAME : INFO + * VAR_IS_TEMPORARY : INFO + * VAR_TOO_SHORT : INFO + * VAR_TOO_LONG : INFO + * VAR_TOO_WORDY : INFO + * SCOPE_ALLCAPS_NAME : INFO + * ARGUMENT_MISSING_NAME : INFO + * ARGUMENT_INVALID_NAME : INFO + * ARGUMENT_ALLCAPS_NAME : INFO + * ARGUMENT_TOO_SHORT : INFO + * ARGUMENT_TOO_LONG : INFO + * ARGUMENT_TOO_WORDY : INFO + * ARGUMENT_IS_TEMPORARY : INFO + * ARGUMENT_HAS_PREFIX_OR_POSTFIX : INFO + * METHOD_ALLCAPS_NAME : INFO + * COMPONENT_INVALID_NAME : INFO + * COMPONENT_ALLCAPS_NAME : INFO + * COMPONENT_TOO_SHORT : INFO + * COMPONENT_TOO_LONG : INFO + * COMPONENT_TOO_WORDY : INFO + * COMPONENT_IS_TEMPORARY : INFO + * COMPONENT_HAS_PREFIX_OR_POSTFIX : INFO + * PACKAGE_CASE_MISMATCH : WARNING + +### Experimental + * NEVER_USE_QUERY_IN_CFM : WARN + * FILE_SHOULD_START_WITH_LOWERCASE : INFO \ No newline at end of file