From d92688a07dc5e6edc3bfc81cced6f25c951a19f4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 2 Feb 2017 20:08:53 +0100 Subject: [PATCH] Introduce end-of-line normalization References pmd/build-tools#2 --- .gitattributes | 13 + .../pmd/lang/apex/ApexHandler.java | 114 +- .../sourceforge/pmd/lang/apex/ApexParser.java | 86 +- .../pmd/lang/apex/ApexParserOptions.java | 66 +- .../pmd/lang/apex/ast/AbstractApexNode.java | 282 +- .../pmd/lang/apex/ast/ApexNode.java | 54 +- .../pmd/lang/apex/ast/ApexParser.java | 194 +- .../pmd/lang/apex/ast/ApexParserVisitor.java | 338 +- .../apex/ast/ApexParserVisitorAdapter.java | 826 +- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 1282 +- .../pmd/lang/apex/rule/AbstractApexRule.java | 1074 +- .../rule/AbstractStatisticalApexRule.java | 64 +- .../lang/apex/rule/ApexRuleChainVisitor.java | 86 +- .../apex/rule/ApexRuleViolationFactory.java | 64 +- .../pmd/lang/apex/rule/ApexXPathRule.java | 46 +- .../AvoidDeeplyNestedIfStmtsRule.java | 94 +- .../ExcessiveParameterListRule.java | 56 +- .../StdCyclomaticComplexityRule.java | 428 +- .../rule/complexity/TooManyFieldsRule.java | 154 +- .../style/ClassNamingConventionsRule.java | 66 +- .../style/MethodNamingConventionsRule.java | 108 +- ...ethodWithSameNameAsEnclosingClassRule.java | 76 +- .../style/VariableNamingConventionsRule.java | 442 +- .../pmd/lang/apex/LanguageVersionTest.java | 54 +- pmd-core/etc/grammar/dummy.jjt | 44 +- .../net/sourceforge/pmd/PMDConfiguration.java | 1200 +- .../net/sourceforge/pmd/RulePriority.java | 194 +- .../net/sourceforge/pmd/RuleSetReference.java | 104 +- .../sourceforge/pmd/RuleSetReferenceId.java | 898 +- .../net/sourceforge/pmd/RuleSetWriter.java | 824 +- .../pmd/RuleViolationComparator.java | 124 +- .../sourceforge/pmd/ant/SourceLanguage.java | 70 +- .../sourceforge/pmd/cpd/AbstractLanguage.java | 116 +- .../sourceforge/pmd/dcd/ClassLoaderUtil.java | 344 +- .../java/net/sourceforge/pmd/dcd/DCD.java | 354 +- .../sourceforge/pmd/dcd/DumpNodeVisitor.java | 212 +- .../sourceforge/pmd/dcd/UsageNodeVisitor.java | 466 +- .../sourceforge/pmd/dcd/asm/PrintVisitor.java | 78 +- .../pmd/dcd/asm/TypeSignatureVisitor.java | 614 +- .../sourceforge/pmd/dcd/graph/ClassNode.java | 256 +- .../pmd/dcd/graph/ClassNodeComparator.java | 64 +- .../pmd/dcd/graph/ConstructorNode.java | 200 +- .../sourceforge/pmd/dcd/graph/FieldNode.java | 112 +- .../sourceforge/pmd/dcd/graph/MemberNode.java | 286 +- .../pmd/dcd/graph/MemberNodeComparator.java | 88 +- .../sourceforge/pmd/dcd/graph/MethodNode.java | 156 +- .../pmd/dcd/graph/NodeVisitor.java | 70 +- .../pmd/dcd/graph/NodeVisitorAcceptor.java | 26 +- .../pmd/dcd/graph/NodeVisitorAdapter.java | 180 +- .../sourceforge/pmd/dcd/graph/UsageGraph.java | 268 +- .../pmd/dcd/graph/UsageGraphBuilder.java | 978 +- .../lang/AbstractLanguageVersionHandler.java | 124 +- .../sourceforge/pmd/lang/AbstractParser.java | 68 +- .../sourceforge/pmd/lang/DataFlowHandler.java | 58 +- .../pmd/lang/LanguageVersionDiscoverer.java | 232 +- .../pmd/lang/LanguageVersionHandler.java | 182 +- .../sourceforge/pmd/lang/ParserOptions.java | 80 +- .../sourceforge/pmd/lang/TokenManager.java | 28 +- .../sourceforge/pmd/lang/XPathHandler.java | 102 +- .../pmd/lang/ast/AbstractNode.java | 926 +- .../pmd/lang/ast/AbstractTokenManager.java | 76 +- .../net/sourceforge/pmd/lang/ast/Node.java | 440 +- .../pmd/lang/ast/ParseException.java | 48 +- .../sourceforge/pmd/lang/ast/RootNode.java | 24 +- .../ast/xpath/AbstractASTXPathHandler.java | 48 +- .../pmd/lang/ast/xpath/AttributeNode.java | 32 +- .../ast/xpath/saxon/AbstractNodeInfo.java | 762 +- .../xpath/saxon/AttributeAxisIterator.java | 100 +- .../lang/ast/xpath/saxon/AttributeNode.java | 166 +- .../lang/ast/xpath/saxon/DocumentNode.java | 202 +- .../pmd/lang/ast/xpath/saxon/ElementNode.java | 306 +- .../pmd/lang/ast/xpath/saxon/IdGenerator.java | 32 +- .../pmd/lang/dfa/AbstractDataFlowNode.java | 310 +- .../pmd/lang/rule/AbstractDelegateRule.java | 552 +- .../rule/AbstractRuleViolationFactory.java | 106 +- .../pmd/lang/rule/ImmutableLanguage.java | 26 +- .../sourceforge/pmd/lang/rule/MockRule.java | 90 +- .../lang/rule/ParametricRuleViolation.java | 370 +- .../pmd/lang/rule/RuleReference.java | 674 +- .../pmd/lang/rule/RuleViolationFactory.java | 68 +- .../AbstractEnumeratedProperty.java | 240 +- .../rule/properties/BooleanMultiProperty.java | 184 +- .../properties/CharacterMultiProperty.java | 188 +- .../rule/properties/DoubleMultiProperty.java | 164 +- .../properties/EnumeratedMultiProperty.java | 268 +- .../rule/properties/FloatMultiProperty.java | 176 +- .../rule/properties/IntegerMultiProperty.java | 166 +- .../rule/properties/LongMultiProperty.java | 170 +- .../lang/rule/properties/LongProperty.java | 204 +- .../rule/properties/MethodMultiProperty.java | 306 +- .../properties/PropertyDescriptorFactory.java | 254 +- .../properties/PropertyDescriptorWrapper.java | 266 +- .../rule/properties/StringMultiProperty.java | 278 +- .../rule/properties/TypeMultiProperty.java | 288 +- .../pmd/lang/rule/stat/StatisticalRule.java | 62 +- .../lang/rule/stat/StatisticalRuleHelper.java | 294 +- .../rule/xpath/AbstractXPathRuleQuery.java | 184 +- .../lang/rule/xpath/JaxenXPathRuleQuery.java | 488 +- .../lang/rule/xpath/SaxonXPathRuleQuery.java | 372 +- .../pmd/lang/rule/xpath/XPathRuleQuery.java | 164 +- .../pmd/lang/xpath/Initializer.java | 130 +- .../pmd/lang/xpath/PMDFunctions.java | 70 +- .../AbstractAccumulatingRenderer.java | 130 +- .../pmd/renderers/RendererFactory.java | 304 +- .../pmd/util/CompoundIterator.java | 156 +- .../net/sourceforge/pmd/util/FileFinder.java | 92 +- .../pmd/util/database/DBMSMetadata.java | 1070 +- .../util/filter/AbstractCompoundFilter.java | 122 +- .../util/filter/AbstractDelegateFilter.java | 86 +- .../pmd/util/filter/AndFilter.java | 78 +- .../pmd/util/filter/DirectoryFilter.java | 54 +- .../pmd/util/filter/FileExtensionFilter.java | 94 +- .../sourceforge/pmd/util/filter/Filter.java | 30 +- .../sourceforge/pmd/util/filter/Filters.java | 474 +- .../pmd/util/filter/NotFilter.java | 62 +- .../sourceforge/pmd/util/filter/OrFilter.java | 78 +- .../pmd/util/filter/RegexStringFilter.java | 188 +- .../rulesets/internal/all-ecmascript.xml | 24 +- .../resources/rulesets/internal/all-java.xml | 70 +- .../rulesets/internal/dogfood-goal.xml | 212 +- .../main/resources/rulesets/releases/41.xml | 6 +- .../sourceforge/pmd/ConfigurationTest.java | 402 +- .../sourceforge/pmd/RuleReferenceTest.java | 374 +- .../pmd/RuleSetReferenceIdTest.java | 644 +- .../pmd/RuleViolationComparatorTest.java | 178 +- .../lang/dfa/report/ViolationNodeTest.java | 230 +- .../pmd/util/CompoundListTest.java | 184 +- .../util/filter/RegexStringFilterTest.java | 228 +- .../net/sourceforge/pmd/xml/j2ee.xml | 766 +- .../pmd/lang/cpp/ContinuationReader.java | 172 +- .../sourceforge/pmd/lang/cpp/CppHandler.java | 52 +- .../sourceforge/pmd/lang/cpp/CppParser.java | 104 +- .../pmd/lang/cpp/CppTokenManager.java | 74 +- .../sourceforge/pmd/LanguageVersionTest.java | 66 +- .../pmd/lang/cpp/ContinuationReaderTest.java | 112 +- pmd-dist/src/main/scripts/bgastviewer.bat | 12 +- pmd-dist/src/main/scripts/cpd.bat | 12 +- pmd-dist/src/main/scripts/cpdgui.bat | 12 +- pmd-dist/src/main/scripts/designer.bat | 12 +- pmd-dist/src/main/scripts/pmd.bat | 12 +- .../sourceforge/pmd/LanguageVersionTest.java | 66 +- .../pmd/lang/java/AbstractJavaHandler.java | 224 +- .../pmd/lang/java/AbstractJavaParser.java | 126 +- .../pmd/lang/java/JavaDataFlowHandler.java | 46 +- .../pmd/lang/java/JavaTokenManager.java | 60 +- .../ast/ASTAnnotationMethodDeclaration.java | 52 +- .../lang/java/ast/AbstractJavaAccessNode.java | 280 +- .../java/ast/AbstractJavaAccessTypeNode.java | 56 +- .../lang/java/ast/AbstractJavaTypeNode.java | 68 +- .../pmd/lang/java/ast/DumpFacade.java | 510 +- .../pmd/lang/java/dfa/JavaDataFlowNode.java | 60 +- .../rule/AbstractStatisticalJavaRule.java | 64 +- .../pmd/lang/java/rule/JavaRuleViolation.java | 296 +- .../java/rule/JavaRuleViolationFactory.java | 66 +- ...oidBranchingStatementAsLastInLoopRule.java | 218 +- .../AvoidMultipleUnaryOperatorsRule.java | 144 +- .../java/rule/basic/CheckSkipResultRule.java | 122 +- .../rule/basic/DoubleCheckedLockingRule.java | 548 +- .../OverrideBothEqualsAndHashcodeRule.java | 192 +- .../codesize/CyclomaticComplexityRule.java | 162 +- .../codesize/ExcessiveClassLengthRule.java | 38 +- .../codesize/ExcessiveMethodLengthRule.java | 38 +- .../codesize/ExcessiveParameterListRule.java | 54 +- .../codesize/ExcessivePublicCountRule.java | 134 +- .../ModifiedCyclomaticComplexityRule.java | 58 +- .../rule/codesize/NPathComplexityRule.java | 530 +- .../codesize/StdCyclomaticComplexityRule.java | 492 +- .../java/rule/codesize/TooManyFieldsRule.java | 142 +- .../AssignmentInOperandRule.java | 154 +- .../DataflowAnomalyAnalysisRule.java | 354 +- .../rule/controversial/DontImportSunRule.java | 40 +- .../SuspiciousOctalEscapeRule.java | 180 +- .../coupling/CouplingBetweenObjectsRule.java | 348 +- .../rule/coupling/ExcessiveImportsRule.java | 76 +- .../java/rule/coupling/LooseCouplingRule.java | 116 +- .../coupling/LoosePackageCouplingRule.java | 292 +- .../design/AccessorClassGenerationRule.java | 638 +- .../design/AvoidDeeplyNestedIfStmtsRule.java | 82 +- .../AvoidReassigningParametersRule.java | 104 +- .../java/rule/design/CloseResourceRule.java | 752 +- ...ConstructorCallsOverridableMethodRule.java | 2160 +-- .../rule/design/IdempotentOperationsRule.java | 170 +- .../design/SimplifyBooleanReturnsRule.java | 536 +- .../finalizers/AvoidCallingFinalizeRule.java | 136 +- .../BeanMembersShouldSerializeRule.java | 238 +- .../JUnitTestsShouldIncludeAssertRule.java | 196 +- .../rule/logging/MoreThanOneLoggerRule.java | 218 +- .../AvoidFieldNameMatchingMethodNameRule.java | 110 +- .../AvoidFieldNameMatchingTypeNameRule.java | 54 +- .../naming/ClassNamingConventionsRule.java | 36 +- .../naming/MethodNamingConventionsRule.java | 132 +- ...ethodWithSameNameAsEnclosingClassRule.java | 50 +- .../naming/VariableNamingConventionsRule.java | 492 +- .../PrematureDeclarationRule.java | 468 +- .../RedundantFieldInitializerRule.java | 356 +- .../ExceptionAsFlowControlRule.java | 94 +- .../SignatureDeclareThrowsExceptionRule.java | 232 +- .../UnnecessaryConversionTemporaryRule.java | 124 +- .../UselessOverridingMethodRule.java | 518 +- .../unusedcode/UnusedFormalParameterRule.java | 254 +- .../unusedcode/UnusedLocalVariableRule.java | 92 +- .../rule/unusedcode/UnusedModifierRule.java | 150 +- .../unusedcode/UnusedPrivateFieldRule.java | 248 +- .../unusedcode/UnusedPrivateMethodRule.java | 220 +- .../lang/java/typeresolution/TypeHelper.java | 130 +- .../pmd/lang/java/xpath/JavaFunctions.java | 58 +- .../pmd/lang/java/xpath/TypeOfFunction.java | 174 +- .../pmd/LanguageVersionDiscovererTest.java | 120 +- .../sourceforge/pmd/LanguageVersionTest.java | 82 +- .../lang/java/rule/JavaRuleViolationTest.java | 222 +- .../testdata/AnonymousInnerClass.java | 44 +- .../testdata/ArrayListFound.java | 22 +- .../testdata/DefaultJavaLangImport.java | 24 +- .../testdata/ExtraTopLevelClass.java | 22 +- .../typeresolution/testdata/InnerClass.java | 26 +- .../pmd/typeresolution/testdata/Literals.java | 86 +- .../typeresolution/testdata/Operators.java | 140 +- .../typeresolution/testdata/Promotion.java | 162 +- .../AvoidBranchingStatementAsLastInLoop.xml | 436 +- .../java/rule/basic/xml/AvoidThreadGroup.xml | 200 +- .../xml/UnnecessaryFullyQualifiedName.xml | 780 +- .../xml/JUnitTestContainsTooManyAsserts.xml | 264 +- .../UseAssertTrueInsteadOfAssertEquals.xml | 190 +- .../xml/RedundantFieldInitializer.xml | 2630 ++-- .../xml/AvoidLosingExceptionInformation.xml | 200 +- .../lang/ecmascript/Ecmascript3Handler.java | 120 +- .../lang/ecmascript/Ecmascript3Parser.java | 90 +- .../ecmascript/EcmascriptParserOptions.java | 258 +- .../ecmascript/ast/ASTArrayComprehension.java | 80 +- .../ast/ASTArrayComprehensionLoop.java | 58 +- .../lang/ecmascript/ast/ASTArrayLiteral.java | 70 +- .../lang/ecmascript/ast/ASTAssignment.java | 42 +- .../pmd/lang/ecmascript/ast/ASTAstRoot.java | 58 +- .../pmd/lang/ecmascript/ast/ASTBlock.java | 42 +- .../ecmascript/ast/ASTBreakStatement.java | 60 +- .../lang/ecmascript/ast/ASTCatchClause.java | 74 +- .../pmd/lang/ecmascript/ast/ASTComment.java | 50 +- .../ast/ASTConditionalExpression.java | 66 +- .../ecmascript/ast/ASTContinueStatement.java | 60 +- .../pmd/lang/ecmascript/ast/ASTDoLoop.java | 58 +- .../lang/ecmascript/ast/ASTElementGet.java | 70 +- .../ecmascript/ast/ASTEmptyExpression.java | 42 +- .../ecmascript/ast/ASTEmptyStatement.java | 36 +- .../ast/ASTExpressionStatement.java | 52 +- .../pmd/lang/ecmascript/ast/ASTForInLoop.java | 72 +- .../pmd/lang/ecmascript/ast/ASTForLoop.java | 72 +- .../lang/ecmascript/ast/ASTFunctionCall.java | 72 +- .../lang/ecmascript/ast/ASTFunctionNode.java | 130 +- .../lang/ecmascript/ast/ASTIfStatement.java | 72 +- .../ecmascript/ast/ASTInfixExpression.java | 40 +- .../ecmascript/ast/ASTKeywordLiteral.java | 78 +- .../pmd/lang/ecmascript/ast/ASTLabel.java | 42 +- .../ecmascript/ast/ASTLabeledStatement.java | 64 +- .../pmd/lang/ecmascript/ast/ASTLetNode.java | 72 +- .../pmd/lang/ecmascript/ast/ASTName.java | 170 +- .../lang/ecmascript/ast/ASTNewExpression.java | 88 +- .../lang/ecmascript/ast/ASTNumberLiteral.java | 62 +- .../lang/ecmascript/ast/ASTObjectLiteral.java | 78 +- .../ecmascript/ast/ASTObjectProperty.java | 56 +- .../ast/ASTParenthesizedExpression.java | 40 +- .../lang/ecmascript/ast/ASTPropertyGet.java | 42 +- .../lang/ecmascript/ast/ASTRegExpLiteral.java | 50 +- .../ecmascript/ast/ASTReturnStatement.java | 48 +- .../pmd/lang/ecmascript/ast/ASTScope.java | 40 +- .../lang/ecmascript/ast/ASTStringLiteral.java | 66 +- .../lang/ecmascript/ast/ASTSwitchCase.java | 90 +- .../ecmascript/ast/ASTSwitchStatement.java | 64 +- .../ecmascript/ast/ASTThrowStatement.java | 40 +- .../lang/ecmascript/ast/ASTTryStatement.java | 120 +- .../ecmascript/ast/ASTUnaryExpression.java | 80 +- .../ast/ASTVariableDeclaration.java | 76 +- .../ast/ASTVariableInitializer.java | 72 +- .../pmd/lang/ecmascript/ast/ASTWhileLoop.java | 56 +- .../lang/ecmascript/ast/ASTWithStatement.java | 56 +- .../lang/ecmascript/ast/ASTXmlDotQuery.java | 40 +- .../lang/ecmascript/ast/ASTXmlExpression.java | 56 +- .../lang/ecmascript/ast/ASTXmlMemberGet.java | 40 +- .../pmd/lang/ecmascript/ast/ASTXmlString.java | 42 +- .../ast/AbstractEcmascriptNode.java | 150 +- .../ast/AbstractInfixEcmascriptNode.java | 70 +- .../ecmascript/ast/DestructuringNode.java | 18 +- .../pmd/lang/ecmascript/ast/DumpFacade.java | 412 +- .../lang/ecmascript/ast/EcmascriptNode.java | 76 +- .../lang/ecmascript/ast/EcmascriptParser.java | 178 +- .../ast/EcmascriptParserVisitor.java | 214 +- .../ast/EcmascriptParserVisitorAdapter.java | 418 +- .../ecmascript/ast/EcmascriptTreeBuilder.java | 512 +- .../ecmascript/ast/TrailingCommaNode.java | 22 +- .../rule/AbstractEcmascriptRule.java | 616 +- .../rule/EcmascriptRuleChainVisitor.java | 90 +- .../rule/EcmascriptRuleViolationFactory.java | 64 +- .../ecmascript/rule/EcmascriptXPathRule.java | 64 +- .../rule/basic/ConsistentReturnRule.java | 78 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../EcmascriptParserOptionsTest.java | 228 +- .../ecmascript/rule/basic/BasicRulesTest.java | 50 +- .../controversial/ControversialRulesTest.java | 34 +- .../rule/basic/xml/AssignmentInOperand.xml | 310 +- .../rule/basic/xml/AvoidTrailingComma.xml | 258 +- .../rule/basic/xml/ConsistentReturn.xml | 178 +- .../rule/basic/xml/EqualComparison.xml | 74 +- .../rule/basic/xml/GlobalVariable.xml | 80 +- .../basic/xml/InnaccurateNumericLiteral.xml | 126 +- .../rule/basic/xml/ScopeForInVariable.xml | 198 +- .../rule/basic/xml/UnreachableCode.xml | 270 +- .../rule/basic/xml/UseBaseWithParseInt.xml | 46 +- .../controversial/xml/AvoidWithStatement.xml | 30 +- .../rule/unnecessary/xml/NoElseReturn.xml | 90 +- .../rule/unnecessary/xml/UnnecessaryBlock.xml | 452 +- .../xml/UnnecessaryParentheses.xml | 86 +- .../sourceforge/pmd/lang/jsp/JspHandler.java | 114 +- .../pmd/lang/jsp/JspTokenManager.java | 60 +- .../pmd/lang/jsp/ast/ASTHtmlScript.java | 46 +- .../pmd/lang/jsp/ast/AbstractJspNode.java | 124 +- .../pmd/lang/jsp/ast/DumpFacade.java | 208 +- .../sourceforge/pmd/lang/jsp/ast/JspNode.java | 38 +- .../pmd/lang/jsp/rule/AbstractJspRule.java | 320 +- .../jsp/rule/JspRuleViolationFactory.java | 64 +- .../pmd/LanguageVersionDiscovererTest.java | 62 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../jsp/rule/basicjsf/BasicJsfRulesTest.java | 34 +- .../jsp/rule/basic/xml/NoInlineScript.xml | 104 +- pmd-matlab/etc/grammar/matlab.jj | 334 +- pmd-matlab/src/main/ant/alljavacc.xml | 90 +- .../sourceforge/pmd/cpd/MatlabLanguage.java | 38 +- .../sourceforge/pmd/cpd/MatlabTokenizer.java | 104 +- .../pmd/lang/matlab/MatlabHandler.java | 52 +- .../pmd/lang/matlab/MatlabLanguageModule.java | 54 +- .../pmd/lang/matlab/MatlabParser.java | 104 +- .../pmd/lang/matlab/MatlabTokenManager.java | 74 +- pmd-matlab/src/site/markdown/index.md | 6 +- pmd-matlab/src/site/site.xml | 24 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../pmd/cpd/MatlabTokenizerTest.java | 72 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- pmd-plsql/etc/grammar/PldocAST.jjt | 10986 ++++++++-------- .../pmd/lang/plsql/PLSQLHandler.java | 202 +- .../pmd/lang/plsql/ast/DumpFacade.java | 206 +- .../pmd/lang/plsql/dfa/PLSQLDataFlowNode.java | 70 +- .../rule/AbstractStatisticalPLSQLRule.java | 64 +- .../codesize/CyclomaticComplexityRule.java | 810 +- .../codesize/ExcessiveMethodLengthRule.java | 38 +- .../codesize/ExcessiveObjectLengthRule.java | 38 +- .../ExcessivePackageBodyLengthRule.java | 38 +- ...cessivePackageSpecificationLengthRule.java | 38 +- .../codesize/ExcessiveParameterListRule.java | 54 +- .../codesize/ExcessiveTypeLengthRule.java | 38 +- .../rule/codesize/NPathComplexityRule.java | 882 +- .../rule/codesize/TooManyFieldsRule.java | 186 +- .../pmd/LanguageVersionDiscovererTest.java | 64 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../sourceforge/pmd/cpd/PythonLanguage.java | 38 +- .../sourceforge/pmd/cpd/PythonTokenizer.java | 104 +- .../pmd/lang/python/PythonHandler.java | 52 +- .../pmd/lang/python/PythonLanguageModule.java | 54 +- .../pmd/lang/python/PythonParser.java | 104 +- .../pmd/lang/python/PythonTokenManager.java | 74 +- .../pmd/LanguageVersionDiscovererTest.java | 64 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../pmd/cpd/PythonTokenizerTest.java | 72 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../pmd/AbstractLanguageVersionTest.java | 276 +- .../pmd/lang/ParserOptionsTest.java | 188 +- .../lang/vm/ast/VmParserVisitorAdapter.java | 512 +- .../pmd/lang/vm/rule/AbstractVmRule.java | 666 +- .../pmd/lang/vm/rule/VmRuleChainVisitor.java | 96 +- .../sourceforge/pmd/LanguageVersionTest.java | 54 +- .../sourceforge/pmd/lang/xml/XmlHandler.java | 132 +- .../sourceforge/pmd/lang/xml/XmlParser.java | 84 +- .../pmd/lang/xml/ast/DumpFacade.java | 186 +- .../sourceforge/pmd/lang/xml/ast/XmlNode.java | 52 +- .../pmd/lang/xml/rule/AbstractDomXmlRule.java | 260 +- .../pmd/lang/xml/rule/AbstractXmlRule.java | 158 +- .../lang/xml/rule/XmlRuleChainVisitor.java | 78 +- .../xml/rule/XmlRuleViolationFactory.java | 64 +- .../pmd/lang/xml/rule/XmlXPathRule.java | 78 +- .../src/main/resources/rulesets/pom/basic.xml | 174 +- .../src/main/resources/rulesets/xml/basic.xml | 70 +- .../src/main/resources/rulesets/xsl/xpath.xml | 164 +- .../sourceforge/pmd/LanguageVersionTest.java | 74 +- .../lang/pom/rule/basic/BasicRulesTest.java | 34 +- .../pmd/lang/xml/XmlParserOptionsTest.java | 336 +- .../lang/xml/rule/AbstractXmlRuleTest.java | 124 +- .../lang/xml/rule/basic/BasicRulesTest.java | 34 +- .../lang/xsl/rule/xpath/XPathRulesTest.java | 36 +- .../pom/rule/basic/xml/InvalidDepencyType.xml | 102 +- .../xml/ProjectVersionAsDependencyVersion.xml | 90 +- .../rule/basic/xml/MistypedCDATASection.xml | 140 +- .../rule/xpath/xml/AvoidAxisNavigation.xml | 80 +- .../lang/xsl/rule/xpath/xml/UseConcatOnce.xml | 50 +- .../markdown/customizing/rule-guidelines.md | 8 +- 391 files changed, 42076 insertions(+), 42063 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..70e92072fd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +* text=auto +*.java text +*.xml text +*.jjt text +*.jj text +*.g4 text +*.md text +*.sh text eol=lf +*.bat text eol=crlf +*.png -text +*.jpg -text +*.svgz -text +*.jar -text diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java index 2719548c2b..7a3df258f2 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java @@ -1,57 +1,57 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex; - -import java.io.Writer; - -import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; -import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.VisitorStarter; -import net.sourceforge.pmd.lang.XPathHandler; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.ast.DumpFacade; -import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; - -import net.sf.saxon.sxpath.IndependentContext; - -public class ApexHandler extends AbstractLanguageVersionHandler { - - @Override - public XPathHandler getXPathHandler() { - return new AbstractASTXPathHandler() { - public void initialize() { - } - - public void initialize(IndependentContext context) { - } - }; - } - - public RuleViolationFactory getRuleViolationFactory() { - return ApexRuleViolationFactory.INSTANCE; - } - - @Override - public ParserOptions getDefaultParserOptions() { - return new ApexParserOptions(); - } - - public Parser getParser(ParserOptions parserOptions) { - return new ApexParser(parserOptions); - } - - @Override - public VisitorStarter getDumpFacade(Writer writer, String prefix, boolean recurse) { - return new VisitorStarter() { - public void start(Node rootNode) { - new DumpFacade().initializeWith(writer, prefix, recurse, (ApexNode) rootNode); - } - }; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex; + +import java.io.Writer; + +import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.VisitorStarter; +import net.sourceforge.pmd.lang.XPathHandler; +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.apex.ast.DumpFacade; +import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +import net.sf.saxon.sxpath.IndependentContext; + +public class ApexHandler extends AbstractLanguageVersionHandler { + + @Override + public XPathHandler getXPathHandler() { + return new AbstractASTXPathHandler() { + public void initialize() { + } + + public void initialize(IndependentContext context) { + } + }; + } + + public RuleViolationFactory getRuleViolationFactory() { + return ApexRuleViolationFactory.INSTANCE; + } + + @Override + public ParserOptions getDefaultParserOptions() { + return new ApexParserOptions(); + } + + public Parser getParser(ParserOptions parserOptions) { + return new ApexParser(parserOptions); + } + + @Override + public VisitorStarter getDumpFacade(Writer writer, String prefix, boolean recurse) { + return new VisitorStarter() { + public void start(Node rootNode) { + new DumpFacade().initializeWith(writer, prefix, recurse, (ApexNode) rootNode); + } + }; + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParser.java index c3e8c02ffd..63e0d529a7 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParser.java @@ -1,43 +1,43 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex; - -import java.io.Reader; -import java.util.Map; - -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.ParseException; - -/** - * Adapter for the Apex jorje parser - */ -public class ApexParser extends AbstractParser { - private net.sourceforge.pmd.lang.apex.ast.ApexParser apexParser; - - public ApexParser(ParserOptions parserOptions) { - super(parserOptions); - apexParser = new net.sourceforge.pmd.lang.apex.ast.ApexParser((ApexParserOptions) parserOptions); - } - - @Override - public TokenManager createTokenManager(Reader source) { - return null; - } - - public boolean canParse() { - return true; - } - - public Node parse(String fileName, Reader source) throws ParseException { - return apexParser.parse(source); - } - - public Map getSuppressMap() { - return apexParser.getSuppressMap(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex; + +import java.io.Reader; +import java.util.Map; + +import net.sourceforge.pmd.lang.AbstractParser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.ParseException; + +/** + * Adapter for the Apex jorje parser + */ +public class ApexParser extends AbstractParser { + private net.sourceforge.pmd.lang.apex.ast.ApexParser apexParser; + + public ApexParser(ParserOptions parserOptions) { + super(parserOptions); + apexParser = new net.sourceforge.pmd.lang.apex.ast.ApexParser((ApexParserOptions) parserOptions); + } + + @Override + public TokenManager createTokenManager(Reader source) { + return null; + } + + public boolean canParse() { + return true; + } + + public Node parse(String fileName, Reader source) throws ParseException { + return apexParser.parse(source); + } + + public Map getSuppressMap() { + return apexParser.getSuppressMap(); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParserOptions.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParserOptions.java index 785328f0a8..7f81184afa 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParserOptions.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexParserOptions.java @@ -1,33 +1,33 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex; - -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.util.StringUtil; - -public class ApexParserOptions extends ParserOptions { - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + (1237); - result = prime * result + (1237); - result = prime * result; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final ApexParserOptions that = (ApexParserOptions) obj; - return StringUtil.isSame(this.suppressMarker, that.suppressMarker, false, false, false); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex; + +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.util.StringUtil; + +public class ApexParserOptions extends ParserOptions { + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (1237); + result = prime * result + (1237); + result = prime * result; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ApexParserOptions that = (ApexParserOptions) obj; + return StringUtil.isSame(this.suppressMarker, that.suppressMarker, false, false, false); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java index 0fbf63fea6..3c729b2708 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java @@ -1,141 +1,141 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -import net.sourceforge.pmd.lang.ast.AbstractNode; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.SourceCodePositioner; - -import apex.jorje.data.Loc; -import apex.jorje.data.Loc.RealLoc; -import apex.jorje.semantic.ast.AstNode; -import apex.jorje.semantic.exception.UnexpectedCodePathException; - -public abstract class AbstractApexNode extends AbstractNode implements ApexNode { - - protected final T node; - - public AbstractApexNode(T node) { - super(node.getClass().hashCode()); - this.node = node; - } - - void calculateLineNumbers(SourceCodePositioner positioner) { - if (!hasRealLoc()) { - return; - } - - RealLoc loc = (RealLoc) node.getLoc(); - int startOffset = loc.startIndex; - int endOffset = loc.endIndex; - // end column will be interpreted as inclusive, while endOffset/endIndex - // is exclusive - endOffset -= 1; - - this.beginLine = positioner.lineNumberFromOffset(startOffset); - this.beginColumn = positioner.columnFromOffset(this.beginLine, startOffset); - this.endLine = positioner.lineNumberFromOffset(endOffset); - this.endColumn = positioner.columnFromOffset(this.endLine, endOffset); - - if (this.endColumn < 0) { - this.endColumn = 0; - } - } - - @Override - public int getBeginLine() { - if (this.beginLine > 0) { - return this.beginLine; - } - Node parent = jjtGetParent(); - if (parent != null) { - return parent.getBeginLine(); - } - throw new RuntimeException("Unable to determine beginning line of Node."); - } - - @Override - public int getBeginColumn() { - if (this.beginColumn > 0) { - return this.beginColumn; - } - Node parent = jjtGetParent(); - if (parent != null) { - return parent.getBeginColumn(); - } - throw new RuntimeException("Unable to determine beginning column of Node."); - } - - @Override - public int getEndLine() { - if (this.endLine > 0) { - return this.endLine; - } - Node parent = jjtGetParent(); - if (parent != null) { - return parent.getEndLine(); - } - throw new RuntimeException("Unable to determine ending line of Node."); - } - - @Override - public int getEndColumn() { - if (this.endColumn > 0) { - return this.endColumn; - } - Node parent = jjtGetParent(); - if (parent != null) { - return parent.getEndColumn(); - } - throw new RuntimeException("Unable to determine ending column of Node."); - } - - /** - * Accept the visitor. * - */ - public Object childrenAccept(ApexParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - @SuppressWarnings("unchecked") - // we know that the children here are all ApexNodes - ApexNode apexNode = (ApexNode) children[i]; - apexNode.jjtAccept(visitor, data); - } - } - return data; - } - - public T getNode() { - return node; - } - - protected boolean hasRealLoc() { - try { - Loc loc = node.getLoc(); - return loc instanceof RealLoc; - } catch (UnexpectedCodePathException e) { - return false; - } catch (IndexOutOfBoundsException e) { - // bug in apex-jorje? happens on some ReferenceExpression nodes - return false; - } catch (NullPointerException e) { - // bug in apex-jorje? - return false; - } - } - - @Override - public String toString() { - return this.getClass().getSimpleName().replaceFirst("^AST", ""); - } - - public String getLocation() { - if (hasRealLoc()) { - return String.valueOf(node.getLoc()); - } else { - return "no location"; - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.SourceCodePositioner; + +import apex.jorje.data.Loc; +import apex.jorje.data.Loc.RealLoc; +import apex.jorje.semantic.ast.AstNode; +import apex.jorje.semantic.exception.UnexpectedCodePathException; + +public abstract class AbstractApexNode extends AbstractNode implements ApexNode { + + protected final T node; + + public AbstractApexNode(T node) { + super(node.getClass().hashCode()); + this.node = node; + } + + void calculateLineNumbers(SourceCodePositioner positioner) { + if (!hasRealLoc()) { + return; + } + + RealLoc loc = (RealLoc) node.getLoc(); + int startOffset = loc.startIndex; + int endOffset = loc.endIndex; + // end column will be interpreted as inclusive, while endOffset/endIndex + // is exclusive + endOffset -= 1; + + this.beginLine = positioner.lineNumberFromOffset(startOffset); + this.beginColumn = positioner.columnFromOffset(this.beginLine, startOffset); + this.endLine = positioner.lineNumberFromOffset(endOffset); + this.endColumn = positioner.columnFromOffset(this.endLine, endOffset); + + if (this.endColumn < 0) { + this.endColumn = 0; + } + } + + @Override + public int getBeginLine() { + if (this.beginLine > 0) { + return this.beginLine; + } + Node parent = jjtGetParent(); + if (parent != null) { + return parent.getBeginLine(); + } + throw new RuntimeException("Unable to determine beginning line of Node."); + } + + @Override + public int getBeginColumn() { + if (this.beginColumn > 0) { + return this.beginColumn; + } + Node parent = jjtGetParent(); + if (parent != null) { + return parent.getBeginColumn(); + } + throw new RuntimeException("Unable to determine beginning column of Node."); + } + + @Override + public int getEndLine() { + if (this.endLine > 0) { + return this.endLine; + } + Node parent = jjtGetParent(); + if (parent != null) { + return parent.getEndLine(); + } + throw new RuntimeException("Unable to determine ending line of Node."); + } + + @Override + public int getEndColumn() { + if (this.endColumn > 0) { + return this.endColumn; + } + Node parent = jjtGetParent(); + if (parent != null) { + return parent.getEndColumn(); + } + throw new RuntimeException("Unable to determine ending column of Node."); + } + + /** + * Accept the visitor. * + */ + public Object childrenAccept(ApexParserVisitor visitor, Object data) { + if (children != null) { + for (int i = 0; i < children.length; ++i) { + @SuppressWarnings("unchecked") + // we know that the children here are all ApexNodes + ApexNode apexNode = (ApexNode) children[i]; + apexNode.jjtAccept(visitor, data); + } + } + return data; + } + + public T getNode() { + return node; + } + + protected boolean hasRealLoc() { + try { + Loc loc = node.getLoc(); + return loc instanceof RealLoc; + } catch (UnexpectedCodePathException e) { + return false; + } catch (IndexOutOfBoundsException e) { + // bug in apex-jorje? happens on some ReferenceExpression nodes + return false; + } catch (NullPointerException e) { + // bug in apex-jorje? + return false; + } + } + + @Override + public String toString() { + return this.getClass().getSimpleName().replaceFirst("^AST", ""); + } + + public String getLocation() { + if (hasRealLoc()) { + return String.valueOf(node.getLoc()); + } else { + return "no location"; + } + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java index 1bdfea6ce2..ee8971d798 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java @@ -1,27 +1,27 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -import net.sourceforge.pmd.lang.ast.Node; - -import apex.jorje.semantic.ast.AstNode; - -public interface ApexNode extends Node { - - /** - * Accept the visitor. * - */ - Object jjtAccept(ApexParserVisitor visitor, Object data); - - /** - * Accept the visitor. * - */ - Object childrenAccept(ApexParserVisitor visitor, Object data); - - /** - * Get the underlying AST node. - */ - T getNode(); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import net.sourceforge.pmd.lang.ast.Node; + +import apex.jorje.semantic.ast.AstNode; + +public interface ApexNode extends Node { + + /** + * Accept the visitor. * + */ + Object jjtAccept(ApexParserVisitor visitor, Object data); + + /** + * Accept the visitor. * + */ + Object childrenAccept(ApexParserVisitor visitor, Object data); + + /** + * Get the underlying AST node. + */ + T getNode(); +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index aeef41c133..8a4f4c3aa8 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -1,97 +1,97 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -import java.io.IOException; -import java.io.Reader; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.io.IOUtils; - -import net.sourceforge.pmd.lang.apex.ApexParserOptions; -import net.sourceforge.pmd.lang.ast.ParseException; - -import apex.jorje.semantic.ast.compilation.Compilation; -import apex.jorje.semantic.ast.compilation.UserClass; -import apex.jorje.semantic.ast.compilation.UserEnum; -import apex.jorje.semantic.ast.compilation.UserInterface; -import apex.jorje.semantic.ast.compilation.UserTrigger; -import apex.jorje.semantic.ast.visitor.AdditionalPassScope; -import apex.jorje.semantic.ast.visitor.AstVisitor; - -public class ApexParser { - protected final ApexParserOptions parserOptions; - - private Map suppressMap; - private String suppressMarker = "NOPMD"; - - public ApexParser(ApexParserOptions parserOptions) { - this.parserOptions = parserOptions; - - if (parserOptions.getSuppressMarker() != null) { - suppressMarker = parserOptions.getSuppressMarker(); - } - } - - public Compilation parseApex(final String sourceCode) throws ParseException { - - TopLevelVisitor visitor = new TopLevelVisitor(); - CompilerService.INSTANCE.visitAstFromString(sourceCode, visitor); - - Compilation astRoot = visitor.getTopLevel(); - return astRoot; - } - - public ApexNode parse(final Reader reader) { - try { - final String sourceCode = IOUtils.toString(reader); - final Compilation astRoot = parseApex(sourceCode); - final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode); - suppressMap = new HashMap<>(); - - if (astRoot == null) { - throw new ParseException("Couldn't parse the source - there is not root node - Syntax Error??"); - } - - ApexNode tree = treeBuilder.build(astRoot); - return tree; - } catch (IOException e) { - throw new ParseException(e); - } - } - - public Map getSuppressMap() { - return suppressMap; - } - - private class TopLevelVisitor extends AstVisitor { - Compilation topLevel; - - public Compilation getTopLevel() { - return topLevel; - } - - @Override - public void visitEnd(UserClass node, AdditionalPassScope scope) { - topLevel = node; - } - - @Override - public void visitEnd(UserEnum node, AdditionalPassScope scope) { - topLevel = node; - } - - @Override - public void visitEnd(UserInterface node, AdditionalPassScope scope) { - topLevel = node; - } - - @Override - public void visitEnd(UserTrigger node, AdditionalPassScope scope) { - topLevel = node; - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import java.io.IOException; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.IOUtils; + +import net.sourceforge.pmd.lang.apex.ApexParserOptions; +import net.sourceforge.pmd.lang.ast.ParseException; + +import apex.jorje.semantic.ast.compilation.Compilation; +import apex.jorje.semantic.ast.compilation.UserClass; +import apex.jorje.semantic.ast.compilation.UserEnum; +import apex.jorje.semantic.ast.compilation.UserInterface; +import apex.jorje.semantic.ast.compilation.UserTrigger; +import apex.jorje.semantic.ast.visitor.AdditionalPassScope; +import apex.jorje.semantic.ast.visitor.AstVisitor; + +public class ApexParser { + protected final ApexParserOptions parserOptions; + + private Map suppressMap; + private String suppressMarker = "NOPMD"; + + public ApexParser(ApexParserOptions parserOptions) { + this.parserOptions = parserOptions; + + if (parserOptions.getSuppressMarker() != null) { + suppressMarker = parserOptions.getSuppressMarker(); + } + } + + public Compilation parseApex(final String sourceCode) throws ParseException { + + TopLevelVisitor visitor = new TopLevelVisitor(); + CompilerService.INSTANCE.visitAstFromString(sourceCode, visitor); + + Compilation astRoot = visitor.getTopLevel(); + return astRoot; + } + + public ApexNode parse(final Reader reader) { + try { + final String sourceCode = IOUtils.toString(reader); + final Compilation astRoot = parseApex(sourceCode); + final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode); + suppressMap = new HashMap<>(); + + if (astRoot == null) { + throw new ParseException("Couldn't parse the source - there is not root node - Syntax Error??"); + } + + ApexNode tree = treeBuilder.build(astRoot); + return tree; + } catch (IOException e) { + throw new ParseException(e); + } + } + + public Map getSuppressMap() { + return suppressMap; + } + + private class TopLevelVisitor extends AstVisitor { + Compilation topLevel; + + public Compilation getTopLevel() { + return topLevel; + } + + @Override + public void visitEnd(UserClass node, AdditionalPassScope scope) { + topLevel = node; + } + + @Override + public void visitEnd(UserEnum node, AdditionalPassScope scope) { + topLevel = node; + } + + @Override + public void visitEnd(UserInterface node, AdditionalPassScope scope) { + topLevel = node; + } + + @Override + public void visitEnd(UserTrigger node, AdditionalPassScope scope) { + topLevel = node; + } + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java index f102337b3b..0911bf3cf9 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java @@ -1,169 +1,169 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -public interface ApexParserVisitor { - Object visit(ApexNode node, Object data); - - Object visit(ASTAnnotation node, Object data); - - Object visit(ASTAnonymousClass node, Object data); - - Object visit(ASTArrayLoadExpression node, Object data); - - Object visit(ASTArrayStoreExpression node, Object data); - - Object visit(ASTAssignmentExpression node, Object data); - - Object visit(ASTBinaryExpression node, Object data); - - Object visit(ASTBindExpressions node, Object data); - - Object visit(ASTBlockStatement node, Object data); - - Object visit(ASTBooleanExpression node, Object data); - - Object visit(ASTBreakStatement node, Object data); - - Object visit(ASTBridgeMethodCreator node, Object data); - - Object visit(ASTCatchBlockStatement node, Object data); - - Object visit(ASTClassRefExpression node, Object data); - - Object visit(ASTConstructorPreambleStatement node, Object data); - - Object visit(ASTContinueStatement node, Object data); - - Object visit(ASTDmlDeleteStatement node, Object data); - - Object visit(ASTDmlInsertStatement node, Object data); - - Object visit(ASTDmlMergeStatement node, Object data); - - Object visit(ASTDmlUndeleteStatement node, Object data); - - Object visit(ASTDmlUpdateStatement node, Object data); - - Object visit(ASTDmlUpsertStatement node, Object data); - - Object visit(ASTDoLoopStatement node, Object data); - - Object visit(ASTDottedExpression node, Object data); - - Object visit(ASTExpression node, Object data); - - Object visit(ASTExpressionStatement node, Object data); - - Object visit(ASTField node, Object data); - - Object visit(ASTFieldDeclaration node, Object data); - - Object visit(ASTFieldDeclarationStatements node, Object data); - - Object visit(ASTForEachStatement node, Object data); - - Object visit(ASTForLoopStatement node, Object data); - - Object visit(ASTIfBlockStatement node, Object data); - - Object visit(ASTIfElseBlockStatement node, Object data); - - Object visit(ASTInstanceOfExpression node, Object data); - - Object visit(ASTJavaMethodCallExpression node, Object data); - - Object visit(ASTJavaVariableExpression node, Object data); - - Object visit(ASTLiteralExpression node, Object data); - - Object visit(ASTMapEntryNode node, Object data); - - Object visit(ASTMethod node, Object data); - - Object visit(ASTMethodCallExpression node, Object data); - - Object visit(ASTModifierNode node, Object data); - - Object visit(ASTModifierOrAnnotation node, Object data); - - Object visit(ASTNewListInitExpression node, Object data); - - Object visit(ASTNewListLiteralExpression node, Object data); - - Object visit(ASTNewMapInitExpression node, Object data); - - Object visit(ASTNewMapLiteralExpression node, Object data); - - Object visit(ASTNewNameValueObjectExpression node, Object data); - - Object visit(ASTNewObjectExpression node, Object data); - - Object visit(ASTNewSetInitExpression node, Object data); - - Object visit(ASTNewSetLiteralExpression node, Object data); - - Object visit(ASTPackageVersionExpression node, Object data); - - Object visit(ASTParameter node, Object data); - - Object visit(ASTPostfixExpression node, Object data); - - Object visit(ASTPrefixExpression node, Object data); - - Object visit(ASTProperty node, Object data); - - Object visit(ASTReferenceExpression node, Object data); - - Object visit(ASTReturnStatement node, Object data); - - Object visit(ASTRunAsBlockStatement node, Object data); - - Object visit(ASTSoqlExpression node, Object data); - - Object visit(ASTSoslExpression node, Object data); - - Object visit(ASTStandardCondition node, Object data); - - Object visit(ASTStatement node, Object data); - - Object visit(ASTSuperMethodCallExpression node, Object data); - - Object visit(ASTSuperVariableExpression node, Object data); - - Object visit(ASTTernaryExpression node, Object data); - - Object visit(ASTTestNode node, Object data); - - Object visit(ASTThisMethodCallExpression node, Object data); - - Object visit(ASTThisVariableExpression node, Object data); - - Object visit(ASTThrowStatement node, Object data); - - Object visit(ASTTriggerVariableExpression node, Object data); - - Object visit(ASTTryCatchFinallyBlockStatement node, Object data); - - Object visit(ASTUserClass node, Object data); - - Object visit(ASTUserClassMethods node, Object data); - - Object visit(ASTUserEnum node, Object data); - - Object visit(ASTUserExceptionMethods node, Object data); - - Object visit(ASTUserInterface node, Object data); - - Object visit(ASTUserTrigger node, Object data); - - Object visit(ASTVariableDeclaration node, Object data); - - Object visit(ASTVariableDeclarationStatements node, Object data); - - Object visit(ASTVariableExpression node, Object data); - - Object visit(ASTWhileLoopStatement node, Object data); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +public interface ApexParserVisitor { + Object visit(ApexNode node, Object data); + + Object visit(ASTAnnotation node, Object data); + + Object visit(ASTAnonymousClass node, Object data); + + Object visit(ASTArrayLoadExpression node, Object data); + + Object visit(ASTArrayStoreExpression node, Object data); + + Object visit(ASTAssignmentExpression node, Object data); + + Object visit(ASTBinaryExpression node, Object data); + + Object visit(ASTBindExpressions node, Object data); + + Object visit(ASTBlockStatement node, Object data); + + Object visit(ASTBooleanExpression node, Object data); + + Object visit(ASTBreakStatement node, Object data); + + Object visit(ASTBridgeMethodCreator node, Object data); + + Object visit(ASTCatchBlockStatement node, Object data); + + Object visit(ASTClassRefExpression node, Object data); + + Object visit(ASTConstructorPreambleStatement node, Object data); + + Object visit(ASTContinueStatement node, Object data); + + Object visit(ASTDmlDeleteStatement node, Object data); + + Object visit(ASTDmlInsertStatement node, Object data); + + Object visit(ASTDmlMergeStatement node, Object data); + + Object visit(ASTDmlUndeleteStatement node, Object data); + + Object visit(ASTDmlUpdateStatement node, Object data); + + Object visit(ASTDmlUpsertStatement node, Object data); + + Object visit(ASTDoLoopStatement node, Object data); + + Object visit(ASTDottedExpression node, Object data); + + Object visit(ASTExpression node, Object data); + + Object visit(ASTExpressionStatement node, Object data); + + Object visit(ASTField node, Object data); + + Object visit(ASTFieldDeclaration node, Object data); + + Object visit(ASTFieldDeclarationStatements node, Object data); + + Object visit(ASTForEachStatement node, Object data); + + Object visit(ASTForLoopStatement node, Object data); + + Object visit(ASTIfBlockStatement node, Object data); + + Object visit(ASTIfElseBlockStatement node, Object data); + + Object visit(ASTInstanceOfExpression node, Object data); + + Object visit(ASTJavaMethodCallExpression node, Object data); + + Object visit(ASTJavaVariableExpression node, Object data); + + Object visit(ASTLiteralExpression node, Object data); + + Object visit(ASTMapEntryNode node, Object data); + + Object visit(ASTMethod node, Object data); + + Object visit(ASTMethodCallExpression node, Object data); + + Object visit(ASTModifierNode node, Object data); + + Object visit(ASTModifierOrAnnotation node, Object data); + + Object visit(ASTNewListInitExpression node, Object data); + + Object visit(ASTNewListLiteralExpression node, Object data); + + Object visit(ASTNewMapInitExpression node, Object data); + + Object visit(ASTNewMapLiteralExpression node, Object data); + + Object visit(ASTNewNameValueObjectExpression node, Object data); + + Object visit(ASTNewObjectExpression node, Object data); + + Object visit(ASTNewSetInitExpression node, Object data); + + Object visit(ASTNewSetLiteralExpression node, Object data); + + Object visit(ASTPackageVersionExpression node, Object data); + + Object visit(ASTParameter node, Object data); + + Object visit(ASTPostfixExpression node, Object data); + + Object visit(ASTPrefixExpression node, Object data); + + Object visit(ASTProperty node, Object data); + + Object visit(ASTReferenceExpression node, Object data); + + Object visit(ASTReturnStatement node, Object data); + + Object visit(ASTRunAsBlockStatement node, Object data); + + Object visit(ASTSoqlExpression node, Object data); + + Object visit(ASTSoslExpression node, Object data); + + Object visit(ASTStandardCondition node, Object data); + + Object visit(ASTStatement node, Object data); + + Object visit(ASTSuperMethodCallExpression node, Object data); + + Object visit(ASTSuperVariableExpression node, Object data); + + Object visit(ASTTernaryExpression node, Object data); + + Object visit(ASTTestNode node, Object data); + + Object visit(ASTThisMethodCallExpression node, Object data); + + Object visit(ASTThisVariableExpression node, Object data); + + Object visit(ASTThrowStatement node, Object data); + + Object visit(ASTTriggerVariableExpression node, Object data); + + Object visit(ASTTryCatchFinallyBlockStatement node, Object data); + + Object visit(ASTUserClass node, Object data); + + Object visit(ASTUserClassMethods node, Object data); + + Object visit(ASTUserEnum node, Object data); + + Object visit(ASTUserExceptionMethods node, Object data); + + Object visit(ASTUserInterface node, Object data); + + Object visit(ASTUserTrigger node, Object data); + + Object visit(ASTVariableDeclaration node, Object data); + + Object visit(ASTVariableDeclarationStatements node, Object data); + + Object visit(ASTVariableExpression node, Object data); + + Object visit(ASTWhileLoopStatement node, Object data); +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java index 72340e8f3b..fcbb799aac 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java @@ -1,413 +1,413 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -public class ApexParserVisitorAdapter implements ApexParserVisitor { - @Override - public Object visit(ApexNode node, Object data) { - node.childrenAccept(this, data); - return null; - } - - @Override - public Object visit(ASTMethod node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTParameter node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClassMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBridgeMethodCreator node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTConstructorPreambleStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserInterface node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserEnum node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfElseBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForEachStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTField node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBreakStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThrowStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDoLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTernaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoqlExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBooleanExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnonymousClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayLoadExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAssignmentExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBinaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBindExpressions node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTCatchBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTClassRefExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTContinueStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlDeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlInsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlMergeStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUndeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpdateStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDottedExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpressionStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTInstanceOfExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMapEntryNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierOrAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewNameValueObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPackageVersionExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPostfixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPrefixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTProperty node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReferenceExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTRunAsBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoslExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStandardCondition node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTestNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTriggerVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserExceptionMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserTrigger node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +public class ApexParserVisitorAdapter implements ApexParserVisitor { + @Override + public Object visit(ApexNode node, Object data) { + node.childrenAccept(this, data); + return null; + } + + @Override + public Object visit(ASTMethod node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserClass node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTModifierNode node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTParameter node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserClassMethods node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBridgeMethodCreator node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTReturnStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTConstructorPreambleStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserInterface node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserEnum node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTFieldDeclaration node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTWhileLoopStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTForLoopStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTIfElseBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTIfBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTForEachStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTField node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBreakStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTThrowStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDoLoopStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTernaryExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSoqlExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBooleanExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTAnnotation node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTAnonymousClass node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTArrayLoadExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTArrayStoreExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTAssignmentExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBinaryExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBindExpressions node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTCatchBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTClassRefExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTContinueStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlDeleteStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlInsertStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlMergeStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlUndeleteStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlUpdateStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlUpsertStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDottedExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTExpressionStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTFieldDeclarationStatements node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTInstanceOfExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTJavaMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTJavaVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTMapEntryNode node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTModifierOrAnnotation node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewListInitExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewListLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewMapInitExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewMapLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewNameValueObjectExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewObjectExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewSetInitExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewSetLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTPackageVersionExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTPostfixExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTPrefixExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTProperty node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTReferenceExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTRunAsBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSoslExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTStandardCondition node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSuperMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSuperVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTestNode node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTThisMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTThisVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTriggerVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserExceptionMethods node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserTrigger node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTVariableDeclaration node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTVariableDeclarationStatements node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index c3abe1e033..614f54c414 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -1,641 +1,641 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.SourceCodePositioner; - -import apex.jorje.semantic.ast.AstNode; -import apex.jorje.semantic.ast.compilation.UserClass; -import apex.jorje.semantic.ast.compilation.UserClassMethods; -import apex.jorje.semantic.ast.compilation.UserEnum; -import apex.jorje.semantic.ast.compilation.UserExceptionMethods; -import apex.jorje.semantic.ast.compilation.UserInterface; -import apex.jorje.semantic.ast.compilation.UserTrigger; -import apex.jorje.semantic.ast.condition.StandardCondition; -import apex.jorje.semantic.ast.expression.ArrayLoadExpression; -import apex.jorje.semantic.ast.expression.ArrayStoreExpression; -import apex.jorje.semantic.ast.expression.AssignmentExpression; -import apex.jorje.semantic.ast.expression.BinaryExpression; -import apex.jorje.semantic.ast.expression.BindExpressions; -import apex.jorje.semantic.ast.expression.BooleanExpression; -import apex.jorje.semantic.ast.expression.ClassRefExpression; -import apex.jorje.semantic.ast.expression.DottedExpression; -import apex.jorje.semantic.ast.expression.Expression; -import apex.jorje.semantic.ast.expression.InstanceOfExpression; -import apex.jorje.semantic.ast.expression.JavaMethodCallExpression; -import apex.jorje.semantic.ast.expression.JavaVariableExpression; -import apex.jorje.semantic.ast.expression.LiteralExpression; -import apex.jorje.semantic.ast.expression.MapEntryNode; -import apex.jorje.semantic.ast.expression.MethodCallExpression; -import apex.jorje.semantic.ast.expression.NewListInitExpression; -import apex.jorje.semantic.ast.expression.NewListLiteralExpression; -import apex.jorje.semantic.ast.expression.NewMapInitExpression; -import apex.jorje.semantic.ast.expression.NewMapLiteralExpression; -import apex.jorje.semantic.ast.expression.NewNameValueObjectExpression; -import apex.jorje.semantic.ast.expression.NewObjectExpression; -import apex.jorje.semantic.ast.expression.NewSetInitExpression; -import apex.jorje.semantic.ast.expression.NewSetLiteralExpression; -import apex.jorje.semantic.ast.expression.PackageVersionExpression; -import apex.jorje.semantic.ast.expression.PostfixExpression; -import apex.jorje.semantic.ast.expression.PrefixExpression; -import apex.jorje.semantic.ast.expression.ReferenceExpression; -import apex.jorje.semantic.ast.expression.SoqlExpression; -import apex.jorje.semantic.ast.expression.SoslExpression; -import apex.jorje.semantic.ast.expression.SuperMethodCallExpression; -import apex.jorje.semantic.ast.expression.SuperVariableExpression; -import apex.jorje.semantic.ast.expression.TernaryExpression; -import apex.jorje.semantic.ast.expression.ThisMethodCallExpression; -import apex.jorje.semantic.ast.expression.ThisVariableExpression; -import apex.jorje.semantic.ast.expression.TriggerVariableExpression; -import apex.jorje.semantic.ast.expression.VariableExpression; -import apex.jorje.semantic.ast.member.Field; -import apex.jorje.semantic.ast.member.Method; -import apex.jorje.semantic.ast.member.Parameter; -import apex.jorje.semantic.ast.member.Property; -import apex.jorje.semantic.ast.member.bridge.BridgeMethodCreator; -import apex.jorje.semantic.ast.modifier.Annotation; -import apex.jorje.semantic.ast.modifier.AnnotationParameter; -import apex.jorje.semantic.ast.modifier.ModifierNode; -import apex.jorje.semantic.ast.modifier.ModifierOrAnnotation; -import apex.jorje.semantic.ast.statement.BlockStatement; -import apex.jorje.semantic.ast.statement.BreakStatement; -import apex.jorje.semantic.ast.statement.CatchBlockStatement; -import apex.jorje.semantic.ast.statement.ContinueStatement; -import apex.jorje.semantic.ast.statement.DmlDeleteStatement; -import apex.jorje.semantic.ast.statement.DmlInsertStatement; -import apex.jorje.semantic.ast.statement.DmlMergeStatement; -import apex.jorje.semantic.ast.statement.DmlUndeleteStatement; -import apex.jorje.semantic.ast.statement.DmlUpdateStatement; -import apex.jorje.semantic.ast.statement.DmlUpsertStatement; -import apex.jorje.semantic.ast.statement.DoLoopStatement; -import apex.jorje.semantic.ast.statement.ExpressionStatement; -import apex.jorje.semantic.ast.statement.FieldDeclaration; -import apex.jorje.semantic.ast.statement.FieldDeclarationStatements; -import apex.jorje.semantic.ast.statement.ForEachStatement; -import apex.jorje.semantic.ast.statement.ForLoopStatement; -import apex.jorje.semantic.ast.statement.IfBlockStatement; -import apex.jorje.semantic.ast.statement.IfElseBlockStatement; -import apex.jorje.semantic.ast.statement.ReturnStatement; -import apex.jorje.semantic.ast.statement.RunAsBlockStatement; -import apex.jorje.semantic.ast.statement.Statement; -import apex.jorje.semantic.ast.statement.ThrowStatement; -import apex.jorje.semantic.ast.statement.TryCatchFinallyBlockStatement; -import apex.jorje.semantic.ast.statement.VariableDeclaration; -import apex.jorje.semantic.ast.statement.VariableDeclarationStatements; -import apex.jorje.semantic.ast.statement.WhileLoopStatement; -import apex.jorje.semantic.ast.visitor.AdditionalPassScope; -import apex.jorje.semantic.ast.visitor.AstVisitor; -import apex.jorje.semantic.exception.Errors; -import apex.jorje.semantic.tester.TestNode; - -public final class ApexTreeBuilder extends AstVisitor { - - private static final Map, Constructor>> NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<>(); - - static { - register(Annotation.class, ASTAnnotation.class); - register(AnnotationParameter.class, ASTAnnotationParameter.class); - register(ArrayLoadExpression.class, ASTArrayLoadExpression.class); - register(ArrayStoreExpression.class, ASTArrayStoreExpression.class); - register(AssignmentExpression.class, ASTAssignmentExpression.class); - register(BinaryExpression.class, ASTBinaryExpression.class); - register(BindExpressions.class, ASTBindExpressions.class); - register(BlockStatement.class, ASTBlockStatement.class); - register(BooleanExpression.class, ASTBooleanExpression.class); - register(BreakStatement.class, ASTBreakStatement.class); - register(BridgeMethodCreator.class, ASTBridgeMethodCreator.class); - register(CatchBlockStatement.class, ASTCatchBlockStatement.class); - register(ClassRefExpression.class, ASTClassRefExpression.class); - register(ContinueStatement.class, ASTContinueStatement.class); - register(DmlDeleteStatement.class, ASTDmlDeleteStatement.class); - register(DmlInsertStatement.class, ASTDmlInsertStatement.class); - register(DmlMergeStatement.class, ASTDmlMergeStatement.class); - register(DmlUndeleteStatement.class, ASTDmlUndeleteStatement.class); - register(DmlUpdateStatement.class, ASTDmlUpdateStatement.class); - register(DmlUpsertStatement.class, ASTDmlUpsertStatement.class); - register(DoLoopStatement.class, ASTDoLoopStatement.class); - register(DottedExpression.class, ASTDottedExpression.class); - register(Expression.class, ASTExpression.class); - register(ExpressionStatement.class, ASTExpressionStatement.class); - register(Field.class, ASTField.class); - register(FieldDeclaration.class, ASTFieldDeclaration.class); - register(FieldDeclarationStatements.class, ASTFieldDeclarationStatements.class); - register(ForEachStatement.class, ASTForEachStatement.class); - register(ForLoopStatement.class, ASTForLoopStatement.class); - register(IfBlockStatement.class, ASTIfBlockStatement.class); - register(IfElseBlockStatement.class, ASTIfElseBlockStatement.class); - register(InstanceOfExpression.class, ASTInstanceOfExpression.class); - register(JavaMethodCallExpression.class, ASTJavaMethodCallExpression.class); - register(JavaVariableExpression.class, ASTJavaVariableExpression.class); - register(LiteralExpression.class, ASTLiteralExpression.class); - register(MapEntryNode.class, ASTMapEntryNode.class); - register(Method.class, ASTMethod.class); - register(MethodCallExpression.class, ASTMethodCallExpression.class); - register(ModifierNode.class, ASTModifierNode.class); - register(ModifierOrAnnotation.class, ASTModifierOrAnnotation.class); - register(NewListInitExpression.class, ASTNewListInitExpression.class); - register(NewListLiteralExpression.class, ASTNewListLiteralExpression.class); - register(NewMapInitExpression.class, ASTNewMapInitExpression.class); - register(NewMapLiteralExpression.class, ASTNewMapLiteralExpression.class); - register(NewNameValueObjectExpression.class, ASTNewNameValueObjectExpression.class); - register(NewObjectExpression.class, ASTNewObjectExpression.class); - register(NewSetInitExpression.class, ASTNewSetInitExpression.class); - register(NewSetLiteralExpression.class, ASTNewSetLiteralExpression.class); - register(PackageVersionExpression.class, ASTPackageVersionExpression.class); - register(Parameter.class, ASTParameter.class); - register(PostfixExpression.class, ASTPostfixExpression.class); - register(PrefixExpression.class, ASTPrefixExpression.class); - register(Property.class, ASTProperty.class); - register(ReferenceExpression.class, ASTReferenceExpression.class); - register(ReturnStatement.class, ASTReturnStatement.class); - register(RunAsBlockStatement.class, ASTRunAsBlockStatement.class); - register(SoqlExpression.class, ASTSoqlExpression.class); - register(SoslExpression.class, ASTSoslExpression.class); - register(StandardCondition.class, ASTStandardCondition.class); - register(Statement.class, ASTStatement.class); - register(SuperMethodCallExpression.class, ASTSuperMethodCallExpression.class); - register(SuperVariableExpression.class, ASTSuperVariableExpression.class); - register(TernaryExpression.class, ASTTernaryExpression.class); - register(TestNode.class, ASTTestNode.class); - register(ThisMethodCallExpression.class, ASTThisMethodCallExpression.class); - register(ThisVariableExpression.class, ASTThisVariableExpression.class); - register(ThrowStatement.class, ASTThrowStatement.class); - register(TriggerVariableExpression.class, ASTTriggerVariableExpression.class); - register(TryCatchFinallyBlockStatement.class, ASTTryCatchFinallyBlockStatement.class); - register(UserClass.class, ASTUserClass.class); - register(UserTrigger.class, ASTUserTrigger.class); - register(UserClassMethods.class, ASTUserClassMethods.class); - register(UserEnum.class, ASTUserEnum.class); - register(UserExceptionMethods.class, ASTUserExceptionMethods.class); - register(UserInterface.class, ASTUserInterface.class); - register(VariableDeclaration.class, ASTVariableDeclaration.class); - register(VariableDeclarationStatements.class, ASTVariableDeclarationStatements.class); - register(VariableExpression.class, ASTVariableExpression.class); - register(WhileLoopStatement.class, ASTWhileLoopStatement.class); - } - - private static void register(Class nodeType, Class> nodeAdapterType) { - try { - NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType)); - } catch (SecurityException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - // The nodes having children built. - private Stack nodes = new Stack<>(); - - // The Apex nodes with children to build. - private Stack parents = new Stack<>(); - - private SourceCodePositioner sourceCodePositioner; - - public ApexTreeBuilder(String sourceCode) { - sourceCodePositioner = new SourceCodePositioner(sourceCode); - } - - AdditionalPassScope scope = new AdditionalPassScope(new Errors()); - - static ApexNode createNodeAdapter(T node) { - try { - @SuppressWarnings("unchecked") - // the register function makes sure only ApexNode can be added, - // where T is "T extends AstNode". - Constructor> constructor = (Constructor>) NODE_TYPE_TO_NODE_ADAPTER_TYPE - .get(node.getClass()); - if (constructor == null) { - throw new IllegalArgumentException( - "There is no Node adapter class registered for the Node class: " + node.getClass()); - } - return constructor.newInstance(node); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e.getTargetException()); - } - } - - public ApexNode build(T astNode) { - // Create a Node - ApexNode node = createNodeAdapter(astNode); - calculateLineNumbers(node); - - // Append to parent - Node parent = nodes.isEmpty() ? null : nodes.peek(); - if (parent != null) { - parent.jjtAddChild(node, parent.jjtGetNumChildren()); - node.jjtSetParent(parent); - } - - // Build the children... - nodes.push(node); - parents.push(astNode); - astNode.traverse(this, scope); - nodes.pop(); - parents.pop(); - - return node; - } - - private void calculateLineNumbers(ApexNode node) { - AbstractApexNode apexNode = (AbstractApexNode) node; - apexNode.calculateLineNumbers(sourceCodePositioner); - } - - private boolean visit(AstNode node) { - if (parents.peek() == node) { - return true; - } else { - build(node); - return false; - } - } - - @Override - public boolean visit(UserEnum node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(UserInterface node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(UserTrigger node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ArrayLoadExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ArrayStoreExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(AssignmentExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(BinaryExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(BooleanExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ClassRefExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(InstanceOfExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(JavaMethodCallExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(JavaVariableExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(LiteralExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ReferenceExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(MethodCallExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewListInitExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewMapInitExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewSetInitExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewListLiteralExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewObjectExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewSetLiteralExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewNameValueObjectExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(PackageVersionExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(PostfixExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(PrefixExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(TernaryExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(StandardCondition node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(TriggerVariableExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DottedExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(VariableExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(BlockStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(BreakStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ContinueStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DmlDeleteStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DmlInsertStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DmlMergeStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DmlUndeleteStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DmlUpdateStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DmlUpsertStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(DoLoopStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ExpressionStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ForEachStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ForLoopStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(FieldDeclaration node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(FieldDeclarationStatements node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(IfBlockStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(IfElseBlockStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ReturnStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(RunAsBlockStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ThrowStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(VariableDeclaration node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(VariableDeclarationStatements node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(WhileLoopStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(BindExpressions node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(SoqlExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(SoslExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(NewMapLiteralExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(MapEntryNode node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(CatchBlockStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(TryCatchFinallyBlockStatement node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(Property node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(Field node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(Parameter node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(BridgeMethodCreator node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(UserClassMethods node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(UserExceptionMethods node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(Annotation node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(AnnotationParameter node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ModifierNode node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(SuperMethodCallExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ThisMethodCallExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(SuperVariableExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(ThisVariableExpression node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(UserClass node, AdditionalPassScope scope) { - return visit(node); - } - - @Override - public boolean visit(Method node, AdditionalPassScope scope) { - return visit(node); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.SourceCodePositioner; + +import apex.jorje.semantic.ast.AstNode; +import apex.jorje.semantic.ast.compilation.UserClass; +import apex.jorje.semantic.ast.compilation.UserClassMethods; +import apex.jorje.semantic.ast.compilation.UserEnum; +import apex.jorje.semantic.ast.compilation.UserExceptionMethods; +import apex.jorje.semantic.ast.compilation.UserInterface; +import apex.jorje.semantic.ast.compilation.UserTrigger; +import apex.jorje.semantic.ast.condition.StandardCondition; +import apex.jorje.semantic.ast.expression.ArrayLoadExpression; +import apex.jorje.semantic.ast.expression.ArrayStoreExpression; +import apex.jorje.semantic.ast.expression.AssignmentExpression; +import apex.jorje.semantic.ast.expression.BinaryExpression; +import apex.jorje.semantic.ast.expression.BindExpressions; +import apex.jorje.semantic.ast.expression.BooleanExpression; +import apex.jorje.semantic.ast.expression.ClassRefExpression; +import apex.jorje.semantic.ast.expression.DottedExpression; +import apex.jorje.semantic.ast.expression.Expression; +import apex.jorje.semantic.ast.expression.InstanceOfExpression; +import apex.jorje.semantic.ast.expression.JavaMethodCallExpression; +import apex.jorje.semantic.ast.expression.JavaVariableExpression; +import apex.jorje.semantic.ast.expression.LiteralExpression; +import apex.jorje.semantic.ast.expression.MapEntryNode; +import apex.jorje.semantic.ast.expression.MethodCallExpression; +import apex.jorje.semantic.ast.expression.NewListInitExpression; +import apex.jorje.semantic.ast.expression.NewListLiteralExpression; +import apex.jorje.semantic.ast.expression.NewMapInitExpression; +import apex.jorje.semantic.ast.expression.NewMapLiteralExpression; +import apex.jorje.semantic.ast.expression.NewNameValueObjectExpression; +import apex.jorje.semantic.ast.expression.NewObjectExpression; +import apex.jorje.semantic.ast.expression.NewSetInitExpression; +import apex.jorje.semantic.ast.expression.NewSetLiteralExpression; +import apex.jorje.semantic.ast.expression.PackageVersionExpression; +import apex.jorje.semantic.ast.expression.PostfixExpression; +import apex.jorje.semantic.ast.expression.PrefixExpression; +import apex.jorje.semantic.ast.expression.ReferenceExpression; +import apex.jorje.semantic.ast.expression.SoqlExpression; +import apex.jorje.semantic.ast.expression.SoslExpression; +import apex.jorje.semantic.ast.expression.SuperMethodCallExpression; +import apex.jorje.semantic.ast.expression.SuperVariableExpression; +import apex.jorje.semantic.ast.expression.TernaryExpression; +import apex.jorje.semantic.ast.expression.ThisMethodCallExpression; +import apex.jorje.semantic.ast.expression.ThisVariableExpression; +import apex.jorje.semantic.ast.expression.TriggerVariableExpression; +import apex.jorje.semantic.ast.expression.VariableExpression; +import apex.jorje.semantic.ast.member.Field; +import apex.jorje.semantic.ast.member.Method; +import apex.jorje.semantic.ast.member.Parameter; +import apex.jorje.semantic.ast.member.Property; +import apex.jorje.semantic.ast.member.bridge.BridgeMethodCreator; +import apex.jorje.semantic.ast.modifier.Annotation; +import apex.jorje.semantic.ast.modifier.AnnotationParameter; +import apex.jorje.semantic.ast.modifier.ModifierNode; +import apex.jorje.semantic.ast.modifier.ModifierOrAnnotation; +import apex.jorje.semantic.ast.statement.BlockStatement; +import apex.jorje.semantic.ast.statement.BreakStatement; +import apex.jorje.semantic.ast.statement.CatchBlockStatement; +import apex.jorje.semantic.ast.statement.ContinueStatement; +import apex.jorje.semantic.ast.statement.DmlDeleteStatement; +import apex.jorje.semantic.ast.statement.DmlInsertStatement; +import apex.jorje.semantic.ast.statement.DmlMergeStatement; +import apex.jorje.semantic.ast.statement.DmlUndeleteStatement; +import apex.jorje.semantic.ast.statement.DmlUpdateStatement; +import apex.jorje.semantic.ast.statement.DmlUpsertStatement; +import apex.jorje.semantic.ast.statement.DoLoopStatement; +import apex.jorje.semantic.ast.statement.ExpressionStatement; +import apex.jorje.semantic.ast.statement.FieldDeclaration; +import apex.jorje.semantic.ast.statement.FieldDeclarationStatements; +import apex.jorje.semantic.ast.statement.ForEachStatement; +import apex.jorje.semantic.ast.statement.ForLoopStatement; +import apex.jorje.semantic.ast.statement.IfBlockStatement; +import apex.jorje.semantic.ast.statement.IfElseBlockStatement; +import apex.jorje.semantic.ast.statement.ReturnStatement; +import apex.jorje.semantic.ast.statement.RunAsBlockStatement; +import apex.jorje.semantic.ast.statement.Statement; +import apex.jorje.semantic.ast.statement.ThrowStatement; +import apex.jorje.semantic.ast.statement.TryCatchFinallyBlockStatement; +import apex.jorje.semantic.ast.statement.VariableDeclaration; +import apex.jorje.semantic.ast.statement.VariableDeclarationStatements; +import apex.jorje.semantic.ast.statement.WhileLoopStatement; +import apex.jorje.semantic.ast.visitor.AdditionalPassScope; +import apex.jorje.semantic.ast.visitor.AstVisitor; +import apex.jorje.semantic.exception.Errors; +import apex.jorje.semantic.tester.TestNode; + +public final class ApexTreeBuilder extends AstVisitor { + + private static final Map, Constructor>> NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<>(); + + static { + register(Annotation.class, ASTAnnotation.class); + register(AnnotationParameter.class, ASTAnnotationParameter.class); + register(ArrayLoadExpression.class, ASTArrayLoadExpression.class); + register(ArrayStoreExpression.class, ASTArrayStoreExpression.class); + register(AssignmentExpression.class, ASTAssignmentExpression.class); + register(BinaryExpression.class, ASTBinaryExpression.class); + register(BindExpressions.class, ASTBindExpressions.class); + register(BlockStatement.class, ASTBlockStatement.class); + register(BooleanExpression.class, ASTBooleanExpression.class); + register(BreakStatement.class, ASTBreakStatement.class); + register(BridgeMethodCreator.class, ASTBridgeMethodCreator.class); + register(CatchBlockStatement.class, ASTCatchBlockStatement.class); + register(ClassRefExpression.class, ASTClassRefExpression.class); + register(ContinueStatement.class, ASTContinueStatement.class); + register(DmlDeleteStatement.class, ASTDmlDeleteStatement.class); + register(DmlInsertStatement.class, ASTDmlInsertStatement.class); + register(DmlMergeStatement.class, ASTDmlMergeStatement.class); + register(DmlUndeleteStatement.class, ASTDmlUndeleteStatement.class); + register(DmlUpdateStatement.class, ASTDmlUpdateStatement.class); + register(DmlUpsertStatement.class, ASTDmlUpsertStatement.class); + register(DoLoopStatement.class, ASTDoLoopStatement.class); + register(DottedExpression.class, ASTDottedExpression.class); + register(Expression.class, ASTExpression.class); + register(ExpressionStatement.class, ASTExpressionStatement.class); + register(Field.class, ASTField.class); + register(FieldDeclaration.class, ASTFieldDeclaration.class); + register(FieldDeclarationStatements.class, ASTFieldDeclarationStatements.class); + register(ForEachStatement.class, ASTForEachStatement.class); + register(ForLoopStatement.class, ASTForLoopStatement.class); + register(IfBlockStatement.class, ASTIfBlockStatement.class); + register(IfElseBlockStatement.class, ASTIfElseBlockStatement.class); + register(InstanceOfExpression.class, ASTInstanceOfExpression.class); + register(JavaMethodCallExpression.class, ASTJavaMethodCallExpression.class); + register(JavaVariableExpression.class, ASTJavaVariableExpression.class); + register(LiteralExpression.class, ASTLiteralExpression.class); + register(MapEntryNode.class, ASTMapEntryNode.class); + register(Method.class, ASTMethod.class); + register(MethodCallExpression.class, ASTMethodCallExpression.class); + register(ModifierNode.class, ASTModifierNode.class); + register(ModifierOrAnnotation.class, ASTModifierOrAnnotation.class); + register(NewListInitExpression.class, ASTNewListInitExpression.class); + register(NewListLiteralExpression.class, ASTNewListLiteralExpression.class); + register(NewMapInitExpression.class, ASTNewMapInitExpression.class); + register(NewMapLiteralExpression.class, ASTNewMapLiteralExpression.class); + register(NewNameValueObjectExpression.class, ASTNewNameValueObjectExpression.class); + register(NewObjectExpression.class, ASTNewObjectExpression.class); + register(NewSetInitExpression.class, ASTNewSetInitExpression.class); + register(NewSetLiteralExpression.class, ASTNewSetLiteralExpression.class); + register(PackageVersionExpression.class, ASTPackageVersionExpression.class); + register(Parameter.class, ASTParameter.class); + register(PostfixExpression.class, ASTPostfixExpression.class); + register(PrefixExpression.class, ASTPrefixExpression.class); + register(Property.class, ASTProperty.class); + register(ReferenceExpression.class, ASTReferenceExpression.class); + register(ReturnStatement.class, ASTReturnStatement.class); + register(RunAsBlockStatement.class, ASTRunAsBlockStatement.class); + register(SoqlExpression.class, ASTSoqlExpression.class); + register(SoslExpression.class, ASTSoslExpression.class); + register(StandardCondition.class, ASTStandardCondition.class); + register(Statement.class, ASTStatement.class); + register(SuperMethodCallExpression.class, ASTSuperMethodCallExpression.class); + register(SuperVariableExpression.class, ASTSuperVariableExpression.class); + register(TernaryExpression.class, ASTTernaryExpression.class); + register(TestNode.class, ASTTestNode.class); + register(ThisMethodCallExpression.class, ASTThisMethodCallExpression.class); + register(ThisVariableExpression.class, ASTThisVariableExpression.class); + register(ThrowStatement.class, ASTThrowStatement.class); + register(TriggerVariableExpression.class, ASTTriggerVariableExpression.class); + register(TryCatchFinallyBlockStatement.class, ASTTryCatchFinallyBlockStatement.class); + register(UserClass.class, ASTUserClass.class); + register(UserTrigger.class, ASTUserTrigger.class); + register(UserClassMethods.class, ASTUserClassMethods.class); + register(UserEnum.class, ASTUserEnum.class); + register(UserExceptionMethods.class, ASTUserExceptionMethods.class); + register(UserInterface.class, ASTUserInterface.class); + register(VariableDeclaration.class, ASTVariableDeclaration.class); + register(VariableDeclarationStatements.class, ASTVariableDeclarationStatements.class); + register(VariableExpression.class, ASTVariableExpression.class); + register(WhileLoopStatement.class, ASTWhileLoopStatement.class); + } + + private static void register(Class nodeType, Class> nodeAdapterType) { + try { + NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType)); + } catch (SecurityException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + // The nodes having children built. + private Stack nodes = new Stack<>(); + + // The Apex nodes with children to build. + private Stack parents = new Stack<>(); + + private SourceCodePositioner sourceCodePositioner; + + public ApexTreeBuilder(String sourceCode) { + sourceCodePositioner = new SourceCodePositioner(sourceCode); + } + + AdditionalPassScope scope = new AdditionalPassScope(new Errors()); + + static ApexNode createNodeAdapter(T node) { + try { + @SuppressWarnings("unchecked") + // the register function makes sure only ApexNode can be added, + // where T is "T extends AstNode". + Constructor> constructor = (Constructor>) NODE_TYPE_TO_NODE_ADAPTER_TYPE + .get(node.getClass()); + if (constructor == null) { + throw new IllegalArgumentException( + "There is no Node adapter class registered for the Node class: " + node.getClass()); + } + return constructor.newInstance(node); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getTargetException()); + } + } + + public ApexNode build(T astNode) { + // Create a Node + ApexNode node = createNodeAdapter(astNode); + calculateLineNumbers(node); + + // Append to parent + Node parent = nodes.isEmpty() ? null : nodes.peek(); + if (parent != null) { + parent.jjtAddChild(node, parent.jjtGetNumChildren()); + node.jjtSetParent(parent); + } + + // Build the children... + nodes.push(node); + parents.push(astNode); + astNode.traverse(this, scope); + nodes.pop(); + parents.pop(); + + return node; + } + + private void calculateLineNumbers(ApexNode node) { + AbstractApexNode apexNode = (AbstractApexNode) node; + apexNode.calculateLineNumbers(sourceCodePositioner); + } + + private boolean visit(AstNode node) { + if (parents.peek() == node) { + return true; + } else { + build(node); + return false; + } + } + + @Override + public boolean visit(UserEnum node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(UserInterface node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(UserTrigger node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ArrayLoadExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ArrayStoreExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(AssignmentExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(BinaryExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(BooleanExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ClassRefExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(InstanceOfExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(JavaMethodCallExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(JavaVariableExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(LiteralExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ReferenceExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(MethodCallExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewListInitExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewMapInitExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewSetInitExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewListLiteralExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewObjectExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewSetLiteralExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewNameValueObjectExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(PackageVersionExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(PostfixExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(PrefixExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(TernaryExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(StandardCondition node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(TriggerVariableExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DottedExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(VariableExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(BlockStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(BreakStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ContinueStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DmlDeleteStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DmlInsertStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DmlMergeStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DmlUndeleteStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DmlUpdateStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DmlUpsertStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(DoLoopStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ExpressionStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ForEachStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ForLoopStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(FieldDeclaration node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(FieldDeclarationStatements node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(IfBlockStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(IfElseBlockStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ReturnStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(RunAsBlockStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ThrowStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(VariableDeclaration node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(VariableDeclarationStatements node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(WhileLoopStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(BindExpressions node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(SoqlExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(SoslExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(NewMapLiteralExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(MapEntryNode node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(CatchBlockStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(TryCatchFinallyBlockStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(Property node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(Field node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(Parameter node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(BridgeMethodCreator node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(UserClassMethods node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(UserExceptionMethods node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(Annotation node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(AnnotationParameter node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ModifierNode node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(SuperMethodCallExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ThisMethodCallExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(SuperVariableExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ThisVariableExpression node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(UserClass node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(Method node, AdditionalPassScope scope) { + return visit(node); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java index 5caa7e46a0..b51210428b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java @@ -1,537 +1,537 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule; - -import java.util.List; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.apex.ApexLanguageModule; -import net.sourceforge.pmd.lang.apex.ApexParserOptions; -import net.sourceforge.pmd.lang.apex.ast.ASTAnnotation; -import net.sourceforge.pmd.lang.apex.ast.ASTAnonymousClass; -import net.sourceforge.pmd.lang.apex.ast.ASTArrayLoadExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTArrayStoreExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTBinaryExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTBindExpressions; -import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTBooleanExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTBreakStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTBridgeMethodCreator; -import net.sourceforge.pmd.lang.apex.ast.ASTCatchBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTClassRefExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTConstructorPreambleStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTContinueStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlInsertStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlUndeleteStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDottedExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTExpressionStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTField; -import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclarationStatements; -import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTIfElseBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTInstanceOfExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTJavaMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTJavaVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTMapEntryNode; -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTModifierNode; -import net.sourceforge.pmd.lang.apex.ast.ASTModifierOrAnnotation; -import net.sourceforge.pmd.lang.apex.ast.ASTNewListInitExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewListLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewMapInitExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewMapLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewNameValueObjectExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewObjectExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewSetInitExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewSetLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTPackageVersionExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTParameter; -import net.sourceforge.pmd.lang.apex.ast.ASTPostfixExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTPrefixExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTProperty; -import net.sourceforge.pmd.lang.apex.ast.ASTReferenceExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTRunAsBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTSoqlExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTSoslExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTStandardCondition; -import net.sourceforge.pmd.lang.apex.ast.ASTStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTSuperMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTSuperVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTTestNode; -import net.sourceforge.pmd.lang.apex.ast.ASTThisMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTThisVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTThrowStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTTriggerVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTTryCatchFinallyBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClassMethods; -import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; -import net.sourceforge.pmd.lang.apex.ast.ASTUserExceptionMethods; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclarationStatements; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitor; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.AbstractRule; -import net.sourceforge.pmd.lang.rule.ImmutableLanguage; -import net.sourceforge.pmd.renderers.CodeClimateRule; - -public abstract class AbstractApexRule extends AbstractRule - implements ApexParserVisitor, ImmutableLanguage, CodeClimateRule { - - public AbstractApexRule() { - super.setLanguage(LanguageRegistry.getLanguage(ApexLanguageModule.NAME)); - definePropertyDescriptor(CODECLIMATE_CATEGORIES); - definePropertyDescriptor(CODECLIMATE_REMEDIATION_MULTIPLIER); - definePropertyDescriptor(CODECLIMATE_BLOCK_HIGHLIGHTING); - } - - @Override - public ParserOptions getParserOptions() { - return new ApexParserOptions(); - } - - public void apply(List nodes, RuleContext ctx) { - visitAll(nodes, ctx); - } - - protected void visitAll(List nodes, RuleContext ctx) { - for (Object element : nodes) { - if (element instanceof ASTUserClass) { - visit((ASTUserClass) element, ctx); - } else if (element instanceof ASTUserInterface) { - visit((ASTUserInterface) element, ctx); - } else if (element instanceof ASTUserTrigger) { - visit((ASTUserTrigger) element, ctx); - } - } - } - - @Override - public Object visit(ApexNode node, Object data) { - node.childrenAccept(this, data); - return null; - } - - @Override - public Object visit(ASTMethod node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTParameter node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClassMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBridgeMethodCreator node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTConstructorPreambleStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserInterface node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserEnum node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfElseBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForEachStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTField node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBreakStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThrowStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDoLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTernaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoqlExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBooleanExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnonymousClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayLoadExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAssignmentExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBinaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBindExpressions node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTCatchBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTClassRefExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTContinueStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlDeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlInsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlMergeStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUndeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpdateStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDottedExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpressionStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTInstanceOfExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMapEntryNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierOrAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewNameValueObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPackageVersionExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPostfixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPrefixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTProperty node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReferenceExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTRunAsBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoslExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStandardCondition node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTestNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTriggerVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserExceptionMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserTrigger node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule; + +import java.util.List; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.apex.ApexLanguageModule; +import net.sourceforge.pmd.lang.apex.ApexParserOptions; +import net.sourceforge.pmd.lang.apex.ast.ASTAnnotation; +import net.sourceforge.pmd.lang.apex.ast.ASTAnonymousClass; +import net.sourceforge.pmd.lang.apex.ast.ASTArrayLoadExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTArrayStoreExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTBinaryExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTBindExpressions; +import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTBooleanExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTBreakStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTBridgeMethodCreator; +import net.sourceforge.pmd.lang.apex.ast.ASTCatchBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTClassRefExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTConstructorPreambleStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTContinueStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDmlInsertStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDmlUndeleteStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDottedExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTExpressionStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTField; +import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclarationStatements; +import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTIfElseBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTInstanceOfExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTJavaMethodCallExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTJavaVariableExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTLiteralExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTMapEntryNode; +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTModifierNode; +import net.sourceforge.pmd.lang.apex.ast.ASTModifierOrAnnotation; +import net.sourceforge.pmd.lang.apex.ast.ASTNewListInitExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewListLiteralExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewMapInitExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewMapLiteralExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewNameValueObjectExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewObjectExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewSetInitExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTNewSetLiteralExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTPackageVersionExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTParameter; +import net.sourceforge.pmd.lang.apex.ast.ASTPostfixExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTPrefixExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTProperty; +import net.sourceforge.pmd.lang.apex.ast.ASTReferenceExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTRunAsBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTSoqlExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTSoslExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTStandardCondition; +import net.sourceforge.pmd.lang.apex.ast.ASTStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTSuperMethodCallExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTSuperVariableExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTTestNode; +import net.sourceforge.pmd.lang.apex.ast.ASTThisMethodCallExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTThisVariableExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTThrowStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTTriggerVariableExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTTryCatchFinallyBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClassMethods; +import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; +import net.sourceforge.pmd.lang.apex.ast.ASTUserExceptionMethods; +import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; +import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; +import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; +import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclarationStatements; +import net.sourceforge.pmd.lang.apex.ast.ASTVariableExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitor; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRule; +import net.sourceforge.pmd.lang.rule.ImmutableLanguage; +import net.sourceforge.pmd.renderers.CodeClimateRule; + +public abstract class AbstractApexRule extends AbstractRule + implements ApexParserVisitor, ImmutableLanguage, CodeClimateRule { + + public AbstractApexRule() { + super.setLanguage(LanguageRegistry.getLanguage(ApexLanguageModule.NAME)); + definePropertyDescriptor(CODECLIMATE_CATEGORIES); + definePropertyDescriptor(CODECLIMATE_REMEDIATION_MULTIPLIER); + definePropertyDescriptor(CODECLIMATE_BLOCK_HIGHLIGHTING); + } + + @Override + public ParserOptions getParserOptions() { + return new ApexParserOptions(); + } + + public void apply(List nodes, RuleContext ctx) { + visitAll(nodes, ctx); + } + + protected void visitAll(List nodes, RuleContext ctx) { + for (Object element : nodes) { + if (element instanceof ASTUserClass) { + visit((ASTUserClass) element, ctx); + } else if (element instanceof ASTUserInterface) { + visit((ASTUserInterface) element, ctx); + } else if (element instanceof ASTUserTrigger) { + visit((ASTUserTrigger) element, ctx); + } + } + } + + @Override + public Object visit(ApexNode node, Object data) { + node.childrenAccept(this, data); + return null; + } + + @Override + public Object visit(ASTMethod node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserClass node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTModifierNode node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTParameter node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserClassMethods node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBridgeMethodCreator node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTReturnStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTConstructorPreambleStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserInterface node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserEnum node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTFieldDeclaration node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTWhileLoopStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTForLoopStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTIfElseBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTIfBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTForEachStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTField node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBreakStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTThrowStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDoLoopStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTernaryExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSoqlExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBooleanExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTAnnotation node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTAnonymousClass node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTArrayLoadExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTArrayStoreExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTAssignmentExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBinaryExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTBindExpressions node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTCatchBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTClassRefExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTContinueStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlDeleteStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlInsertStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlMergeStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlUndeleteStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlUpdateStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDmlUpsertStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTDottedExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTExpressionStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTFieldDeclarationStatements node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTInstanceOfExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTJavaMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTJavaVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTMapEntryNode node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTModifierOrAnnotation node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewListInitExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewListLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewMapInitExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewMapLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewNameValueObjectExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewObjectExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewSetInitExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTNewSetLiteralExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTPackageVersionExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTPostfixExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTPrefixExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTProperty node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTReferenceExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTRunAsBlockStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSoslExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTStandardCondition node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTStatement node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSuperMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTSuperVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTestNode node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTThisMethodCallExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTThisVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTTriggerVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserExceptionMethods node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTUserTrigger node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTVariableDeclaration node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTVariableDeclarationStatements node, Object data) { + return visit((ApexNode) node, data); + } + + @Override + public Object visit(ASTVariableExpression node, Object data) { + return visit((ApexNode) node, data); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractStatisticalApexRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractStatisticalApexRule.java index 27fc0e6576..facfe0f7e5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractStatisticalApexRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractStatisticalApexRule.java @@ -1,32 +1,32 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule; - -import java.util.List; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.stat.StatisticalRule; -import net.sourceforge.pmd.lang.rule.stat.StatisticalRuleHelper; -import net.sourceforge.pmd.stat.DataPoint; - -public abstract class AbstractStatisticalApexRule extends AbstractApexRule implements StatisticalRule { - - private final StatisticalRuleHelper helper = new StatisticalRuleHelper(this); - - public void addDataPoint(DataPoint point) { - helper.addDataPoint(point); - } - - public Object[] getViolationParameters(DataPoint point) { - return null; - } - - @Override - public void apply(List nodes, RuleContext ctx) { - super.apply(nodes, ctx); - helper.apply(ctx); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule; + +import java.util.List; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.stat.StatisticalRule; +import net.sourceforge.pmd.lang.rule.stat.StatisticalRuleHelper; +import net.sourceforge.pmd.stat.DataPoint; + +public abstract class AbstractStatisticalApexRule extends AbstractApexRule implements StatisticalRule { + + private final StatisticalRuleHelper helper = new StatisticalRuleHelper(this); + + public void addDataPoint(DataPoint point) { + helper.addDataPoint(point); + } + + public Object[] getViolationParameters(DataPoint point) { + return null; + } + + @Override + public void apply(List nodes, RuleContext ctx) { + super.apply(nodes, ctx); + helper.apply(ctx); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleChainVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleChainVisitor.java index d730519e93..b3f906bbc7 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleChainVisitor.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleChainVisitor.java @@ -1,43 +1,43 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule; - -import java.util.Collections; -import java.util.List; -import java.util.Stack; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitor; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.AbstractRuleChainVisitor; -import net.sourceforge.pmd.lang.rule.XPathRule; - -public class ApexRuleChainVisitor extends AbstractRuleChainVisitor { - - protected void indexNodes(List nodes, RuleContext ctx) { - Stack stack = new Stack<>(); - stack.addAll(nodes); - Collections.reverse(stack); - while (!stack.isEmpty()) { - Node node = stack.pop(); - indexNode(node); - if (node.jjtGetNumChildren() > 0) { - for (int i = node.jjtGetNumChildren() - 1; i >= 0; i--) { - stack.push(node.jjtGetChild(i)); - } - } - } - } - - protected void visit(Rule rule, Node node, RuleContext ctx) { - if (rule instanceof XPathRule) { - ((XPathRule) rule).evaluate(node, ctx); - } else { - ((ApexNode) node).jjtAccept((ApexParserVisitor) rule, ctx); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule; + +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitor; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRuleChainVisitor; +import net.sourceforge.pmd.lang.rule.XPathRule; + +public class ApexRuleChainVisitor extends AbstractRuleChainVisitor { + + protected void indexNodes(List nodes, RuleContext ctx) { + Stack stack = new Stack<>(); + stack.addAll(nodes); + Collections.reverse(stack); + while (!stack.isEmpty()) { + Node node = stack.pop(); + indexNode(node); + if (node.jjtGetNumChildren() > 0) { + for (int i = node.jjtGetNumChildren() - 1; i >= 0; i--) { + stack.push(node.jjtGetChild(i)); + } + } + } + } + + protected void visit(Rule rule, Node node, RuleContext ctx) { + if (rule instanceof XPathRule) { + ((XPathRule) rule).evaluate(node, ctx); + } else { + ((ApexNode) node).jjtAccept((ApexParserVisitor) rule, ctx); + } + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleViolationFactory.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleViolationFactory.java index 971b5dd02f..30fa90df4a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleViolationFactory.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexRuleViolationFactory.java @@ -1,32 +1,32 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory; -import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; - -public final class ApexRuleViolationFactory extends AbstractRuleViolationFactory { - - public static final ApexRuleViolationFactory INSTANCE = new ApexRuleViolationFactory(); - - private ApexRuleViolationFactory() { - } - - @SuppressWarnings("rawtypes") - @Override - protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) { - return new ParametricRuleViolation<>(rule, ruleContext, (ApexNode) node, message); - } - - protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, - int beginLine, int endLine) { - return null; // FIXME - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory; +import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; + +public final class ApexRuleViolationFactory extends AbstractRuleViolationFactory { + + public static final ApexRuleViolationFactory INSTANCE = new ApexRuleViolationFactory(); + + private ApexRuleViolationFactory() { + } + + @SuppressWarnings("rawtypes") + @Override + protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) { + return new ParametricRuleViolation<>(rule, ruleContext, (ApexNode) node, message); + } + + protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, + int beginLine, int endLine) { + return null; // FIXME + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java index 743310b966..37f5f6ff48 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java @@ -1,23 +1,23 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.apex.ApexLanguageModule; -import net.sourceforge.pmd.lang.apex.ApexParserOptions; -import net.sourceforge.pmd.lang.rule.XPathRule; - -public class ApexXPathRule extends XPathRule { - - public ApexXPathRule() { - super.setLanguage(LanguageRegistry.getLanguage(ApexLanguageModule.NAME)); - } - - @Override - public ParserOptions getParserOptions() { - return new ApexParserOptions(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.apex.ApexLanguageModule; +import net.sourceforge.pmd.lang.apex.ApexParserOptions; +import net.sourceforge.pmd.lang.rule.XPathRule; + +public class ApexXPathRule extends XPathRule { + + public ApexXPathRule() { + super.setLanguage(LanguageRegistry.getLanguage(ApexLanguageModule.NAME)); + } + + @Override + public ParserOptions getParserOptions() { + return new ApexParserOptions(); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java index 754b873825..9e3d56aab6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java @@ -1,47 +1,47 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.complexity; - -import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -public class AvoidDeeplyNestedIfStmtsRule extends AbstractApexRule { - - private int depth; - private int depthLimit; - - private static final IntegerProperty PROBLEM_DEPTH_DESCRIPTOR = new IntegerProperty("problemDepth", - "The if statement depth reporting threshold", 1, 25, 3, 1.0f); - - public AvoidDeeplyNestedIfStmtsRule() { - definePropertyDescriptor(PROBLEM_DEPTH_DESCRIPTOR); - - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); - // Note: Remedy needs better OO design and therefore high effort - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 200); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - public Object visit(ASTUserClass node, Object data) { - depth = 0; - depthLimit = getProperty(PROBLEM_DEPTH_DESCRIPTOR); - - return super.visit(node, data); - } - - public Object visit(ASTIfBlockStatement node, Object data) { - depth++; - - super.visit(node, data); - if (depth == depthLimit) { - addViolation(data, node); - } - depth--; - - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.complexity; + +import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +public class AvoidDeeplyNestedIfStmtsRule extends AbstractApexRule { + + private int depth; + private int depthLimit; + + private static final IntegerProperty PROBLEM_DEPTH_DESCRIPTOR = new IntegerProperty("problemDepth", + "The if statement depth reporting threshold", 1, 25, 3, 1.0f); + + public AvoidDeeplyNestedIfStmtsRule() { + definePropertyDescriptor(PROBLEM_DEPTH_DESCRIPTOR); + + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); + // Note: Remedy needs better OO design and therefore high effort + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 200); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + public Object visit(ASTUserClass node, Object data) { + depth = 0; + depthLimit = getProperty(PROBLEM_DEPTH_DESCRIPTOR); + + return super.visit(node, data); + } + + public Object visit(ASTIfBlockStatement node, Object data) { + depth++; + + super.visit(node, data); + if (depth == depthLimit) { + addViolation(data, node); + } + depth--; + + return data; + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/ExcessiveParameterListRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/ExcessiveParameterListRule.java index dc530b5cda..33d7f426db 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/ExcessiveParameterListRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/ExcessiveParameterListRule.java @@ -1,28 +1,28 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.complexity; - -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTParameter; -import net.sourceforge.pmd.util.NumericConstants; - -/** - * This rule detects an abnormally long parameter list. Note: This counts Nodes, - * and not necessarily parameters, so the numbers may not match up. (But - * topcount and sigma should work.) - */ -public class ExcessiveParameterListRule extends ExcessiveNodeCountRule { - public ExcessiveParameterListRule() { - super(ASTMethod.class); - setProperty(MINIMUM_DESCRIPTOR, 4d); - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 50); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - public Object visit(ASTParameter node, Object data) { - return NumericConstants.ONE; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.complexity; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTParameter; +import net.sourceforge.pmd.util.NumericConstants; + +/** + * This rule detects an abnormally long parameter list. Note: This counts Nodes, + * and not necessarily parameters, so the numbers may not match up. (But + * topcount and sigma should work.) + */ +public class ExcessiveParameterListRule extends ExcessiveNodeCountRule { + public ExcessiveParameterListRule() { + super(ASTMethod.class); + setProperty(MINIMUM_DESCRIPTOR, 4d); + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 50); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + public Object visit(ASTParameter node, Object data) { + return NumericConstants.ONE; + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java index ba32d53f45..f718e5aa33 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java @@ -1,214 +1,214 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.complexity; - -import java.util.Stack; - -import net.sourceforge.pmd.lang.apex.ast.ASTBooleanExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTTryCatchFinallyBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; -import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -/** - * Implements the standard cyclomatic complexity rule - *

- * Standard rules: +1 for each decision point, but not including boolean - * operators unlike CyclomaticComplexityRule. - * - * @author ported on Java version of Alan Hohn, based on work by Donald A. - * Leckie - * - * @since June 18, 2014 - */ -public class StdCyclomaticComplexityRule extends AbstractApexRule { - - public static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty("reportLevel", - "Cyclomatic Complexity reporting threshold", 1, 30, 10, 1.0f); - - public static final BooleanProperty SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty( - "showClassesComplexity", "Add class average violations to the report", true, 2.0f); - - public static final BooleanProperty SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty( - "showMethodsComplexity", "Add method average violations to the report", true, 3.0f); - - private int reportLevel; - private boolean showClassesComplexity = true; - private boolean showMethodsComplexity = true; - - protected static class Entry { - private int decisionPoints = 1; - public int highestDecisionPoints; - public int methodCount; - - private Entry(Node node) { - } - - public void bumpDecisionPoints() { - decisionPoints++; - } - - public void bumpDecisionPoints(int size) { - decisionPoints += size; - } - - public int getComplexityAverage() { - return (double) methodCount == 0 ? 1 : (int) Math.rint((double) decisionPoints / (double) methodCount); - } - } - - protected Stack entryStack = new Stack<>(); - - public StdCyclomaticComplexityRule() { - definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR); - definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 250); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); - showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (showClassesComplexity) { - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "class", node.getImage(), - classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); - } - } - return data; - } - - @Override - public Object visit(ASTUserTrigger node, Object data) { - reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); - showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (showClassesComplexity) { - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "trigger", node.getImage(), - classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); - } - } - return data; - } - - @Override - public Object visit(ASTUserInterface node, Object data) { - return data; - } - - @Override - public Object visit(ASTUserEnum node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "class", node.getImage(), - classEntry.getComplexityAverage() + "(Highest = " + classEntry.highestDecisionPoints + ')', }); - } - return data; - } - - @Override - public Object visit(ASTMethod node, Object data) { - if (!node.getImage().matches("||clone")) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry methodEntry = entryStack.pop(); - int methodDecisionPoints = methodEntry.decisionPoints; - Entry classEntry = entryStack.peek(); - classEntry.methodCount++; - classEntry.bumpDecisionPoints(methodDecisionPoints); - - if (methodDecisionPoints > classEntry.highestDecisionPoints) { - classEntry.highestDecisionPoints = methodDecisionPoints; - } - - if (showMethodsComplexity && methodEntry.decisionPoints >= reportLevel) { - String methodType = (node.getNode().getMethodInfo().isConstructor()) ? "constructor" : "method"; - addViolation(data, node, - new String[] { methodType, node.getImage(), String.valueOf(methodEntry.decisionPoints) }); - } - } - return data; - } - - @Override - public Object visit(ASTIfBlockStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTForLoopStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTForEachStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTDoLoopStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTTernaryExpression node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTBooleanExpression node, Object data) { - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.complexity; + +import java.util.Stack; + +import net.sourceforge.pmd.lang.apex.ast.ASTBooleanExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTTryCatchFinallyBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; +import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; +import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; +import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +/** + * Implements the standard cyclomatic complexity rule + *

+ * Standard rules: +1 for each decision point, but not including boolean + * operators unlike CyclomaticComplexityRule. + * + * @author ported on Java version of Alan Hohn, based on work by Donald A. + * Leckie + * + * @since June 18, 2014 + */ +public class StdCyclomaticComplexityRule extends AbstractApexRule { + + public static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty("reportLevel", + "Cyclomatic Complexity reporting threshold", 1, 30, 10, 1.0f); + + public static final BooleanProperty SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty( + "showClassesComplexity", "Add class average violations to the report", true, 2.0f); + + public static final BooleanProperty SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty( + "showMethodsComplexity", "Add method average violations to the report", true, 3.0f); + + private int reportLevel; + private boolean showClassesComplexity = true; + private boolean showMethodsComplexity = true; + + protected static class Entry { + private int decisionPoints = 1; + public int highestDecisionPoints; + public int methodCount; + + private Entry(Node node) { + } + + public void bumpDecisionPoints() { + decisionPoints++; + } + + public void bumpDecisionPoints(int size) { + decisionPoints += size; + } + + public int getComplexityAverage() { + return (double) methodCount == 0 ? 1 : (int) Math.rint((double) decisionPoints / (double) methodCount); + } + } + + protected Stack entryStack = new Stack<>(); + + public StdCyclomaticComplexityRule() { + definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR); + definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); + definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); + + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 250); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + @Override + public Object visit(ASTUserClass node, Object data) { + reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); + showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); + showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry classEntry = entryStack.pop(); + if (showClassesComplexity) { + if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "class", node.getImage(), + classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); + } + } + return data; + } + + @Override + public Object visit(ASTUserTrigger node, Object data) { + reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); + showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); + showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry classEntry = entryStack.pop(); + if (showClassesComplexity) { + if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "trigger", node.getImage(), + classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); + } + } + return data; + } + + @Override + public Object visit(ASTUserInterface node, Object data) { + return data; + } + + @Override + public Object visit(ASTUserEnum node, Object data) { + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry classEntry = entryStack.pop(); + if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "class", node.getImage(), + classEntry.getComplexityAverage() + "(Highest = " + classEntry.highestDecisionPoints + ')', }); + } + return data; + } + + @Override + public Object visit(ASTMethod node, Object data) { + if (!node.getImage().matches("||clone")) { + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry methodEntry = entryStack.pop(); + int methodDecisionPoints = methodEntry.decisionPoints; + Entry classEntry = entryStack.peek(); + classEntry.methodCount++; + classEntry.bumpDecisionPoints(methodDecisionPoints); + + if (methodDecisionPoints > classEntry.highestDecisionPoints) { + classEntry.highestDecisionPoints = methodDecisionPoints; + } + + if (showMethodsComplexity && methodEntry.decisionPoints >= reportLevel) { + String methodType = (node.getNode().getMethodInfo().isConstructor()) ? "constructor" : "method"; + addViolation(data, node, + new String[] { methodType, node.getImage(), String.valueOf(methodEntry.decisionPoints) }); + } + } + return data; + } + + @Override + public Object visit(ASTIfBlockStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTForLoopStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTForEachStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTWhileLoopStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTDoLoopStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTTernaryExpression node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTBooleanExpression node, Object data) { + return data; + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/TooManyFieldsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/TooManyFieldsRule.java index e753ea6e80..34b8350192 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/TooManyFieldsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/TooManyFieldsRule.java @@ -1,77 +1,77 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.complexity; - -import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.FINAL; -import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.STATIC; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.lang.apex.ast.ASTField; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; -import net.sourceforge.pmd.util.NumericConstants; - -public class TooManyFieldsRule extends AbstractApexRule { - - private static final int DEFAULT_MAXFIELDS = 15; - - private Map stats; - private Map nodes; - - private static final IntegerProperty MAX_FIELDS_DESCRIPTOR = new IntegerProperty("maxfields", - "Max allowable fields", 1, 300, DEFAULT_MAXFIELDS, 1.0f); - - public TooManyFieldsRule() { - definePropertyDescriptor(MAX_FIELDS_DESCRIPTOR); - - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 200); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - - int maxFields = getProperty(MAX_FIELDS_DESCRIPTOR); - - stats = new HashMap<>(5); - nodes = new HashMap<>(5); - - List l = node.findDescendantsOfType(ASTField.class); - - for (ASTField fd : l) { - if (fd.getNode().getModifierInfo().all(FINAL, STATIC)) { - continue; - } - ASTUserClass clazz = fd.getFirstParentOfType(ASTUserClass.class); - if (clazz != null) { - bumpCounterFor(clazz); - } - } - for (Map.Entry entry : stats.entrySet()) { - int val = entry.getValue(); - Node n = nodes.get(entry.getKey()); - if (val > maxFields) { - addViolation(data, n); - } - } - return data; - } - - private void bumpCounterFor(ASTUserClass clazz) { - String key = clazz.getImage(); - if (!stats.containsKey(key)) { - stats.put(key, NumericConstants.ZERO); - nodes.put(key, clazz); - } - Integer i = Integer.valueOf(stats.get(key) + 1); - stats.put(key, i); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.complexity; + +import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.FINAL; +import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.STATIC; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.lang.apex.ast.ASTField; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; +import net.sourceforge.pmd.util.NumericConstants; + +public class TooManyFieldsRule extends AbstractApexRule { + + private static final int DEFAULT_MAXFIELDS = 15; + + private Map stats; + private Map nodes; + + private static final IntegerProperty MAX_FIELDS_DESCRIPTOR = new IntegerProperty("maxfields", + "Max allowable fields", 1, 300, DEFAULT_MAXFIELDS, 1.0f); + + public TooManyFieldsRule() { + definePropertyDescriptor(MAX_FIELDS_DESCRIPTOR); + + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Complexity" }); + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 200); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + @Override + public Object visit(ASTUserClass node, Object data) { + + int maxFields = getProperty(MAX_FIELDS_DESCRIPTOR); + + stats = new HashMap<>(5); + nodes = new HashMap<>(5); + + List l = node.findDescendantsOfType(ASTField.class); + + for (ASTField fd : l) { + if (fd.getNode().getModifierInfo().all(FINAL, STATIC)) { + continue; + } + ASTUserClass clazz = fd.getFirstParentOfType(ASTUserClass.class); + if (clazz != null) { + bumpCounterFor(clazz); + } + } + for (Map.Entry entry : stats.entrySet()) { + int val = entry.getValue(); + Node n = nodes.get(entry.getKey()); + if (val > maxFields) { + addViolation(data, n); + } + } + return data; + } + + private void bumpCounterFor(ASTUserClass clazz) { + String key = clazz.getImage(); + if (!stats.containsKey(key)) { + stats.put(key, NumericConstants.ZERO); + nodes.put(key, clazz); + } + Integer i = Integer.valueOf(stats.get(key) + 1); + stats.put(key, i); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/ClassNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/ClassNamingConventionsRule.java index b5677f6f7d..15895262be 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/ClassNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/ClassNamingConventionsRule.java @@ -1,33 +1,33 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.style; - -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; - -public class ClassNamingConventionsRule extends AbstractApexRule { - - public ClassNamingConventionsRule() { - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); - // Note: x10 as Apex has not automatic refactoring - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 5); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - public Object visit(ASTUserClass node, Object data) { - if (Character.isLowerCase(node.getImage().charAt(0))) { - addViolation(data, node); - } - return data; - } - - public Object visit(ASTUserInterface node, Object data) { - if (Character.isLowerCase(node.getImage().charAt(0))) { - addViolation(data, node); - } - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.style; + +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; + +public class ClassNamingConventionsRule extends AbstractApexRule { + + public ClassNamingConventionsRule() { + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); + // Note: x10 as Apex has not automatic refactoring + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 5); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + public Object visit(ASTUserClass node, Object data) { + if (Character.isLowerCase(node.getImage().charAt(0))) { + addViolation(data, node); + } + return data; + } + + public Object visit(ASTUserInterface node, Object data) { + if (Character.isLowerCase(node.getImage().charAt(0))) { + addViolation(data, node); + } + return data; + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodNamingConventionsRule.java index ffc2a63dad..08b78c6b3d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodNamingConventionsRule.java @@ -1,54 +1,54 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.style; - -import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.OVERRIDE; - -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTProperty; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; - -public class MethodNamingConventionsRule extends AbstractApexRule { - - public MethodNamingConventionsRule() { - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); - // Note: x10 as Apex has not automatic refactoring - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 1); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - public Object visit(ASTUserClass node, Object data) { - return super.visit(node, data); - } - - public Object visit(ASTMethod node, Object data) { - if (isOverriddenMethod(node) || isPropertyAccessor(node) || isConstructor(node)) { - return data; - } - - String methodName = node.getImage(); - - if (Character.isUpperCase(methodName.charAt(0))) { - addViolationWithMessage(data, node, "Method names should not start with capital letters"); - } - if (methodName.indexOf('_') >= 0) { - addViolationWithMessage(data, node, "Method names should not contain underscores"); - } - return data; - } - - private boolean isOverriddenMethod(ASTMethod node) { - return node.getNode().getModifiers().has(OVERRIDE); - } - - private boolean isPropertyAccessor(ASTMethod node) { - return (node.getParentsOfType(ASTProperty.class).size() > 0); - } - - private boolean isConstructor(ASTMethod node) { - return (node.getNode().getMethodInfo().isConstructor()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.style; + +import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.OVERRIDE; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTProperty; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; + +public class MethodNamingConventionsRule extends AbstractApexRule { + + public MethodNamingConventionsRule() { + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); + // Note: x10 as Apex has not automatic refactoring + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 1); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + public Object visit(ASTUserClass node, Object data) { + return super.visit(node, data); + } + + public Object visit(ASTMethod node, Object data) { + if (isOverriddenMethod(node) || isPropertyAccessor(node) || isConstructor(node)) { + return data; + } + + String methodName = node.getImage(); + + if (Character.isUpperCase(methodName.charAt(0))) { + addViolationWithMessage(data, node, "Method names should not start with capital letters"); + } + if (methodName.indexOf('_') >= 0) { + addViolationWithMessage(data, node, "Method names should not contain underscores"); + } + return data; + } + + private boolean isOverriddenMethod(ASTMethod node) { + return node.getNode().getModifiers().has(OVERRIDE); + } + + private boolean isPropertyAccessor(ASTMethod node) { + return (node.getParentsOfType(ASTProperty.class).size() > 0); + } + + private boolean isConstructor(ASTMethod node) { + return (node.getNode().getMethodInfo().isConstructor()); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodWithSameNameAsEnclosingClassRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodWithSameNameAsEnclosingClassRule.java index e0b21f11e4..ea0544d0c2 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodWithSameNameAsEnclosingClassRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/MethodWithSameNameAsEnclosingClassRule.java @@ -1,38 +1,38 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.style; - -import java.util.List; - -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; - -public class MethodWithSameNameAsEnclosingClassRule extends AbstractApexRule { - - public MethodWithSameNameAsEnclosingClassRule() { - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); - // Note: x10 as Apex has not automatic refactoring - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 50); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - String className = node.getImage(); - - List methods = node.findDescendantsOfType(ASTMethod.class); - - for (ASTMethod m : methods) { - String methodName = m.getImage(); - - if (!m.getNode().getMethodInfo().isConstructor() && methodName.equalsIgnoreCase(className)) { - addViolation(data, m); - } - } - - return super.visit(node, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.style; + +import java.util.List; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; + +public class MethodWithSameNameAsEnclosingClassRule extends AbstractApexRule { + + public MethodWithSameNameAsEnclosingClassRule() { + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); + // Note: x10 as Apex has not automatic refactoring + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 50); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + @Override + public Object visit(ASTUserClass node, Object data) { + String className = node.getImage(); + + List methods = node.findDescendantsOfType(ASTMethod.class); + + for (ASTMethod m : methods) { + String methodName = m.getImage(); + + if (!m.getNode().getMethodInfo().isConstructor() && methodName.equalsIgnoreCase(className)) { + addViolation(data, m); + } + } + + return super.visit(node, data); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/VariableNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/VariableNamingConventionsRule.java index b60c8afe46..4efeebaa67 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/VariableNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/style/VariableNamingConventionsRule.java @@ -1,221 +1,221 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.style; - -import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.FINAL; -import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.STATIC; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.lang.apex.ast.ASTField; -import net.sourceforge.pmd.lang.apex.ast.ASTParameter; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; -import net.sourceforge.pmd.util.CollectionUtil; - -public class VariableNamingConventionsRule extends AbstractApexRule { - - private boolean checkMembers; - private boolean checkLocals; - private boolean checkParameters; - private String[] staticPrefixes; - private String[] staticSuffixes; - private String[] memberPrefixes; - private String[] memberSuffixes; - private String[] localPrefixes; - private String[] localSuffixes; - private String[] parameterPrefixes; - private String[] parameterSuffixes; - - private static final BooleanProperty CHECK_MEMBERS_DESCRIPTOR = new BooleanProperty("checkMembers", - "Check member variables", true, 1.0f); - - private static final BooleanProperty CHECK_LOCALS_DESCRIPTOR = new BooleanProperty("checkLocals", - "Check local variables", true, 2.0f); - - private static final BooleanProperty CHECK_PARAMETERS_DESCRIPTOR = new BooleanProperty("checkParameters", - "Check constructor and method parameter variables", true, 3.0f); - - private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix", - "Static variable prefixes", new String[] { "" }, 4.0f, ','); - - private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix", - "Static variable suffixes", new String[] { "" }, 5.0f, ','); - - private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix", - "Member variable prefixes", new String[] { "" }, 6.0f, ','); - - private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix", - "Member variable suffixes", new String[] { "" }, 7.0f, ','); - - private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix", - "Local variable prefixes", new String[] { "" }, 8.0f, ','); - - private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix", - "Local variable suffixes", new String[] { "" }, 9.0f, ','); - - private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix", - "Method parameter variable prefixes", new String[] { "" }, 10.0f, ','); - - private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix", - "Method parameter variable suffixes", new String[] { "" }, 11.0f, ','); - - public VariableNamingConventionsRule() { - definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR); - definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR); - definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR); - definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR); - - setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); - // Note: x10 as Apex has not automatic refactoring - setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 5); - setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); - } - - public Object visit(ASTUserClass node, Object data) { - init(); - return super.visit(node, data); - } - - public Object visit(ASTUserInterface node, Object data) { - init(); - return super.visit(node, data); - } - - protected void init() { - checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR); - checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR); - checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR); - staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR); - staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR); - memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR); - memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR); - localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR); - localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR); - parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR); - parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR); - } - - public Object visit(ASTField node, Object data) { - if (!checkMembers) { - return data; - } - boolean isStatic = node.getNode().getFieldInfo().getModifiers().has(STATIC); - boolean isFinal = node.getNode().getFieldInfo().getModifiers().has(FINAL); - - return checkName(isStatic ? staticPrefixes : memberPrefixes, isStatic ? staticSuffixes : memberSuffixes, node, - isStatic, isFinal, data); - } - - public Object visit(ASTVariableDeclaration node, Object data) { - - if (!checkLocals) { - return data; - } - - boolean isFinal = node.getNode().getLocalInfo().getModifiers().has(FINAL); - return checkName(localPrefixes, localSuffixes, node, false, isFinal, data); - } - - public Object visit(ASTParameter node, Object data) { - if (!checkParameters) { - return data; - } - - boolean isFinal = node.getNode().getModifierInfo().has(FINAL); - return checkName(parameterPrefixes, parameterSuffixes, node, false, isFinal, data); - } - - private Object checkName(String[] prefixes, String[] suffixes, ApexNode node, boolean isStatic, boolean isFinal, - Object data) { - - String varName = node.getImage(); - - // Skip on null (with exception classes) and serialVersionUID - if (varName == null || "serialVersionUID".equals(varName)) { - return data; - } - - // Static finals should be uppercase - if (isStatic && isFinal) { - if (!varName.equals(varName.toUpperCase())) { - addViolationWithMessage(data, node, - "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.", - new Object[] { varName }); - } - return data; - } else if (!isFinal) { - String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes); - - if (normalizedVarName.indexOf('_') >= 0) { - addViolationWithMessage(data, node, - "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.", - new Object[] { varName }); - } - if (Character.isUpperCase(varName.charAt(0))) { - addViolationWithMessage(data, node, - "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.", - new Object[] { varName }); - } - } - return data; - } - - private String normalizeVariableName(String varName, String[] prefixes, String[] suffixes) { - return stripSuffix(stripPrefix(varName, prefixes), suffixes); - } - - private String stripSuffix(String varName, String[] suffixes) { - if (suffixes != null) { - for (int i = 0; i < suffixes.length; i++) { - if (varName.endsWith(suffixes[i])) { - varName = varName.substring(0, varName.length() - suffixes[i].length()); - break; - } - } - } - return varName; - } - - private String stripPrefix(String varName, String[] prefixes) { - if (prefixes != null) { - for (int i = 0; i < prefixes.length; i++) { - if (varName.startsWith(prefixes[i])) { - return varName.substring(prefixes[i].length()); - } - } - } - return varName; - } - - public boolean hasPrefixesOrSuffixes() { - - for (PropertyDescriptor desc : getPropertyDescriptors()) { - if (desc instanceof StringMultiProperty) { - String[] values = getProperty((StringMultiProperty) desc); - if (CollectionUtil.isNotEmpty(values)) { - return true; - } - } - } - return false; - } - - public String dysfunctionReason() { - return hasPrefixesOrSuffixes() ? null : "No prefixes or suffixes specified"; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.style; + +import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.FINAL; +import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.STATIC; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.lang.apex.ast.ASTField; +import net.sourceforge.pmd.lang.apex.ast.ASTParameter; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; +import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; +import net.sourceforge.pmd.util.CollectionUtil; + +public class VariableNamingConventionsRule extends AbstractApexRule { + + private boolean checkMembers; + private boolean checkLocals; + private boolean checkParameters; + private String[] staticPrefixes; + private String[] staticSuffixes; + private String[] memberPrefixes; + private String[] memberSuffixes; + private String[] localPrefixes; + private String[] localSuffixes; + private String[] parameterPrefixes; + private String[] parameterSuffixes; + + private static final BooleanProperty CHECK_MEMBERS_DESCRIPTOR = new BooleanProperty("checkMembers", + "Check member variables", true, 1.0f); + + private static final BooleanProperty CHECK_LOCALS_DESCRIPTOR = new BooleanProperty("checkLocals", + "Check local variables", true, 2.0f); + + private static final BooleanProperty CHECK_PARAMETERS_DESCRIPTOR = new BooleanProperty("checkParameters", + "Check constructor and method parameter variables", true, 3.0f); + + private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix", + "Static variable prefixes", new String[] { "" }, 4.0f, ','); + + private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix", + "Static variable suffixes", new String[] { "" }, 5.0f, ','); + + private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix", + "Member variable prefixes", new String[] { "" }, 6.0f, ','); + + private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix", + "Member variable suffixes", new String[] { "" }, 7.0f, ','); + + private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix", + "Local variable prefixes", new String[] { "" }, 8.0f, ','); + + private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix", + "Local variable suffixes", new String[] { "" }, 9.0f, ','); + + private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix", + "Method parameter variable prefixes", new String[] { "" }, 10.0f, ','); + + private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix", + "Method parameter variable suffixes", new String[] { "" }, 11.0f, ','); + + public VariableNamingConventionsRule() { + definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR); + definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR); + definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR); + definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR); + definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR); + definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR); + definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR); + + setProperty(CODECLIMATE_CATEGORIES, new String[] { "Style" }); + // Note: x10 as Apex has not automatic refactoring + setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 5); + setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); + } + + public Object visit(ASTUserClass node, Object data) { + init(); + return super.visit(node, data); + } + + public Object visit(ASTUserInterface node, Object data) { + init(); + return super.visit(node, data); + } + + protected void init() { + checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR); + checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR); + checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR); + staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR); + staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR); + memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR); + memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR); + localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR); + localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR); + parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR); + parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR); + } + + public Object visit(ASTField node, Object data) { + if (!checkMembers) { + return data; + } + boolean isStatic = node.getNode().getFieldInfo().getModifiers().has(STATIC); + boolean isFinal = node.getNode().getFieldInfo().getModifiers().has(FINAL); + + return checkName(isStatic ? staticPrefixes : memberPrefixes, isStatic ? staticSuffixes : memberSuffixes, node, + isStatic, isFinal, data); + } + + public Object visit(ASTVariableDeclaration node, Object data) { + + if (!checkLocals) { + return data; + } + + boolean isFinal = node.getNode().getLocalInfo().getModifiers().has(FINAL); + return checkName(localPrefixes, localSuffixes, node, false, isFinal, data); + } + + public Object visit(ASTParameter node, Object data) { + if (!checkParameters) { + return data; + } + + boolean isFinal = node.getNode().getModifierInfo().has(FINAL); + return checkName(parameterPrefixes, parameterSuffixes, node, false, isFinal, data); + } + + private Object checkName(String[] prefixes, String[] suffixes, ApexNode node, boolean isStatic, boolean isFinal, + Object data) { + + String varName = node.getImage(); + + // Skip on null (with exception classes) and serialVersionUID + if (varName == null || "serialVersionUID".equals(varName)) { + return data; + } + + // Static finals should be uppercase + if (isStatic && isFinal) { + if (!varName.equals(varName.toUpperCase())) { + addViolationWithMessage(data, node, + "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.", + new Object[] { varName }); + } + return data; + } else if (!isFinal) { + String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes); + + if (normalizedVarName.indexOf('_') >= 0) { + addViolationWithMessage(data, node, + "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.", + new Object[] { varName }); + } + if (Character.isUpperCase(varName.charAt(0))) { + addViolationWithMessage(data, node, + "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.", + new Object[] { varName }); + } + } + return data; + } + + private String normalizeVariableName(String varName, String[] prefixes, String[] suffixes) { + return stripSuffix(stripPrefix(varName, prefixes), suffixes); + } + + private String stripSuffix(String varName, String[] suffixes) { + if (suffixes != null) { + for (int i = 0; i < suffixes.length; i++) { + if (varName.endsWith(suffixes[i])) { + varName = varName.substring(0, varName.length() - suffixes[i].length()); + break; + } + } + } + return varName; + } + + private String stripPrefix(String varName, String[] prefixes) { + if (prefixes != null) { + for (int i = 0; i < prefixes.length; i++) { + if (varName.startsWith(prefixes[i])) { + return varName.substring(prefixes[i].length()); + } + } + } + return varName; + } + + public boolean hasPrefixesOrSuffixes() { + + for (PropertyDescriptor desc : getPropertyDescriptors()) { + if (desc instanceof StringMultiProperty) { + String[] values = getProperty((StringMultiProperty) desc); + if (CollectionUtil.isNotEmpty(values)) { + return true; + } + } + } + return false; + } + + public String dysfunctionReason() { + return hasPrefixesOrSuffixes() ? null : "No prefixes or suffixes specified"; + } + +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/LanguageVersionTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/LanguageVersionTest.java index c22ab6ee31..f668936b68 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/LanguageVersionTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/LanguageVersionTest.java @@ -1,27 +1,27 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.runners.Parameterized.Parameters; - -import net.sourceforge.pmd.AbstractLanguageVersionTest; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; - -public class LanguageVersionTest extends AbstractLanguageVersionTest { - - public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { - super(name, terseName, version, expected); - } - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { { ApexLanguageModule.NAME, ApexLanguageModule.TERSE_NAME, "35", - LanguageRegistry.getLanguage("Apex").getVersion("35"), }, }); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.runners.Parameterized.Parameters; + +import net.sourceforge.pmd.AbstractLanguageVersionTest; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; + +public class LanguageVersionTest extends AbstractLanguageVersionTest { + + public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { + super(name, terseName, version, expected); + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { { ApexLanguageModule.NAME, ApexLanguageModule.TERSE_NAME, "35", + LanguageRegistry.getLanguage("Apex").getVersion("35"), }, }); + } +} diff --git a/pmd-core/etc/grammar/dummy.jjt b/pmd-core/etc/grammar/dummy.jjt index 724ae0254c..46a09e2831 100644 --- a/pmd-core/etc/grammar/dummy.jjt +++ b/pmd-core/etc/grammar/dummy.jjt @@ -1,22 +1,22 @@ -/* This is a dummy JJTree used to generate the reusable aspects of JavaCC parsers. */ -options { - USER_CHAR_STREAM = true; -} - -PARSER_BEGIN(DummyParser) -package net.sourceforge.pmd.lang.ast.dummy; -public class DummyParser -{ -} -PARSER_END(DummyParser) - -TOKEN : -{ - -} - -ASTDummy Dummy() : -{} -{ - -} +/* This is a dummy JJTree used to generate the reusable aspects of JavaCC parsers. */ +options { + USER_CHAR_STREAM = true; +} + +PARSER_BEGIN(DummyParser) +package net.sourceforge.pmd.lang.ast.dummy; +public class DummyParser +{ +} +PARSER_END(DummyParser) + +TOKEN : +{ + +} + +ASTDummy Dummy() : +{} +{ + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java index 2bcfa5d7e9..c59ed57c77 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -1,600 +1,600 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - -import net.sourceforge.pmd.cache.AnalysisCache; -import net.sourceforge.pmd.cache.FileAnalysisCache; -import net.sourceforge.pmd.cache.NoopAnalysisCache; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; -import net.sourceforge.pmd.renderers.Renderer; -import net.sourceforge.pmd.renderers.RendererFactory; -import net.sourceforge.pmd.util.ClasspathClassLoader; -import net.sourceforge.pmd.util.IOUtil; - -/** - * This class contains the details for the runtime configuration of PMD. There - * are several aspects to the configuration of PMD. - * - *

The aspects related to generic PMD behavior:

- *
    - *
  • Suppress marker is used in source files to suppress a RuleViolation, - * defaults to {@link PMD#SUPPRESS_MARKER}. {@link #getSuppressMarker()}
  • - *
  • The number of threads to create when invoking on multiple files, defaults - * one thread per available processor. {@link #getThreads()}
  • - *
  • A ClassLoader to use when loading classes during Rule processing (e.g. - * during type resolution), defaults to ClassLoader of the Configuration class. - * {@link #getClassLoader()}
  • - *
  • A means to configure a ClassLoader using a prepended classpath String, - * instead of directly setting it programmatically. - * {@link #prependClasspath(String)}
  • - *
  • A LanguageVersionDiscoverer instance, which defaults to using the default - * LanguageVersion of each Language. Means are provided to change the - * LanguageVersion for each Language. - * {@link #getLanguageVersionDiscoverer()}
  • - *
- * - *

The aspects related to Rules and Source files are:

- *
    - *
  • A comma separated list of RuleSets URIs. {@link #getRuleSets()}
  • - *
  • A minimum priority threshold when loading Rules from RuleSets, defaults - * to {@link RulePriority#LOW}. {@link #getMinimumPriority()}
  • - *
  • The character encoding of source files, defaults to the system default as - * returned by System.getProperty("file.encoding"). - * {@link #getSourceEncoding()}
  • - *
  • A comma separated list of input paths to process for source files. This - * may include files, directories, archives (e.g. ZIP files), etc. - * {@link #getInputPaths()}
  • - *
  • A flag which controls, whether {@link RuleSetFactoryCompatibility} filter - * should be used or not: #isRuleSetFactoryCompatibilityEnabled; - *
- * - *
    - *
  • The renderer format to use for Reports. {@link #getReportFormat()}
  • - *
  • The file to which the Report should render. {@link #getReportFile()}
  • - *
  • An indicator of whether to use File short names in Reports, defaults to - * false. {@link #isReportShortNames()}
  • - *
  • The initialization properties to use when creating a Renderer instance. - * {@link #getReportProperties()}
  • - *
  • An indicator of whether to show suppressed Rule violations in Reports. - * {@link #isShowSuppressedViolations()}
  • - *
- * - *

The aspects related to special PMD behavior are:

- *
    - *
  • An indicator of whether PMD should log debug information. - * {@link #isDebug()}
  • - *
  • An indicator of whether PMD should perform stress testing behaviors, such - * as randomizing the order of file processing. {@link #isStressTest()}
  • - *
  • An indicator of whether PMD should log benchmarking information. - * {@link #isBenchmark()}
  • - *
- */ -public class PMDConfiguration extends AbstractConfiguration { - - // General behavior options - private String suppressMarker = PMD.SUPPRESS_MARKER; - private int threads = Runtime.getRuntime().availableProcessors(); - private ClassLoader classLoader = getClass().getClassLoader(); - private LanguageVersionDiscoverer languageVersionDiscoverer = new LanguageVersionDiscoverer(); - - // Rule and source file options - private String ruleSets; - private RulePriority minimumPriority = RulePriority.LOW; - private String inputPaths; - private String inputUri; - private String inputFilePath; - private boolean ruleSetFactoryCompatibilityEnabled = true; - - // Reporting options - private String reportFormat; - private String reportFile; - private boolean reportShortNames = false; - private Properties reportProperties = new Properties(); - private boolean showSuppressedViolations = false; - private boolean failOnViolation = true; - - private boolean stressTest; - private boolean benchmark; - private AnalysisCache analysisCache = new NoopAnalysisCache(); - - /** - * Get the suppress marker. This is the source level marker used to indicate - * a RuleViolation should be suppressed. - * - * @return The suppress marker. - */ - public String getSuppressMarker() { - return suppressMarker; - } - - /** - * Set the suppress marker. - * - * @param suppressMarker - * The suppress marker to use. - */ - public void setSuppressMarker(String suppressMarker) { - this.suppressMarker = suppressMarker; - } - - /** - * Get the number of threads to use when processing Rules. - * - * @return The number of threads. - */ - public int getThreads() { - return threads; - } - - /** - * Set the number of threads to use when processing Rules. - * - * @param threads - * The number of threads. - */ - public void setThreads(int threads) { - this.threads = threads; - } - - /** - * Get the ClassLoader being used by PMD when processing Rules. - * - * @return The ClassLoader being used - */ - public ClassLoader getClassLoader() { - return classLoader; - } - - /** - * Set the ClassLoader being used by PMD when processing Rules. Setting a - * value of null will cause the default ClassLoader to be used. - * - * @param classLoader - * The ClassLoader to use - */ - public void setClassLoader(ClassLoader classLoader) { - if (classLoader == null) { - this.classLoader = getClass().getClassLoader(); - } else { - this.classLoader = classLoader; - } - } - - /** - * Prepend the specified classpath like string to the current ClassLoader of - * the configuration. If no ClassLoader is currently configured, the - * ClassLoader used to load the {@link PMDConfiguration} class will be used - * as the parent ClassLoader of the created ClassLoader. - * - *

If the classpath String looks like a URL to a file (i.e. starts with - * file://) the file will be read with each line representing - * an entry on the classpath.

- * - * @param classpath - * The prepended classpath. - * @throws IOException - * if the given classpath is invalid (e.g. does not exist) - * @see PMDConfiguration#setClassLoader(ClassLoader) - * @see ClasspathClassLoader - */ - public void prependClasspath(String classpath) throws IOException { - if (classLoader == null) { - classLoader = PMDConfiguration.class.getClassLoader(); - } - if (classpath != null) { - classLoader = new ClasspathClassLoader(classpath, classLoader); - } - } - - /** - * Get the LanguageVersionDiscoverer, used to determine the LanguageVersion - * of a source file. - * - * @return The LanguageVersionDiscoverer. - */ - public LanguageVersionDiscoverer getLanguageVersionDiscoverer() { - return languageVersionDiscoverer; - } - - /** - * Set the given LanguageVersion as the current default for it's Language. - * - * @param languageVersion - * the LanguageVersion - */ - public void setDefaultLanguageVersion(LanguageVersion languageVersion) { - setDefaultLanguageVersions(Arrays.asList(languageVersion)); - } - - /** - * Set the given LanguageVersions as the current default for their - * Languages. - * - * @param languageVersions - * The LanguageVersions. - */ - public void setDefaultLanguageVersions(List languageVersions) { - for (LanguageVersion languageVersion : languageVersions) { - languageVersionDiscoverer.setDefaultLanguageVersion(languageVersion); - } - } - - /** - * Get the LanguageVersion of the source file with given name. This depends - * on the fileName extension, and the java version. - *

- * For compatibility with older code that does not always pass in a correct - * filename, unrecognized files are assumed to be java files. - *

- * - * @param fileName - * Name of the file, can be absolute, or simple. - * @return the LanguageVersion - */ - // FUTURE Delete this? I can't think of a good reason to keep it around. - // Failure to determine the LanguageVersion for a file should be a hard - // error, or simply cause the file to be skipped? - public LanguageVersion getLanguageVersionOfFile(String fileName) { - LanguageVersion languageVersion = languageVersionDiscoverer.getDefaultLanguageVersionForFile(fileName); - if (languageVersion == null) { - // For compatibility with older code that does not always pass in - // a correct filename. - languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getLanguage("Java")); - } - return languageVersion; - } - - /** - * Get the comma separated list of RuleSet URIs. - * - * @return The RuleSet URIs. - */ - public String getRuleSets() { - return ruleSets; - } - - /** - * Set the comma separated list of RuleSet URIs. - * - * @param ruleSets - * the rulesets to set - */ - public void setRuleSets(String ruleSets) { - this.ruleSets = ruleSets; - } - - /** - * Get the minimum priority threshold when loading Rules from RuleSets. - * - * @return The minimum priority threshold. - */ - public RulePriority getMinimumPriority() { - return minimumPriority; - } - - /** - * Set the minimum priority threshold when loading Rules from RuleSets. - * - * @param minimumPriority - * The minimum priority. - */ - public void setMinimumPriority(RulePriority minimumPriority) { - this.minimumPriority = minimumPriority; - } - - /** - * Get the comma separated list of input paths to process for source files. - * - * @return A comma separated list. - */ - public String getInputPaths() { - return inputPaths; - } - - /** - * Set the comma separated list of input paths to process for source files. - * - * @param inputPaths - * The comma separated list. - */ - public void setInputPaths(String inputPaths) { - this.inputPaths = inputPaths; - } - - public String getInputFilePath() { - return inputFilePath; - } - - /** - * The input file path points to a single file, which contains a - * comma-separated list of source file names to process. - * - * @param inputFilePath - * path to the file - */ - public void setInputFilePath(String inputFilePath) { - this.inputFilePath = inputFilePath; - } - - /** - * Get the input URI to process for source code objects. - * - * @return URI - */ - public String getInputUri() { - return inputUri; - } - - /** - * Set the input URI to process for source code objects. - * - * @param inputUri - * a single URI - */ - public void setInputUri(String inputUri) { - this.inputUri = inputUri; - } - - /** - * Get whether to use File short names in Reports. - * - * @return true when using short names in reports. - */ - public boolean isReportShortNames() { - return reportShortNames; - } - - /** - * Set whether to use File short names in Reports. - * - * @param reportShortNames - * true when using short names in reports. - */ - public void setReportShortNames(boolean reportShortNames) { - this.reportShortNames = reportShortNames; - } - - /** - * Create a Renderer instance based upon the configured reporting options. - * No writer is created. - * - * @return renderer - */ - public Renderer createRenderer() { - return createRenderer(false); - } - - /** - * Create a Renderer instance based upon the configured reporting options. - * If withReportWriter then we'll configure it with a writer for the - * reportFile specified. - * - * @param withReportWriter - * whether to configure a writer or not - * @return A Renderer instance. - */ - public Renderer createRenderer(boolean withReportWriter) { - Renderer renderer = RendererFactory.createRenderer(reportFormat, reportProperties); - renderer.setShowSuppressedViolations(showSuppressedViolations); - if (withReportWriter) { - renderer.setWriter(IOUtil.createWriter(reportFile)); - } - return renderer; - } - - /** - * Get the report format. - * - * @return The report format. - */ - public String getReportFormat() { - return reportFormat; - } - - /** - * Set the report format. This should be a name of a Renderer. - * - * @param reportFormat - * The report format. - * - * @see Renderer - */ - public void setReportFormat(String reportFormat) { - this.reportFormat = reportFormat; - } - - /** - * Get the file to which the report should render. - * - * @return The file to which to render. - */ - public String getReportFile() { - return reportFile; - } - - /** - * Set the file to which the report should render. - * - * @param reportFile - * the file to set - */ - public void setReportFile(String reportFile) { - this.reportFile = reportFile; - } - - /** - * Get whether the report should show suppressed violations. - * - * @return true if showing suppressed violations, - * false otherwise. - */ - public boolean isShowSuppressedViolations() { - return showSuppressedViolations; - } - - /** - * Set whether the report should show suppressed violations. - * - * @param showSuppressedViolations - * true if showing suppressed violations, - * false otherwise. - */ - public void setShowSuppressedViolations(boolean showSuppressedViolations) { - this.showSuppressedViolations = showSuppressedViolations; - } - - /** - * Get the Report properties. These are used to create the Renderer. - * - * @return The report properties. - */ - public Properties getReportProperties() { - return reportProperties; - } - - /** - * Set the Report properties. These are used to create the Renderer. - * - * @param reportProperties - * The Report properties to set. - */ - public void setReportProperties(Properties reportProperties) { - this.reportProperties = reportProperties; - } - - /** - * Return the stress test indicator. If this value is true then - * PMD will randomize the order of file processing to attempt to shake out - * bugs. - * - * @return true if stress test is enbaled, false - * otherwise. - */ - public boolean isStressTest() { - return stressTest; - } - - /** - * Set the stress test indicator. - * - * @param stressTest - * The stree test indicator to set. - * @see #isStressTest() - */ - public void setStressTest(boolean stressTest) { - this.stressTest = stressTest; - } - - /** - * Return the benchmark indicator. If this value is true then - * PMD will log benchmark information. - * - * @return true if benchmark logging is enbaled, - * false otherwise. - */ - public boolean isBenchmark() { - return benchmark; - } - - /** - * Set the benchmark indicator. - * - * @param benchmark - * The benchmark indicator to set. - * @see #isBenchmark() - */ - public void setBenchmark(boolean benchmark) { - this.benchmark = benchmark; - } - - /** - * Whether PMD should exit with status 4 (the default behavior, true) if - * violations are found or just with 0 (to not break the build, e.g.). - * - * @return failOnViolation - */ - public boolean isFailOnViolation() { - return failOnViolation; - } - - /** - * Sets whether PMD should exit with status 4 (the default behavior, true) - * if violations are found or just with 0 (to not break the build, e.g.). - * - * @param failOnViolation - * failOnViolation - */ - public void setFailOnViolation(boolean failOnViolation) { - this.failOnViolation = failOnViolation; - } - - /** - * Checks if the rule set factory compatibility feature is enabled. - * - * @return true, if the rule set factory compatibility feature is enabled - * - * @see RuleSetFactoryCompatibility - */ - public boolean isRuleSetFactoryCompatibilityEnabled() { - return ruleSetFactoryCompatibilityEnabled; - } - - /** - * Sets the rule set factory compatibility feature enabled/disabled. - * - * @param ruleSetFactoryCompatibilityEnabled - * true if the feature should be enabled - * - * @see RuleSetFactoryCompatibility - */ - public void setRuleSetFactoryCompatibilityEnabled(boolean ruleSetFactoryCompatibilityEnabled) { - this.ruleSetFactoryCompatibilityEnabled = ruleSetFactoryCompatibilityEnabled; - } - - /** - * Retrieves the currently used analysis cache. Will never be null. - * - * @return The currently used analysis cache. Never null. - */ - public AnalysisCache getAnalysisCache() { - return analysisCache; - } - - /** - * Sets the analysis cache to be used. Setting a - * value of null will cause a Noop AnalysisCache to be used. - * - * @param cache The analysis cache to be used. - */ - public void setAnalysisCache(final AnalysisCache cache) { - if (cache == null) { - analysisCache = new NoopAnalysisCache(); - } else { - analysisCache = cache; - } - } - - /** - * Sets the location of the analysis cache to be used. This will automatically configure - * and appropriate AnalysisCache implementation. - * - * @param cacheLocation The location of the analysis cache to be used. - */ - public void setAnalysisCacheLocation(final String cacheLocation) { - if (cacheLocation == null) { - setAnalysisCache(new NoopAnalysisCache()); - } else { - setAnalysisCache(new FileAnalysisCache(new File(cacheLocation))); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import net.sourceforge.pmd.cache.AnalysisCache; +import net.sourceforge.pmd.cache.FileAnalysisCache; +import net.sourceforge.pmd.cache.NoopAnalysisCache; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; +import net.sourceforge.pmd.renderers.Renderer; +import net.sourceforge.pmd.renderers.RendererFactory; +import net.sourceforge.pmd.util.ClasspathClassLoader; +import net.sourceforge.pmd.util.IOUtil; + +/** + * This class contains the details for the runtime configuration of PMD. There + * are several aspects to the configuration of PMD. + * + *

The aspects related to generic PMD behavior:

+ *
    + *
  • Suppress marker is used in source files to suppress a RuleViolation, + * defaults to {@link PMD#SUPPRESS_MARKER}. {@link #getSuppressMarker()}
  • + *
  • The number of threads to create when invoking on multiple files, defaults + * one thread per available processor. {@link #getThreads()}
  • + *
  • A ClassLoader to use when loading classes during Rule processing (e.g. + * during type resolution), defaults to ClassLoader of the Configuration class. + * {@link #getClassLoader()}
  • + *
  • A means to configure a ClassLoader using a prepended classpath String, + * instead of directly setting it programmatically. + * {@link #prependClasspath(String)}
  • + *
  • A LanguageVersionDiscoverer instance, which defaults to using the default + * LanguageVersion of each Language. Means are provided to change the + * LanguageVersion for each Language. + * {@link #getLanguageVersionDiscoverer()}
  • + *
+ * + *

The aspects related to Rules and Source files are:

+ *
    + *
  • A comma separated list of RuleSets URIs. {@link #getRuleSets()}
  • + *
  • A minimum priority threshold when loading Rules from RuleSets, defaults + * to {@link RulePriority#LOW}. {@link #getMinimumPriority()}
  • + *
  • The character encoding of source files, defaults to the system default as + * returned by System.getProperty("file.encoding"). + * {@link #getSourceEncoding()}
  • + *
  • A comma separated list of input paths to process for source files. This + * may include files, directories, archives (e.g. ZIP files), etc. + * {@link #getInputPaths()}
  • + *
  • A flag which controls, whether {@link RuleSetFactoryCompatibility} filter + * should be used or not: #isRuleSetFactoryCompatibilityEnabled; + *
+ * + *
    + *
  • The renderer format to use for Reports. {@link #getReportFormat()}
  • + *
  • The file to which the Report should render. {@link #getReportFile()}
  • + *
  • An indicator of whether to use File short names in Reports, defaults to + * false. {@link #isReportShortNames()}
  • + *
  • The initialization properties to use when creating a Renderer instance. + * {@link #getReportProperties()}
  • + *
  • An indicator of whether to show suppressed Rule violations in Reports. + * {@link #isShowSuppressedViolations()}
  • + *
+ * + *

The aspects related to special PMD behavior are:

+ *
    + *
  • An indicator of whether PMD should log debug information. + * {@link #isDebug()}
  • + *
  • An indicator of whether PMD should perform stress testing behaviors, such + * as randomizing the order of file processing. {@link #isStressTest()}
  • + *
  • An indicator of whether PMD should log benchmarking information. + * {@link #isBenchmark()}
  • + *
+ */ +public class PMDConfiguration extends AbstractConfiguration { + + // General behavior options + private String suppressMarker = PMD.SUPPRESS_MARKER; + private int threads = Runtime.getRuntime().availableProcessors(); + private ClassLoader classLoader = getClass().getClassLoader(); + private LanguageVersionDiscoverer languageVersionDiscoverer = new LanguageVersionDiscoverer(); + + // Rule and source file options + private String ruleSets; + private RulePriority minimumPriority = RulePriority.LOW; + private String inputPaths; + private String inputUri; + private String inputFilePath; + private boolean ruleSetFactoryCompatibilityEnabled = true; + + // Reporting options + private String reportFormat; + private String reportFile; + private boolean reportShortNames = false; + private Properties reportProperties = new Properties(); + private boolean showSuppressedViolations = false; + private boolean failOnViolation = true; + + private boolean stressTest; + private boolean benchmark; + private AnalysisCache analysisCache = new NoopAnalysisCache(); + + /** + * Get the suppress marker. This is the source level marker used to indicate + * a RuleViolation should be suppressed. + * + * @return The suppress marker. + */ + public String getSuppressMarker() { + return suppressMarker; + } + + /** + * Set the suppress marker. + * + * @param suppressMarker + * The suppress marker to use. + */ + public void setSuppressMarker(String suppressMarker) { + this.suppressMarker = suppressMarker; + } + + /** + * Get the number of threads to use when processing Rules. + * + * @return The number of threads. + */ + public int getThreads() { + return threads; + } + + /** + * Set the number of threads to use when processing Rules. + * + * @param threads + * The number of threads. + */ + public void setThreads(int threads) { + this.threads = threads; + } + + /** + * Get the ClassLoader being used by PMD when processing Rules. + * + * @return The ClassLoader being used + */ + public ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Set the ClassLoader being used by PMD when processing Rules. Setting a + * value of null will cause the default ClassLoader to be used. + * + * @param classLoader + * The ClassLoader to use + */ + public void setClassLoader(ClassLoader classLoader) { + if (classLoader == null) { + this.classLoader = getClass().getClassLoader(); + } else { + this.classLoader = classLoader; + } + } + + /** + * Prepend the specified classpath like string to the current ClassLoader of + * the configuration. If no ClassLoader is currently configured, the + * ClassLoader used to load the {@link PMDConfiguration} class will be used + * as the parent ClassLoader of the created ClassLoader. + * + *

If the classpath String looks like a URL to a file (i.e. starts with + * file://) the file will be read with each line representing + * an entry on the classpath.

+ * + * @param classpath + * The prepended classpath. + * @throws IOException + * if the given classpath is invalid (e.g. does not exist) + * @see PMDConfiguration#setClassLoader(ClassLoader) + * @see ClasspathClassLoader + */ + public void prependClasspath(String classpath) throws IOException { + if (classLoader == null) { + classLoader = PMDConfiguration.class.getClassLoader(); + } + if (classpath != null) { + classLoader = new ClasspathClassLoader(classpath, classLoader); + } + } + + /** + * Get the LanguageVersionDiscoverer, used to determine the LanguageVersion + * of a source file. + * + * @return The LanguageVersionDiscoverer. + */ + public LanguageVersionDiscoverer getLanguageVersionDiscoverer() { + return languageVersionDiscoverer; + } + + /** + * Set the given LanguageVersion as the current default for it's Language. + * + * @param languageVersion + * the LanguageVersion + */ + public void setDefaultLanguageVersion(LanguageVersion languageVersion) { + setDefaultLanguageVersions(Arrays.asList(languageVersion)); + } + + /** + * Set the given LanguageVersions as the current default for their + * Languages. + * + * @param languageVersions + * The LanguageVersions. + */ + public void setDefaultLanguageVersions(List languageVersions) { + for (LanguageVersion languageVersion : languageVersions) { + languageVersionDiscoverer.setDefaultLanguageVersion(languageVersion); + } + } + + /** + * Get the LanguageVersion of the source file with given name. This depends + * on the fileName extension, and the java version. + *

+ * For compatibility with older code that does not always pass in a correct + * filename, unrecognized files are assumed to be java files. + *

+ * + * @param fileName + * Name of the file, can be absolute, or simple. + * @return the LanguageVersion + */ + // FUTURE Delete this? I can't think of a good reason to keep it around. + // Failure to determine the LanguageVersion for a file should be a hard + // error, or simply cause the file to be skipped? + public LanguageVersion getLanguageVersionOfFile(String fileName) { + LanguageVersion languageVersion = languageVersionDiscoverer.getDefaultLanguageVersionForFile(fileName); + if (languageVersion == null) { + // For compatibility with older code that does not always pass in + // a correct filename. + languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getLanguage("Java")); + } + return languageVersion; + } + + /** + * Get the comma separated list of RuleSet URIs. + * + * @return The RuleSet URIs. + */ + public String getRuleSets() { + return ruleSets; + } + + /** + * Set the comma separated list of RuleSet URIs. + * + * @param ruleSets + * the rulesets to set + */ + public void setRuleSets(String ruleSets) { + this.ruleSets = ruleSets; + } + + /** + * Get the minimum priority threshold when loading Rules from RuleSets. + * + * @return The minimum priority threshold. + */ + public RulePriority getMinimumPriority() { + return minimumPriority; + } + + /** + * Set the minimum priority threshold when loading Rules from RuleSets. + * + * @param minimumPriority + * The minimum priority. + */ + public void setMinimumPriority(RulePriority minimumPriority) { + this.minimumPriority = minimumPriority; + } + + /** + * Get the comma separated list of input paths to process for source files. + * + * @return A comma separated list. + */ + public String getInputPaths() { + return inputPaths; + } + + /** + * Set the comma separated list of input paths to process for source files. + * + * @param inputPaths + * The comma separated list. + */ + public void setInputPaths(String inputPaths) { + this.inputPaths = inputPaths; + } + + public String getInputFilePath() { + return inputFilePath; + } + + /** + * The input file path points to a single file, which contains a + * comma-separated list of source file names to process. + * + * @param inputFilePath + * path to the file + */ + public void setInputFilePath(String inputFilePath) { + this.inputFilePath = inputFilePath; + } + + /** + * Get the input URI to process for source code objects. + * + * @return URI + */ + public String getInputUri() { + return inputUri; + } + + /** + * Set the input URI to process for source code objects. + * + * @param inputUri + * a single URI + */ + public void setInputUri(String inputUri) { + this.inputUri = inputUri; + } + + /** + * Get whether to use File short names in Reports. + * + * @return true when using short names in reports. + */ + public boolean isReportShortNames() { + return reportShortNames; + } + + /** + * Set whether to use File short names in Reports. + * + * @param reportShortNames + * true when using short names in reports. + */ + public void setReportShortNames(boolean reportShortNames) { + this.reportShortNames = reportShortNames; + } + + /** + * Create a Renderer instance based upon the configured reporting options. + * No writer is created. + * + * @return renderer + */ + public Renderer createRenderer() { + return createRenderer(false); + } + + /** + * Create a Renderer instance based upon the configured reporting options. + * If withReportWriter then we'll configure it with a writer for the + * reportFile specified. + * + * @param withReportWriter + * whether to configure a writer or not + * @return A Renderer instance. + */ + public Renderer createRenderer(boolean withReportWriter) { + Renderer renderer = RendererFactory.createRenderer(reportFormat, reportProperties); + renderer.setShowSuppressedViolations(showSuppressedViolations); + if (withReportWriter) { + renderer.setWriter(IOUtil.createWriter(reportFile)); + } + return renderer; + } + + /** + * Get the report format. + * + * @return The report format. + */ + public String getReportFormat() { + return reportFormat; + } + + /** + * Set the report format. This should be a name of a Renderer. + * + * @param reportFormat + * The report format. + * + * @see Renderer + */ + public void setReportFormat(String reportFormat) { + this.reportFormat = reportFormat; + } + + /** + * Get the file to which the report should render. + * + * @return The file to which to render. + */ + public String getReportFile() { + return reportFile; + } + + /** + * Set the file to which the report should render. + * + * @param reportFile + * the file to set + */ + public void setReportFile(String reportFile) { + this.reportFile = reportFile; + } + + /** + * Get whether the report should show suppressed violations. + * + * @return true if showing suppressed violations, + * false otherwise. + */ + public boolean isShowSuppressedViolations() { + return showSuppressedViolations; + } + + /** + * Set whether the report should show suppressed violations. + * + * @param showSuppressedViolations + * true if showing suppressed violations, + * false otherwise. + */ + public void setShowSuppressedViolations(boolean showSuppressedViolations) { + this.showSuppressedViolations = showSuppressedViolations; + } + + /** + * Get the Report properties. These are used to create the Renderer. + * + * @return The report properties. + */ + public Properties getReportProperties() { + return reportProperties; + } + + /** + * Set the Report properties. These are used to create the Renderer. + * + * @param reportProperties + * The Report properties to set. + */ + public void setReportProperties(Properties reportProperties) { + this.reportProperties = reportProperties; + } + + /** + * Return the stress test indicator. If this value is true then + * PMD will randomize the order of file processing to attempt to shake out + * bugs. + * + * @return true if stress test is enbaled, false + * otherwise. + */ + public boolean isStressTest() { + return stressTest; + } + + /** + * Set the stress test indicator. + * + * @param stressTest + * The stree test indicator to set. + * @see #isStressTest() + */ + public void setStressTest(boolean stressTest) { + this.stressTest = stressTest; + } + + /** + * Return the benchmark indicator. If this value is true then + * PMD will log benchmark information. + * + * @return true if benchmark logging is enbaled, + * false otherwise. + */ + public boolean isBenchmark() { + return benchmark; + } + + /** + * Set the benchmark indicator. + * + * @param benchmark + * The benchmark indicator to set. + * @see #isBenchmark() + */ + public void setBenchmark(boolean benchmark) { + this.benchmark = benchmark; + } + + /** + * Whether PMD should exit with status 4 (the default behavior, true) if + * violations are found or just with 0 (to not break the build, e.g.). + * + * @return failOnViolation + */ + public boolean isFailOnViolation() { + return failOnViolation; + } + + /** + * Sets whether PMD should exit with status 4 (the default behavior, true) + * if violations are found or just with 0 (to not break the build, e.g.). + * + * @param failOnViolation + * failOnViolation + */ + public void setFailOnViolation(boolean failOnViolation) { + this.failOnViolation = failOnViolation; + } + + /** + * Checks if the rule set factory compatibility feature is enabled. + * + * @return true, if the rule set factory compatibility feature is enabled + * + * @see RuleSetFactoryCompatibility + */ + public boolean isRuleSetFactoryCompatibilityEnabled() { + return ruleSetFactoryCompatibilityEnabled; + } + + /** + * Sets the rule set factory compatibility feature enabled/disabled. + * + * @param ruleSetFactoryCompatibilityEnabled + * true if the feature should be enabled + * + * @see RuleSetFactoryCompatibility + */ + public void setRuleSetFactoryCompatibilityEnabled(boolean ruleSetFactoryCompatibilityEnabled) { + this.ruleSetFactoryCompatibilityEnabled = ruleSetFactoryCompatibilityEnabled; + } + + /** + * Retrieves the currently used analysis cache. Will never be null. + * + * @return The currently used analysis cache. Never null. + */ + public AnalysisCache getAnalysisCache() { + return analysisCache; + } + + /** + * Sets the analysis cache to be used. Setting a + * value of null will cause a Noop AnalysisCache to be used. + * + * @param cache The analysis cache to be used. + */ + public void setAnalysisCache(final AnalysisCache cache) { + if (cache == null) { + analysisCache = new NoopAnalysisCache(); + } else { + analysisCache = cache; + } + } + + /** + * Sets the location of the analysis cache to be used. This will automatically configure + * and appropriate AnalysisCache implementation. + * + * @param cacheLocation The location of the analysis cache to be used. + */ + public void setAnalysisCacheLocation(final String cacheLocation) { + if (cacheLocation == null) { + setAnalysisCache(new NoopAnalysisCache()); + } else { + setAnalysisCache(new FileAnalysisCache(new File(cacheLocation))); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java b/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java index 4ef99b380e..bdfd2c3882 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java @@ -1,97 +1,97 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -/** - * These are the possible Rule priority values. - * - * For backward compatibility, priorities range in value from 1 to 5, with 5 - * being the lowest priority. This means the ordinal value of the Enum should be - * avoided in favor of {@link RulePriority#getPriority()} and - * {@link RulePriority#valueOf(int)} - * - * @see How - * to define rules priority - */ -public enum RulePriority { - - /** High: Change absolutely required. Behavior is critically broken/buggy */ - HIGH(1, "High"), - /** - * Medium to high: Change highly recommended. Behavior is quite likely to be - * broken/buggy. - */ - MEDIUM_HIGH(2, "Medium High"), - /** - * Medium: Change recommended. Behavior is confusing, perhaps buggy, and/or - * against standards/best practices. - */ - MEDIUM(3, "Medium"), - /** - * Medium to low: Change optional. Behavior is not likely to be buggy, but - * more just flies in the face of standards/style/good taste. - */ - MEDIUM_LOW(4, "Medium Low"), - /** - * Low: Change highly optional. Nice to have, such as a consistent naming - * policy for package/class/fields... - */ - LOW(5, "Low"); - - private final int priority; - private final String name; - - RulePriority(int priority, String name) { - this.priority = priority; - this.name = name; - } - - /** - * Get the priority value as a number. This is the value to be used in the - * externalized form of a priority (e.g. in RuleSet XML). - * - * @return The int value of the priority. - */ - public int getPriority() { - return priority; - } - - /** - * Get the descriptive name of this priority. - * - * @return The descriptive name. - */ - public String getName() { - return name; - } - - /** - * Returns the descriptive name of the priority. - * - * @return descriptive name of the priority - * @see #getName() - */ - @Override - public String toString() { - return name; - } - - /** - * Get the priority which corresponds to the given number as returned by - * {@link RulePriority#getPriority()}. If the number is an invalid value, - * then {@link RulePriority#LOW} will be returned. - * - * @param priority - * The numeric priority value. - * @return The priority. - */ - public static RulePriority valueOf(int priority) { - try { - return RulePriority.values()[priority - 1]; - } catch (ArrayIndexOutOfBoundsException e) { - return LOW; - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +/** + * These are the possible Rule priority values. + * + * For backward compatibility, priorities range in value from 1 to 5, with 5 + * being the lowest priority. This means the ordinal value of the Enum should be + * avoided in favor of {@link RulePriority#getPriority()} and + * {@link RulePriority#valueOf(int)} + * + * @see How + * to define rules priority + */ +public enum RulePriority { + + /** High: Change absolutely required. Behavior is critically broken/buggy */ + HIGH(1, "High"), + /** + * Medium to high: Change highly recommended. Behavior is quite likely to be + * broken/buggy. + */ + MEDIUM_HIGH(2, "Medium High"), + /** + * Medium: Change recommended. Behavior is confusing, perhaps buggy, and/or + * against standards/best practices. + */ + MEDIUM(3, "Medium"), + /** + * Medium to low: Change optional. Behavior is not likely to be buggy, but + * more just flies in the face of standards/style/good taste. + */ + MEDIUM_LOW(4, "Medium Low"), + /** + * Low: Change highly optional. Nice to have, such as a consistent naming + * policy for package/class/fields... + */ + LOW(5, "Low"); + + private final int priority; + private final String name; + + RulePriority(int priority, String name) { + this.priority = priority; + this.name = name; + } + + /** + * Get the priority value as a number. This is the value to be used in the + * externalized form of a priority (e.g. in RuleSet XML). + * + * @return The int value of the priority. + */ + public int getPriority() { + return priority; + } + + /** + * Get the descriptive name of this priority. + * + * @return The descriptive name. + */ + public String getName() { + return name; + } + + /** + * Returns the descriptive name of the priority. + * + * @return descriptive name of the priority + * @see #getName() + */ + @Override + public String toString() { + return name; + } + + /** + * Get the priority which corresponds to the given number as returned by + * {@link RulePriority#getPriority()}. If the number is an invalid value, + * then {@link RulePriority#LOW} will be returned. + * + * @param priority + * The numeric priority value. + * @return The priority. + */ + public static RulePriority valueOf(int priority) { + try { + return RulePriority.values()[priority - 1]; + } catch (ArrayIndexOutOfBoundsException e) { + return LOW; + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReference.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReference.java index 8fa85c3d63..6a31100b87 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReference.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReference.java @@ -1,52 +1,52 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * This class represents a reference to RuleSet. - */ -public class RuleSetReference { - private String ruleSetFileName; - private boolean allRules; - private Set excludes = new LinkedHashSet<>(0); - - public RuleSetReference() { - } - - public RuleSetReference(String theFilename) { - ruleSetFileName = theFilename; - } - - public String getRuleSetFileName() { - return ruleSetFileName; - } - - public void setRuleSetFileName(String ruleSetFileName) { - this.ruleSetFileName = ruleSetFileName; - } - - public boolean isAllRules() { - return allRules; - } - - public void setAllRules(boolean allRules) { - this.allRules = allRules; - } - - public Set getExcludes() { - return excludes; - } - - public void setExcludes(Set excludes) { - this.excludes = excludes; - } - - public void addExclude(String name) { - this.excludes.add(name); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * This class represents a reference to RuleSet. + */ +public class RuleSetReference { + private String ruleSetFileName; + private boolean allRules; + private Set excludes = new LinkedHashSet<>(0); + + public RuleSetReference() { + } + + public RuleSetReference(String theFilename) { + ruleSetFileName = theFilename; + } + + public String getRuleSetFileName() { + return ruleSetFileName; + } + + public void setRuleSetFileName(String ruleSetFileName) { + this.ruleSetFileName = ruleSetFileName; + } + + public boolean isAllRules() { + return allRules; + } + + public void setAllRules(boolean allRules) { + this.allRules = allRules; + } + + public Set getExcludes() { + return excludes; + } + + public void setExcludes(Set excludes) { + this.excludes = excludes; + } + + public void addExclude(String name) { + this.excludes.add(name); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java index dc9d550342..dbf958d305 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java @@ -1,449 +1,449 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.util.ResourceLoader; -import net.sourceforge.pmd.util.StringUtil; - -/** - * This class is used to parse a RuleSet reference value. Most commonly used for - * specifying a RuleSet to process, or in a Rule 'ref' attribute value in the - * RuleSet XML. The RuleSet reference can refer to either an external RuleSet or - * the current RuleSet when used as a Rule 'ref' attribute value. An individual - * Rule in the RuleSet can be indicated. - * - * For an external RuleSet, referring to the entire RuleSet, the format is - * ruleSetName, where the RuleSet name is either a resource file path to - * a RuleSet that ends with '.xml', or a simple RuleSet name. - * - * A simple RuleSet name, is one which contains no path separators, and either - * contains a '-' or is entirely numeric release number. A simple name of the - * form [language]-[name] is short for the full RuleSet name - * rulesets/[language]/[name].xml. A numeric release simple name of - * the form [release] is short for the full PMD Release RuleSet - * name rulesets/releases/[release].xml. - * - * For an external RuleSet, referring to a single Rule, the format is - * ruleSetName/ruleName, where the RuleSet name is as described above. A - * Rule with the ruleName should exist in this external RuleSet. - * - * For the current RuleSet, the format is ruleName, where the Rule name - * is not RuleSet name (i.e. contains no path separators, '-' or '.xml' in it, - * and is not all numeric). A Rule with the ruleName should exist in the - * current RuleSet. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Examples
StringRuleSet file nameRule
rulesets/java/basic.xmlrulesets/java/basic.xmlall
java-basicrulesets/java/basic.xmlall
50rulesets/releases/50.xmlall
rulesets/java/basic.xml/EmptyCatchBlockrulesets/java/basic.xmlEmptyCatchBlock
EmptyCatchBlocknullEmptyCatchBlock
- */ -public class RuleSetReferenceId { - private final boolean external; - private final String ruleSetFileName; - private final boolean allRules; - private final String ruleName; - private final RuleSetReferenceId externalRuleSetReferenceId; - - /** - * Construct a RuleSetReferenceId for the given single ID string. - * - * @param id - * The id string. - * @throws IllegalArgumentException - * If the ID contains a comma character. - */ - public RuleSetReferenceId(final String id) { - - this(id, null); - } - - /** - * Construct a RuleSetReferenceId for the given single ID string. If an - * external RuleSetReferenceId is given, the ID must refer to a non-external - * Rule. The external RuleSetReferenceId will be responsible for producing - * the InputStream containing the Rule. - * - * @param id - * The id string. - * @param externalRuleSetReferenceId - * A RuleSetReferenceId to associate with this new instance. - * @throws IllegalArgumentException - * If the ID contains a comma character. - * @throws IllegalArgumentException - * If external RuleSetReferenceId is not external. - * @throws IllegalArgumentException - * If the ID is not Rule reference when there is an external - * RuleSetReferenceId. - */ - public RuleSetReferenceId(final String id, final RuleSetReferenceId externalRuleSetReferenceId) { - - if (externalRuleSetReferenceId != null && !externalRuleSetReferenceId.isExternal()) { - throw new IllegalArgumentException("Cannot pair with non-external <" + externalRuleSetReferenceId + ">."); - } - - if (id != null && id.indexOf(',') >= 0) { - throw new IllegalArgumentException( - "A single RuleSetReferenceId cannot contain ',' (comma) characters: " + id); - } - - // Damn this parsing sucks, but my brain is just not working to let me - // write a simpler scheme. - - if (isValidUrl(id)) { - // A full RuleSet name - external = true; - ruleSetFileName = StringUtils.strip(id); - allRules = true; - ruleName = null; - } else if (isFullRuleSetName(id)) { - // A full RuleSet name - external = true; - ruleSetFileName = id; - allRules = true; - ruleName = null; - } else { - String tempRuleName = getRuleName(id); - String tempRuleSetFileName = tempRuleName != null && id != null - ? id.substring(0, id.length() - tempRuleName.length() - 1) : id; - - if (isValidUrl(tempRuleSetFileName)) { - // remaining part is a xml ruleset file, so the tempRuleName is - // probably a real rule name - external = true; - ruleSetFileName = StringUtils.strip(tempRuleSetFileName); - ruleName = StringUtils.strip(tempRuleName); - allRules = tempRuleName == null; - } else if (isHttpUrl(id)) { - // it's a url, we can't determine whether it's a full ruleset or - // a single rule - so falling back to - // a full RuleSet name - external = true; - ruleSetFileName = StringUtils.strip(id); - allRules = true; - ruleName = null; - } else if (isFullRuleSetName(tempRuleSetFileName)) { - // remaining part is a xml ruleset file, so the tempRuleName is - // probably a real rule name - external = true; - ruleSetFileName = tempRuleSetFileName; - ruleName = tempRuleName; - allRules = tempRuleName == null; - } else { - // resolve the ruleset name - it's maybe a built in ruleset - String builtinRuleSet = resolveBuiltInRuleset(tempRuleSetFileName); - if (checkRulesetExists(builtinRuleSet)) { - external = true; - ruleSetFileName = builtinRuleSet; - ruleName = tempRuleName; - allRules = tempRuleName == null; - } else { - // well, we didn't find the ruleset, so it's probably not a - // internal ruleset. - // at this time, we don't know, whether the tempRuleName is - // a name of the rule - // or the file name of the ruleset file. - // It is assumed, that tempRuleName is actually the filename - // of the ruleset, - // if there are more separator characters in the remaining - // ruleset filename (tempRuleSetFileName). - // This means, the only reliable way to specify single rules - // within a custom rulesest file is - // only possible, if the ruleset file has a .xml file - // extension. - if (tempRuleSetFileName == null || tempRuleSetFileName.contains(File.separator)) { - external = true; - ruleSetFileName = id; - ruleName = null; - allRules = true; - } else { - external = externalRuleSetReferenceId != null ? externalRuleSetReferenceId.isExternal() : false; - ruleSetFileName = externalRuleSetReferenceId != null - ? externalRuleSetReferenceId.getRuleSetFileName() : null; - ruleName = id; - allRules = false; - } - } - } - } - - if (this.external && this.ruleName != null && !this.ruleName.equals(id) && externalRuleSetReferenceId != null) { - throw new IllegalArgumentException( - "Cannot pair external <" + this + "> with external <" + externalRuleSetReferenceId + ">."); - } - this.externalRuleSetReferenceId = externalRuleSetReferenceId; - } - - /** - * Tries to load the given ruleset. - * - * @param name - * the ruleset name - * @return true if the ruleset could be loaded, - * false otherwise. - */ - private boolean checkRulesetExists(String name) { - boolean resourceFound = false; - if (name != null) { - try { - InputStream resource = ResourceLoader.loadResourceAsStream(name, - RuleSetReferenceId.class.getClassLoader()); - if (resource != null) { - resourceFound = true; - IOUtils.closeQuietly(resource); - } - } catch (RuleSetNotFoundException e) { - resourceFound = false; - } - } - return resourceFound; - } - - /** - * Assumes that the ruleset name given is e.g. "java-basic". Then it will - * return the full classpath name for the ruleset, in this example it would - * return "rulesets/java/basic.xml". - * - * @param name - * the ruleset name - * @return the full classpath to the ruleset - */ - private String resolveBuiltInRuleset(final String name) { - String result = null; - if (name != null) { - // Likely a simple RuleSet name - int index = name.indexOf('-'); - if (index >= 0) { - // Standard short name - result = "rulesets/" + name.substring(0, index) + "/" + name.substring(index + 1) + ".xml"; - } else { - // A release RuleSet? - if (name.matches("[0-9]+.*")) { - result = "rulesets/releases/" + name + ".xml"; - } else { - // Appears to be a non-standard RuleSet name - result = name; - } - } - } - return result; - } - - /** - * Extracts the rule name out of a ruleset path. E.g. for - * "/my/ruleset.xml/MyRule" it would return "MyRule". If no single rule is - * specified, null is returned. - * - * @param rulesetName - * the full rule set path - * @return the rule name or null. - */ - private String getRuleName(final String rulesetName) { - String result = null; - if (rulesetName != null) { - // Find last path separator if it exists... this might be a rule - // name - final int separatorIndex = Math.max(rulesetName.lastIndexOf('/'), rulesetName.lastIndexOf('\\')); - if (separatorIndex >= 0 && separatorIndex != rulesetName.length() - 1) { - result = rulesetName.substring(separatorIndex + 1); - } - } - return result; - } - - private static boolean isHttpUrl(String name) { - String stripped = StringUtils.strip(name); - if (stripped == null) { - return false; - } - - if (stripped.startsWith("http://") || stripped.startsWith("https://")) { - return true; - } - - return false; - } - - private static boolean isValidUrl(String name) { - if (isHttpUrl(name)) { - String url = StringUtils.strip(name); - try { - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - connection.setRequestMethod("HEAD"); - connection.setConnectTimeout(ResourceLoader.TIMEOUT); - connection.setReadTimeout(ResourceLoader.TIMEOUT); - int responseCode = connection.getResponseCode(); - if (responseCode == 200) { - return true; - } - } catch (IOException e) { - return false; - } - } - return false; - } - - private static boolean isFullRuleSetName(String name) { - - return name != null && name.endsWith(".xml"); - } - - /** - * Parse a String comma separated list of RuleSet reference IDs into a List - * of RuleReferenceId instances. - * - * @param referenceString - * A comma separated list of RuleSet reference IDs. - * @return The corresponding List of RuleSetReferenceId instances. - */ - public static List parse(String referenceString) { - List references = new ArrayList<>(); - if (referenceString != null && referenceString.trim().length() > 0) { - - if (referenceString.indexOf(',') == -1) { - references.add(new RuleSetReferenceId(referenceString)); - } else { - for (String name : referenceString.split(",")) { - references.add(new RuleSetReferenceId(name.trim())); - } - } - } - return references; - } - - /** - * Is this an external RuleSet reference? - * - * @return true if this is an external reference, - * false otherwise. - */ - public boolean isExternal() { - return external; - } - - /** - * Is this a reference to all Rules in a RuleSet, or a single Rule? - * - * @return true if this is a reference to all Rules, - * false otherwise. - */ - public boolean isAllRules() { - return allRules; - } - - /** - * Get the RuleSet file name. - * - * @return The RuleSet file name if this is an external reference, - * null otherwise. - */ - public String getRuleSetFileName() { - return ruleSetFileName; - } - - /** - * Get the Rule name. - * - * @return The Rule name. The Rule name. - */ - public String getRuleName() { - return ruleName; - } - - /** - * Try to load the RuleSet resource with the specified ClassLoader. Multiple - * attempts to get independent InputStream instances may be made, so - * subclasses must ensure they support this behavior. Delegates to an - * external RuleSetReferenceId if there is one associated with this - * instance. - * - * @param classLoader - * The ClassLoader to use. - * @return An InputStream to that resource. - * @throws RuleSetNotFoundException - * if unable to find a resource. - */ - public InputStream getInputStream(ClassLoader classLoader) throws RuleSetNotFoundException { - if (externalRuleSetReferenceId == null) { - InputStream in = StringUtil.isEmpty(ruleSetFileName) ? null - : ResourceLoader.loadResourceAsStream(ruleSetFileName, classLoader); - if (in == null) { - throw new RuleSetNotFoundException("Can't find resource '" + ruleSetFileName + "' for rule '" + ruleName - + "'" + ". Make sure the resource is a valid file or URL and is on the CLASSPATH. " - + "Here's the current classpath: " + System.getProperty("java.class.path")); - } - return in; - } else { - return externalRuleSetReferenceId.getInputStream(classLoader); - } - } - - /** - * Return the String form of this Rule reference. - * - * @return Return the String form of this Rule reference, which is - * ruleSetFileName for all Rule external references, - * ruleSetFileName/ruleName, for a single Rule external - * references, or ruleName otherwise. - */ - @Override - public String toString() { - if (ruleSetFileName != null) { - if (allRules) { - return ruleSetFileName; - } else { - return ruleSetFileName + "/" + ruleName; - } - - } else { - if (allRules) { - return "anonymous all Rule"; - } else { - return ruleName; - } - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import net.sourceforge.pmd.util.ResourceLoader; +import net.sourceforge.pmd.util.StringUtil; + +/** + * This class is used to parse a RuleSet reference value. Most commonly used for + * specifying a RuleSet to process, or in a Rule 'ref' attribute value in the + * RuleSet XML. The RuleSet reference can refer to either an external RuleSet or + * the current RuleSet when used as a Rule 'ref' attribute value. An individual + * Rule in the RuleSet can be indicated. + * + * For an external RuleSet, referring to the entire RuleSet, the format is + * ruleSetName, where the RuleSet name is either a resource file path to + * a RuleSet that ends with '.xml', or a simple RuleSet name. + * + * A simple RuleSet name, is one which contains no path separators, and either + * contains a '-' or is entirely numeric release number. A simple name of the + * form [language]-[name] is short for the full RuleSet name + * rulesets/[language]/[name].xml. A numeric release simple name of + * the form [release] is short for the full PMD Release RuleSet + * name rulesets/releases/[release].xml. + * + * For an external RuleSet, referring to a single Rule, the format is + * ruleSetName/ruleName, where the RuleSet name is as described above. A + * Rule with the ruleName should exist in this external RuleSet. + * + * For the current RuleSet, the format is ruleName, where the Rule name + * is not RuleSet name (i.e. contains no path separators, '-' or '.xml' in it, + * and is not all numeric). A Rule with the ruleName should exist in the + * current RuleSet. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples
StringRuleSet file nameRule
rulesets/java/basic.xmlrulesets/java/basic.xmlall
java-basicrulesets/java/basic.xmlall
50rulesets/releases/50.xmlall
rulesets/java/basic.xml/EmptyCatchBlockrulesets/java/basic.xmlEmptyCatchBlock
EmptyCatchBlocknullEmptyCatchBlock
+ */ +public class RuleSetReferenceId { + private final boolean external; + private final String ruleSetFileName; + private final boolean allRules; + private final String ruleName; + private final RuleSetReferenceId externalRuleSetReferenceId; + + /** + * Construct a RuleSetReferenceId for the given single ID string. + * + * @param id + * The id string. + * @throws IllegalArgumentException + * If the ID contains a comma character. + */ + public RuleSetReferenceId(final String id) { + + this(id, null); + } + + /** + * Construct a RuleSetReferenceId for the given single ID string. If an + * external RuleSetReferenceId is given, the ID must refer to a non-external + * Rule. The external RuleSetReferenceId will be responsible for producing + * the InputStream containing the Rule. + * + * @param id + * The id string. + * @param externalRuleSetReferenceId + * A RuleSetReferenceId to associate with this new instance. + * @throws IllegalArgumentException + * If the ID contains a comma character. + * @throws IllegalArgumentException + * If external RuleSetReferenceId is not external. + * @throws IllegalArgumentException + * If the ID is not Rule reference when there is an external + * RuleSetReferenceId. + */ + public RuleSetReferenceId(final String id, final RuleSetReferenceId externalRuleSetReferenceId) { + + if (externalRuleSetReferenceId != null && !externalRuleSetReferenceId.isExternal()) { + throw new IllegalArgumentException("Cannot pair with non-external <" + externalRuleSetReferenceId + ">."); + } + + if (id != null && id.indexOf(',') >= 0) { + throw new IllegalArgumentException( + "A single RuleSetReferenceId cannot contain ',' (comma) characters: " + id); + } + + // Damn this parsing sucks, but my brain is just not working to let me + // write a simpler scheme. + + if (isValidUrl(id)) { + // A full RuleSet name + external = true; + ruleSetFileName = StringUtils.strip(id); + allRules = true; + ruleName = null; + } else if (isFullRuleSetName(id)) { + // A full RuleSet name + external = true; + ruleSetFileName = id; + allRules = true; + ruleName = null; + } else { + String tempRuleName = getRuleName(id); + String tempRuleSetFileName = tempRuleName != null && id != null + ? id.substring(0, id.length() - tempRuleName.length() - 1) : id; + + if (isValidUrl(tempRuleSetFileName)) { + // remaining part is a xml ruleset file, so the tempRuleName is + // probably a real rule name + external = true; + ruleSetFileName = StringUtils.strip(tempRuleSetFileName); + ruleName = StringUtils.strip(tempRuleName); + allRules = tempRuleName == null; + } else if (isHttpUrl(id)) { + // it's a url, we can't determine whether it's a full ruleset or + // a single rule - so falling back to + // a full RuleSet name + external = true; + ruleSetFileName = StringUtils.strip(id); + allRules = true; + ruleName = null; + } else if (isFullRuleSetName(tempRuleSetFileName)) { + // remaining part is a xml ruleset file, so the tempRuleName is + // probably a real rule name + external = true; + ruleSetFileName = tempRuleSetFileName; + ruleName = tempRuleName; + allRules = tempRuleName == null; + } else { + // resolve the ruleset name - it's maybe a built in ruleset + String builtinRuleSet = resolveBuiltInRuleset(tempRuleSetFileName); + if (checkRulesetExists(builtinRuleSet)) { + external = true; + ruleSetFileName = builtinRuleSet; + ruleName = tempRuleName; + allRules = tempRuleName == null; + } else { + // well, we didn't find the ruleset, so it's probably not a + // internal ruleset. + // at this time, we don't know, whether the tempRuleName is + // a name of the rule + // or the file name of the ruleset file. + // It is assumed, that tempRuleName is actually the filename + // of the ruleset, + // if there are more separator characters in the remaining + // ruleset filename (tempRuleSetFileName). + // This means, the only reliable way to specify single rules + // within a custom rulesest file is + // only possible, if the ruleset file has a .xml file + // extension. + if (tempRuleSetFileName == null || tempRuleSetFileName.contains(File.separator)) { + external = true; + ruleSetFileName = id; + ruleName = null; + allRules = true; + } else { + external = externalRuleSetReferenceId != null ? externalRuleSetReferenceId.isExternal() : false; + ruleSetFileName = externalRuleSetReferenceId != null + ? externalRuleSetReferenceId.getRuleSetFileName() : null; + ruleName = id; + allRules = false; + } + } + } + } + + if (this.external && this.ruleName != null && !this.ruleName.equals(id) && externalRuleSetReferenceId != null) { + throw new IllegalArgumentException( + "Cannot pair external <" + this + "> with external <" + externalRuleSetReferenceId + ">."); + } + this.externalRuleSetReferenceId = externalRuleSetReferenceId; + } + + /** + * Tries to load the given ruleset. + * + * @param name + * the ruleset name + * @return true if the ruleset could be loaded, + * false otherwise. + */ + private boolean checkRulesetExists(String name) { + boolean resourceFound = false; + if (name != null) { + try { + InputStream resource = ResourceLoader.loadResourceAsStream(name, + RuleSetReferenceId.class.getClassLoader()); + if (resource != null) { + resourceFound = true; + IOUtils.closeQuietly(resource); + } + } catch (RuleSetNotFoundException e) { + resourceFound = false; + } + } + return resourceFound; + } + + /** + * Assumes that the ruleset name given is e.g. "java-basic". Then it will + * return the full classpath name for the ruleset, in this example it would + * return "rulesets/java/basic.xml". + * + * @param name + * the ruleset name + * @return the full classpath to the ruleset + */ + private String resolveBuiltInRuleset(final String name) { + String result = null; + if (name != null) { + // Likely a simple RuleSet name + int index = name.indexOf('-'); + if (index >= 0) { + // Standard short name + result = "rulesets/" + name.substring(0, index) + "/" + name.substring(index + 1) + ".xml"; + } else { + // A release RuleSet? + if (name.matches("[0-9]+.*")) { + result = "rulesets/releases/" + name + ".xml"; + } else { + // Appears to be a non-standard RuleSet name + result = name; + } + } + } + return result; + } + + /** + * Extracts the rule name out of a ruleset path. E.g. for + * "/my/ruleset.xml/MyRule" it would return "MyRule". If no single rule is + * specified, null is returned. + * + * @param rulesetName + * the full rule set path + * @return the rule name or null. + */ + private String getRuleName(final String rulesetName) { + String result = null; + if (rulesetName != null) { + // Find last path separator if it exists... this might be a rule + // name + final int separatorIndex = Math.max(rulesetName.lastIndexOf('/'), rulesetName.lastIndexOf('\\')); + if (separatorIndex >= 0 && separatorIndex != rulesetName.length() - 1) { + result = rulesetName.substring(separatorIndex + 1); + } + } + return result; + } + + private static boolean isHttpUrl(String name) { + String stripped = StringUtils.strip(name); + if (stripped == null) { + return false; + } + + if (stripped.startsWith("http://") || stripped.startsWith("https://")) { + return true; + } + + return false; + } + + private static boolean isValidUrl(String name) { + if (isHttpUrl(name)) { + String url = StringUtils.strip(name); + try { + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + connection.setRequestMethod("HEAD"); + connection.setConnectTimeout(ResourceLoader.TIMEOUT); + connection.setReadTimeout(ResourceLoader.TIMEOUT); + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + return true; + } + } catch (IOException e) { + return false; + } + } + return false; + } + + private static boolean isFullRuleSetName(String name) { + + return name != null && name.endsWith(".xml"); + } + + /** + * Parse a String comma separated list of RuleSet reference IDs into a List + * of RuleReferenceId instances. + * + * @param referenceString + * A comma separated list of RuleSet reference IDs. + * @return The corresponding List of RuleSetReferenceId instances. + */ + public static List parse(String referenceString) { + List references = new ArrayList<>(); + if (referenceString != null && referenceString.trim().length() > 0) { + + if (referenceString.indexOf(',') == -1) { + references.add(new RuleSetReferenceId(referenceString)); + } else { + for (String name : referenceString.split(",")) { + references.add(new RuleSetReferenceId(name.trim())); + } + } + } + return references; + } + + /** + * Is this an external RuleSet reference? + * + * @return true if this is an external reference, + * false otherwise. + */ + public boolean isExternal() { + return external; + } + + /** + * Is this a reference to all Rules in a RuleSet, or a single Rule? + * + * @return true if this is a reference to all Rules, + * false otherwise. + */ + public boolean isAllRules() { + return allRules; + } + + /** + * Get the RuleSet file name. + * + * @return The RuleSet file name if this is an external reference, + * null otherwise. + */ + public String getRuleSetFileName() { + return ruleSetFileName; + } + + /** + * Get the Rule name. + * + * @return The Rule name. The Rule name. + */ + public String getRuleName() { + return ruleName; + } + + /** + * Try to load the RuleSet resource with the specified ClassLoader. Multiple + * attempts to get independent InputStream instances may be made, so + * subclasses must ensure they support this behavior. Delegates to an + * external RuleSetReferenceId if there is one associated with this + * instance. + * + * @param classLoader + * The ClassLoader to use. + * @return An InputStream to that resource. + * @throws RuleSetNotFoundException + * if unable to find a resource. + */ + public InputStream getInputStream(ClassLoader classLoader) throws RuleSetNotFoundException { + if (externalRuleSetReferenceId == null) { + InputStream in = StringUtil.isEmpty(ruleSetFileName) ? null + : ResourceLoader.loadResourceAsStream(ruleSetFileName, classLoader); + if (in == null) { + throw new RuleSetNotFoundException("Can't find resource '" + ruleSetFileName + "' for rule '" + ruleName + + "'" + ". Make sure the resource is a valid file or URL and is on the CLASSPATH. " + + "Here's the current classpath: " + System.getProperty("java.class.path")); + } + return in; + } else { + return externalRuleSetReferenceId.getInputStream(classLoader); + } + } + + /** + * Return the String form of this Rule reference. + * + * @return Return the String form of this Rule reference, which is + * ruleSetFileName for all Rule external references, + * ruleSetFileName/ruleName, for a single Rule external + * references, or ruleName otherwise. + */ + @Override + public String toString() { + if (ruleSetFileName != null) { + if (allRules) { + return ruleSetFileName; + } else { + return ruleSetFileName + "/" + ruleName; + } + + } else { + if (allRules) { + return "anonymous all Rule"; + } else { + return ruleName; + } + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java index 96bfefe61c..8df757af97 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java @@ -1,412 +1,412 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.io.OutputStream; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.FactoryConfigurationError; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.apache.commons.io.IOUtils; -import org.w3c.dom.CDATASection; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Text; - -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.rule.ImmutableLanguage; -import net.sourceforge.pmd.lang.rule.RuleReference; -import net.sourceforge.pmd.lang.rule.XPathRule; -import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; -import net.sourceforge.pmd.lang.rule.properties.factories.PropertyDescriptorUtil; - -/** - * This class represents a way to serialize a RuleSet to an XML configuration - * file. - */ -public class RuleSetWriter { - - public static final String RULESET_NS_URI = "http://pmd.sourceforge.net/ruleset/2.0.0"; - - private final OutputStream outputStream; - private Document document; - private Set ruleSetFileNames; - - public RuleSetWriter(OutputStream outputStream) { - this.outputStream = outputStream; - } - - public void close() { - IOUtils.closeQuietly(outputStream); - } - - public void write(RuleSet ruleSet) { - try { - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - documentBuilderFactory.setNamespaceAware(true); - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - document = documentBuilder.newDocument(); - ruleSetFileNames = new HashSet<>(); - - Element ruleSetElement = createRuleSetElement(ruleSet); - document.appendChild(ruleSetElement); - - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - try { - transformerFactory.setAttribute("indent-number", 3); - } catch (IllegalArgumentException iae) { - // ignore it, specific to one parser - } - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.METHOD, "xml"); - // This is as close to pretty printing as we'll get using standard - // Java APIs. - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.transform(new DOMSource(document), new StreamResult(outputStream)); - } catch (DOMException e) { - throw new RuntimeException(e); - } catch (FactoryConfigurationError e) { - throw new RuntimeException(e); - } catch (ParserConfigurationException e) { - throw new RuntimeException(e); - } catch (TransformerException e) { - throw new RuntimeException(e); - } - } - - private Element createRuleSetElement(RuleSet ruleSet) { - Element ruleSetElement = document.createElementNS(RULESET_NS_URI, "ruleset"); - ruleSetElement.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); - ruleSetElement.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", - RULESET_NS_URI + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd"); - ruleSetElement.setAttribute("name", ruleSet.getName()); - - Element descriptionElement = createDescriptionElement(ruleSet.getDescription()); - ruleSetElement.appendChild(descriptionElement); - - for (String excludePattern : ruleSet.getExcludePatterns()) { - Element excludePatternElement = createExcludePatternElement(excludePattern); - ruleSetElement.appendChild(excludePatternElement); - } - for (String includePattern : ruleSet.getIncludePatterns()) { - Element includePatternElement = createIncludePatternElement(includePattern); - ruleSetElement.appendChild(includePatternElement); - } - for (Rule rule : ruleSet.getRules()) { - Element ruleElement = createRuleElement(rule); - if (ruleElement != null) { - ruleSetElement.appendChild(ruleElement); - } - } - - return ruleSetElement; - } - - private Element createDescriptionElement(String description) { - return createTextElement("description", description); - } - - private Element createExcludePatternElement(String excludePattern) { - return createTextElement("exclude-pattern", excludePattern); - } - - private Element createIncludePatternElement(String includePattern) { - return createTextElement("include-pattern", includePattern); - } - - private Element createRuleElement() { - return document.createElementNS(RULESET_NS_URI, "rule"); - } - - private Element createExcludeElement(String exclude) { - Element element = document.createElementNS(RULESET_NS_URI, "exclude"); - element.setAttribute("name", exclude); - return element; - } - - private Element createExampleElement(String example) { - return createCDATASectionElement("example", example); - } - - private Element createPriorityElement(RulePriority priority) { - return createTextElement("priority", String.valueOf(priority.getPriority())); - } - - private Element createPropertiesElement() { - return document.createElementNS(RULESET_NS_URI, "properties"); - } - - private Element createRuleElement(Rule rule) { - if (rule instanceof RuleReference) { - RuleReference ruleReference = (RuleReference) rule; - RuleSetReference ruleSetReference = ruleReference.getRuleSetReference(); - if (ruleSetReference.isAllRules()) { - if (!ruleSetFileNames.contains(ruleSetReference.getRuleSetFileName())) { - ruleSetFileNames.add(ruleSetReference.getRuleSetFileName()); - Element ruleSetReferenceElement = createRuleSetReferenceElement(ruleSetReference); - return ruleSetReferenceElement; - } else { - return null; - } - } else { - Language language = ruleReference.getOverriddenLanguage(); - LanguageVersion minimumLanguageVersion = ruleReference.getOverriddenMinimumLanguageVersion(); - LanguageVersion maximumLanguageVersion = ruleReference.getOverriddenMaximumLanguageVersion(); - Boolean deprecated = ruleReference.isOverriddenDeprecated(); - String name = ruleReference.getOverriddenName(); - String ref = ruleReference.getRuleSetReference().getRuleSetFileName() + "/" - + ruleReference.getRule().getName(); - String message = ruleReference.getOverriddenMessage(); - String externalInfoUrl = ruleReference.getOverriddenExternalInfoUrl(); - String description = ruleReference.getOverriddenDescription(); - RulePriority priority = ruleReference.getOverriddenPriority(); - List> propertyDescriptors = ruleReference.getOverriddenPropertyDescriptors(); - Map, Object> propertiesByPropertyDescriptor = ruleReference - .getOverriddenPropertiesByPropertyDescriptor(); - List examples = ruleReference.getOverriddenExamples(); - - return createSingleRuleElement(language, minimumLanguageVersion, maximumLanguageVersion, deprecated, - name, null, ref, message, externalInfoUrl, null, null, null, description, priority, - propertyDescriptors, propertiesByPropertyDescriptor, examples); - } - } else { - return createSingleRuleElement(rule instanceof ImmutableLanguage ? null : rule.getLanguage(), - rule.getMinimumLanguageVersion(), rule.getMaximumLanguageVersion(), rule.isDeprecated(), - rule.getName(), rule.getSince(), null, rule.getMessage(), rule.getExternalInfoUrl(), - rule.getRuleClass(), rule.usesDFA(), rule.usesTypeResolution(), rule.getDescription(), - rule.getPriority(), rule.getPropertyDescriptors(), rule.getPropertiesByPropertyDescriptor(), - rule.getExamples()); - } - } - - private void setIfNonNull(Object value, Element target, String id) { - if (value != null) { - target.setAttribute(id, value.toString()); - } - } - - private Element createSingleRuleElement(Language language, LanguageVersion minimumLanguageVersion, - LanguageVersion maximumLanguageVersion, Boolean deprecated, String name, String since, String ref, - String message, String externalInfoUrl, String clazz, Boolean dfa, Boolean typeResolution, - String description, RulePriority priority, List> propertyDescriptors, - Map, Object> propertiesByPropertyDescriptor, List examples) { - Element ruleElement = createRuleElement(); - if (language != null) { - ruleElement.setAttribute("language", language.getTerseName()); - } - if (minimumLanguageVersion != null) { - ruleElement.setAttribute("minimumLanguageVersion", minimumLanguageVersion.getVersion()); - } - if (maximumLanguageVersion != null) { - ruleElement.setAttribute("maximumLanguageVersion", maximumLanguageVersion.getVersion()); - } - - setIfNonNull(deprecated, ruleElement, "deprecated"); - setIfNonNull(name, ruleElement, "name"); - setIfNonNull(since, ruleElement, "since"); - setIfNonNull(ref, ruleElement, "ref"); - setIfNonNull(message, ruleElement, "message"); - setIfNonNull(clazz, ruleElement, "class"); - setIfNonNull(externalInfoUrl, ruleElement, "externalInfoUrl"); - setIfNonNull(dfa, ruleElement, "dfa"); - setIfNonNull(typeResolution, ruleElement, "typeResolution"); - - if (description != null) { - Element descriptionElement = createDescriptionElement(description); - ruleElement.appendChild(descriptionElement); - } - if (priority != null) { - Element priorityElement = createPriorityElement(priority); - ruleElement.appendChild(priorityElement); - } - Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor); - if (propertiesElement != null) { - ruleElement.appendChild(propertiesElement); - } - if (examples != null) { - for (String example : examples) { - Element exampleElement = createExampleElement(example); - ruleElement.appendChild(exampleElement); - } - } - return ruleElement; - } - - private Element createRuleSetReferenceElement(RuleSetReference ruleSetReference) { - Element ruleSetReferenceElement = createRuleElement(); - ruleSetReferenceElement.setAttribute("ref", ruleSetReference.getRuleSetFileName()); - for (String exclude : ruleSetReference.getExcludes()) { - Element excludeElement = createExcludeElement(exclude); - ruleSetReferenceElement.appendChild(excludeElement); - } - return ruleSetReferenceElement; - } - - @SuppressWarnings("PMD.CompareObjectsWithEquals") - private Element createPropertiesElement(List> propertyDescriptors, - Map, Object> propertiesByPropertyDescriptor) { - - Element propertiesElement = null; - if (propertyDescriptors != null) { - - for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // For - // each - // provided - // PropertyDescriptor - - if (propertyDescriptor instanceof PropertyDescriptorWrapper) { // Any - // wrapper - // property - // needs - // to - // go - // out - // as - // a - // definition. - if (propertiesElement == null) { - propertiesElement = createPropertiesElement(); - } - - Element propertyElement = createPropertyDefinitionElementBR( - ((PropertyDescriptorWrapper) propertyDescriptor).getPropertyDescriptor()); - propertiesElement.appendChild(propertyElement); - } else { - if (propertiesByPropertyDescriptor != null) { // Otherwise, - // any - // property - // which has a - // value - // different - // than the - // default - // needs to go - // out as a - // value. - Object defaultValue = propertyDescriptor.defaultValue(); - Object value = propertiesByPropertyDescriptor.get(propertyDescriptor); - if (value != defaultValue && (value == null || !value.equals(defaultValue))) { - if (propertiesElement == null) { - propertiesElement = createPropertiesElement(); - } - - Element propertyElement = createPropertyValueElement(propertyDescriptor, value); - propertiesElement.appendChild(propertyElement); - } - } - } - } - } - - if (propertiesByPropertyDescriptor != null) { - // Then, for each PropertyDescriptor not explicitly provided - for (Map.Entry, Object> entry : propertiesByPropertyDescriptor.entrySet()) { - // If not explicitly given... - PropertyDescriptor propertyDescriptor = entry.getKey(); - if (!propertyDescriptors.contains(propertyDescriptor)) { - // Otherwise, any property which has a value different than - // the - // default needs to go out as a value. - Object defaultValue = propertyDescriptor.defaultValue(); - Object value = entry.getValue(); - if (value != defaultValue && (value == null || !value.equals(defaultValue))) { - if (propertiesElement == null) { - propertiesElement = createPropertiesElement(); - } - Element propertyElement = createPropertyValueElement(propertyDescriptor, value); - propertiesElement.appendChild(propertyElement); - } - } - } - } - return propertiesElement; - } - - private Element createPropertyValueElement(PropertyDescriptor propertyDescriptor, Object value) { - Element propertyElement = document.createElementNS(RULESET_NS_URI, "property"); - propertyElement.setAttribute("name", propertyDescriptor.name()); - String valueString = propertyDescriptor.asDelimitedString(value); - if (XPathRule.XPATH_DESCRIPTOR.equals(propertyDescriptor)) { - Element valueElement = createCDATASectionElement("value", valueString); - propertyElement.appendChild(valueElement); - } else { - propertyElement.setAttribute("value", valueString); - } - - return propertyElement; - } - - // private Element createPropertyDefinitionElement(PropertyDescriptor - // propertyDescriptor) { - // Element propertyElement = createPropertyValueElement(propertyDescriptor, - // propertyDescriptor.defaultValue()); - // - // propertyElement.setAttribute("description", - // propertyDescriptor.description()); - // String type = - // PropertyDescriptorFactory.getPropertyDescriptorType(propertyDescriptor); - // propertyElement.setAttribute("type", type); - // - // if (propertyDescriptor.isMultiValue()) { - // propertyElement.setAttribute("delimiter", - // String.valueOf(propertyDescriptor.multiValueDelimiter())); - // } - // - // if (propertyDescriptor instanceof AbstractNumericProperty) { - // propertyElement.setAttribute("min", - // String.valueOf(((AbstractNumericProperty) - // propertyDescriptor).lowerLimit())); - // propertyElement.setAttribute("max", - // String.valueOf(((AbstractNumericProperty) - // propertyDescriptor).upperLimit())); - // } - // - // return propertyElement; - // } - - private Element createPropertyDefinitionElementBR(PropertyDescriptor propertyDescriptor) { - - final Element propertyElement = createPropertyValueElement(propertyDescriptor, - propertyDescriptor.defaultValue()); - propertyElement.setAttribute(PropertyDescriptorFields.TYPE, - PropertyDescriptorUtil.typeIdFor(propertyDescriptor.type())); - - Map propertyValuesById = propertyDescriptor.attributeValuesById(); - for (Map.Entry entry : propertyValuesById.entrySet()) { - propertyElement.setAttribute(entry.getKey(), entry.getValue()); - } - - return propertyElement; - } - - private Element createTextElement(String name, String value) { - Element element = document.createElementNS(RULESET_NS_URI, name); - Text text = document.createTextNode(value); - element.appendChild(text); - return element; - } - - private Element createCDATASectionElement(String name, String value) { - Element element = document.createElementNS(RULESET_NS_URI, name); - CDATASection cdataSection = document.createCDATASection(value); - element.appendChild(cdataSection); - return element; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.io.OutputStream; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.io.IOUtils; +import org.w3c.dom.CDATASection; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Text; + +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.rule.ImmutableLanguage; +import net.sourceforge.pmd.lang.rule.RuleReference; +import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; +import net.sourceforge.pmd.lang.rule.properties.factories.PropertyDescriptorUtil; + +/** + * This class represents a way to serialize a RuleSet to an XML configuration + * file. + */ +public class RuleSetWriter { + + public static final String RULESET_NS_URI = "http://pmd.sourceforge.net/ruleset/2.0.0"; + + private final OutputStream outputStream; + private Document document; + private Set ruleSetFileNames; + + public RuleSetWriter(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public void close() { + IOUtils.closeQuietly(outputStream); + } + + public void write(RuleSet ruleSet) { + try { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + document = documentBuilder.newDocument(); + ruleSetFileNames = new HashSet<>(); + + Element ruleSetElement = createRuleSetElement(ruleSet); + document.appendChild(ruleSetElement); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + try { + transformerFactory.setAttribute("indent-number", 3); + } catch (IllegalArgumentException iae) { + // ignore it, specific to one parser + } + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + // This is as close to pretty printing as we'll get using standard + // Java APIs. + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.transform(new DOMSource(document), new StreamResult(outputStream)); + } catch (DOMException e) { + throw new RuntimeException(e); + } catch (FactoryConfigurationError e) { + throw new RuntimeException(e); + } catch (ParserConfigurationException e) { + throw new RuntimeException(e); + } catch (TransformerException e) { + throw new RuntimeException(e); + } + } + + private Element createRuleSetElement(RuleSet ruleSet) { + Element ruleSetElement = document.createElementNS(RULESET_NS_URI, "ruleset"); + ruleSetElement.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + ruleSetElement.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", + RULESET_NS_URI + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd"); + ruleSetElement.setAttribute("name", ruleSet.getName()); + + Element descriptionElement = createDescriptionElement(ruleSet.getDescription()); + ruleSetElement.appendChild(descriptionElement); + + for (String excludePattern : ruleSet.getExcludePatterns()) { + Element excludePatternElement = createExcludePatternElement(excludePattern); + ruleSetElement.appendChild(excludePatternElement); + } + for (String includePattern : ruleSet.getIncludePatterns()) { + Element includePatternElement = createIncludePatternElement(includePattern); + ruleSetElement.appendChild(includePatternElement); + } + for (Rule rule : ruleSet.getRules()) { + Element ruleElement = createRuleElement(rule); + if (ruleElement != null) { + ruleSetElement.appendChild(ruleElement); + } + } + + return ruleSetElement; + } + + private Element createDescriptionElement(String description) { + return createTextElement("description", description); + } + + private Element createExcludePatternElement(String excludePattern) { + return createTextElement("exclude-pattern", excludePattern); + } + + private Element createIncludePatternElement(String includePattern) { + return createTextElement("include-pattern", includePattern); + } + + private Element createRuleElement() { + return document.createElementNS(RULESET_NS_URI, "rule"); + } + + private Element createExcludeElement(String exclude) { + Element element = document.createElementNS(RULESET_NS_URI, "exclude"); + element.setAttribute("name", exclude); + return element; + } + + private Element createExampleElement(String example) { + return createCDATASectionElement("example", example); + } + + private Element createPriorityElement(RulePriority priority) { + return createTextElement("priority", String.valueOf(priority.getPriority())); + } + + private Element createPropertiesElement() { + return document.createElementNS(RULESET_NS_URI, "properties"); + } + + private Element createRuleElement(Rule rule) { + if (rule instanceof RuleReference) { + RuleReference ruleReference = (RuleReference) rule; + RuleSetReference ruleSetReference = ruleReference.getRuleSetReference(); + if (ruleSetReference.isAllRules()) { + if (!ruleSetFileNames.contains(ruleSetReference.getRuleSetFileName())) { + ruleSetFileNames.add(ruleSetReference.getRuleSetFileName()); + Element ruleSetReferenceElement = createRuleSetReferenceElement(ruleSetReference); + return ruleSetReferenceElement; + } else { + return null; + } + } else { + Language language = ruleReference.getOverriddenLanguage(); + LanguageVersion minimumLanguageVersion = ruleReference.getOverriddenMinimumLanguageVersion(); + LanguageVersion maximumLanguageVersion = ruleReference.getOverriddenMaximumLanguageVersion(); + Boolean deprecated = ruleReference.isOverriddenDeprecated(); + String name = ruleReference.getOverriddenName(); + String ref = ruleReference.getRuleSetReference().getRuleSetFileName() + "/" + + ruleReference.getRule().getName(); + String message = ruleReference.getOverriddenMessage(); + String externalInfoUrl = ruleReference.getOverriddenExternalInfoUrl(); + String description = ruleReference.getOverriddenDescription(); + RulePriority priority = ruleReference.getOverriddenPriority(); + List> propertyDescriptors = ruleReference.getOverriddenPropertyDescriptors(); + Map, Object> propertiesByPropertyDescriptor = ruleReference + .getOverriddenPropertiesByPropertyDescriptor(); + List examples = ruleReference.getOverriddenExamples(); + + return createSingleRuleElement(language, minimumLanguageVersion, maximumLanguageVersion, deprecated, + name, null, ref, message, externalInfoUrl, null, null, null, description, priority, + propertyDescriptors, propertiesByPropertyDescriptor, examples); + } + } else { + return createSingleRuleElement(rule instanceof ImmutableLanguage ? null : rule.getLanguage(), + rule.getMinimumLanguageVersion(), rule.getMaximumLanguageVersion(), rule.isDeprecated(), + rule.getName(), rule.getSince(), null, rule.getMessage(), rule.getExternalInfoUrl(), + rule.getRuleClass(), rule.usesDFA(), rule.usesTypeResolution(), rule.getDescription(), + rule.getPriority(), rule.getPropertyDescriptors(), rule.getPropertiesByPropertyDescriptor(), + rule.getExamples()); + } + } + + private void setIfNonNull(Object value, Element target, String id) { + if (value != null) { + target.setAttribute(id, value.toString()); + } + } + + private Element createSingleRuleElement(Language language, LanguageVersion minimumLanguageVersion, + LanguageVersion maximumLanguageVersion, Boolean deprecated, String name, String since, String ref, + String message, String externalInfoUrl, String clazz, Boolean dfa, Boolean typeResolution, + String description, RulePriority priority, List> propertyDescriptors, + Map, Object> propertiesByPropertyDescriptor, List examples) { + Element ruleElement = createRuleElement(); + if (language != null) { + ruleElement.setAttribute("language", language.getTerseName()); + } + if (minimumLanguageVersion != null) { + ruleElement.setAttribute("minimumLanguageVersion", minimumLanguageVersion.getVersion()); + } + if (maximumLanguageVersion != null) { + ruleElement.setAttribute("maximumLanguageVersion", maximumLanguageVersion.getVersion()); + } + + setIfNonNull(deprecated, ruleElement, "deprecated"); + setIfNonNull(name, ruleElement, "name"); + setIfNonNull(since, ruleElement, "since"); + setIfNonNull(ref, ruleElement, "ref"); + setIfNonNull(message, ruleElement, "message"); + setIfNonNull(clazz, ruleElement, "class"); + setIfNonNull(externalInfoUrl, ruleElement, "externalInfoUrl"); + setIfNonNull(dfa, ruleElement, "dfa"); + setIfNonNull(typeResolution, ruleElement, "typeResolution"); + + if (description != null) { + Element descriptionElement = createDescriptionElement(description); + ruleElement.appendChild(descriptionElement); + } + if (priority != null) { + Element priorityElement = createPriorityElement(priority); + ruleElement.appendChild(priorityElement); + } + Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor); + if (propertiesElement != null) { + ruleElement.appendChild(propertiesElement); + } + if (examples != null) { + for (String example : examples) { + Element exampleElement = createExampleElement(example); + ruleElement.appendChild(exampleElement); + } + } + return ruleElement; + } + + private Element createRuleSetReferenceElement(RuleSetReference ruleSetReference) { + Element ruleSetReferenceElement = createRuleElement(); + ruleSetReferenceElement.setAttribute("ref", ruleSetReference.getRuleSetFileName()); + for (String exclude : ruleSetReference.getExcludes()) { + Element excludeElement = createExcludeElement(exclude); + ruleSetReferenceElement.appendChild(excludeElement); + } + return ruleSetReferenceElement; + } + + @SuppressWarnings("PMD.CompareObjectsWithEquals") + private Element createPropertiesElement(List> propertyDescriptors, + Map, Object> propertiesByPropertyDescriptor) { + + Element propertiesElement = null; + if (propertyDescriptors != null) { + + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // For + // each + // provided + // PropertyDescriptor + + if (propertyDescriptor instanceof PropertyDescriptorWrapper) { // Any + // wrapper + // property + // needs + // to + // go + // out + // as + // a + // definition. + if (propertiesElement == null) { + propertiesElement = createPropertiesElement(); + } + + Element propertyElement = createPropertyDefinitionElementBR( + ((PropertyDescriptorWrapper) propertyDescriptor).getPropertyDescriptor()); + propertiesElement.appendChild(propertyElement); + } else { + if (propertiesByPropertyDescriptor != null) { // Otherwise, + // any + // property + // which has a + // value + // different + // than the + // default + // needs to go + // out as a + // value. + Object defaultValue = propertyDescriptor.defaultValue(); + Object value = propertiesByPropertyDescriptor.get(propertyDescriptor); + if (value != defaultValue && (value == null || !value.equals(defaultValue))) { + if (propertiesElement == null) { + propertiesElement = createPropertiesElement(); + } + + Element propertyElement = createPropertyValueElement(propertyDescriptor, value); + propertiesElement.appendChild(propertyElement); + } + } + } + } + } + + if (propertiesByPropertyDescriptor != null) { + // Then, for each PropertyDescriptor not explicitly provided + for (Map.Entry, Object> entry : propertiesByPropertyDescriptor.entrySet()) { + // If not explicitly given... + PropertyDescriptor propertyDescriptor = entry.getKey(); + if (!propertyDescriptors.contains(propertyDescriptor)) { + // Otherwise, any property which has a value different than + // the + // default needs to go out as a value. + Object defaultValue = propertyDescriptor.defaultValue(); + Object value = entry.getValue(); + if (value != defaultValue && (value == null || !value.equals(defaultValue))) { + if (propertiesElement == null) { + propertiesElement = createPropertiesElement(); + } + Element propertyElement = createPropertyValueElement(propertyDescriptor, value); + propertiesElement.appendChild(propertyElement); + } + } + } + } + return propertiesElement; + } + + private Element createPropertyValueElement(PropertyDescriptor propertyDescriptor, Object value) { + Element propertyElement = document.createElementNS(RULESET_NS_URI, "property"); + propertyElement.setAttribute("name", propertyDescriptor.name()); + String valueString = propertyDescriptor.asDelimitedString(value); + if (XPathRule.XPATH_DESCRIPTOR.equals(propertyDescriptor)) { + Element valueElement = createCDATASectionElement("value", valueString); + propertyElement.appendChild(valueElement); + } else { + propertyElement.setAttribute("value", valueString); + } + + return propertyElement; + } + + // private Element createPropertyDefinitionElement(PropertyDescriptor + // propertyDescriptor) { + // Element propertyElement = createPropertyValueElement(propertyDescriptor, + // propertyDescriptor.defaultValue()); + // + // propertyElement.setAttribute("description", + // propertyDescriptor.description()); + // String type = + // PropertyDescriptorFactory.getPropertyDescriptorType(propertyDescriptor); + // propertyElement.setAttribute("type", type); + // + // if (propertyDescriptor.isMultiValue()) { + // propertyElement.setAttribute("delimiter", + // String.valueOf(propertyDescriptor.multiValueDelimiter())); + // } + // + // if (propertyDescriptor instanceof AbstractNumericProperty) { + // propertyElement.setAttribute("min", + // String.valueOf(((AbstractNumericProperty) + // propertyDescriptor).lowerLimit())); + // propertyElement.setAttribute("max", + // String.valueOf(((AbstractNumericProperty) + // propertyDescriptor).upperLimit())); + // } + // + // return propertyElement; + // } + + private Element createPropertyDefinitionElementBR(PropertyDescriptor propertyDescriptor) { + + final Element propertyElement = createPropertyValueElement(propertyDescriptor, + propertyDescriptor.defaultValue()); + propertyElement.setAttribute(PropertyDescriptorFields.TYPE, + PropertyDescriptorUtil.typeIdFor(propertyDescriptor.type())); + + Map propertyValuesById = propertyDescriptor.attributeValuesById(); + for (Map.Entry entry : propertyValuesById.entrySet()) { + propertyElement.setAttribute(entry.getKey(), entry.getValue()); + } + + return propertyElement; + } + + private Element createTextElement(String name, String value) { + Element element = document.createElementNS(RULESET_NS_URI, name); + Text text = document.createTextNode(value); + element.appendChild(text); + return element; + } + + private Element createCDATASectionElement(String name, String value) { + Element element = document.createElementNS(RULESET_NS_URI, name); + CDATASection cdataSection = document.createCDATASection(value); + element.appendChild(cdataSection); + return element; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleViolationComparator.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleViolationComparator.java index 1947c7ddab..bbfa48ed07 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleViolationComparator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleViolationComparator.java @@ -1,62 +1,62 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.util.Comparator; - -/** - * Compares RuleViolations using the following criteria: - *
    - *
  1. Source file name
  2. - *
  3. Begin line
  4. - *
  5. Description
  6. - *
  7. Begin column
  8. - *
  9. End line
  10. - *
  11. End column
  12. - *
  13. Rule name
  14. - *
- */ -public final class RuleViolationComparator implements Comparator { - - public static final RuleViolationComparator INSTANCE = new RuleViolationComparator(); - - private RuleViolationComparator() { - } - - @Override - public int compare(final RuleViolation r1, final RuleViolation r2) { - int cmp = r1.getFilename().compareTo(r2.getFilename()); - if (cmp == 0) { - cmp = r1.getBeginLine() - r2.getBeginLine(); - if (cmp == 0) { - cmp = compare(r1.getDescription(), r2.getDescription()); - if (cmp == 0) { - cmp = r1.getBeginColumn() - r2.getBeginColumn(); - if (cmp == 0) { - cmp = r1.getEndLine() - r2.getEndLine(); - if (cmp == 0) { - cmp = r1.getEndColumn() - r2.getEndColumn(); - if (cmp == 0) { - cmp = r1.getRule().getName().compareTo(r2.getRule().getName()); - } - } - } - } - } - } - return cmp; - } - - private static int compare(final String s1, final String s2) { - // Treat null as larger - if (s1 == null) { - return 1; - } else if (s2 == null) { - return -1; - } else { - return s1.compareTo(s2); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.util.Comparator; + +/** + * Compares RuleViolations using the following criteria: + *
    + *
  1. Source file name
  2. + *
  3. Begin line
  4. + *
  5. Description
  6. + *
  7. Begin column
  8. + *
  9. End line
  10. + *
  11. End column
  12. + *
  13. Rule name
  14. + *
+ */ +public final class RuleViolationComparator implements Comparator { + + public static final RuleViolationComparator INSTANCE = new RuleViolationComparator(); + + private RuleViolationComparator() { + } + + @Override + public int compare(final RuleViolation r1, final RuleViolation r2) { + int cmp = r1.getFilename().compareTo(r2.getFilename()); + if (cmp == 0) { + cmp = r1.getBeginLine() - r2.getBeginLine(); + if (cmp == 0) { + cmp = compare(r1.getDescription(), r2.getDescription()); + if (cmp == 0) { + cmp = r1.getBeginColumn() - r2.getBeginColumn(); + if (cmp == 0) { + cmp = r1.getEndLine() - r2.getEndLine(); + if (cmp == 0) { + cmp = r1.getEndColumn() - r2.getEndColumn(); + if (cmp == 0) { + cmp = r1.getRule().getName().compareTo(r2.getRule().getName()); + } + } + } + } + } + } + return cmp; + } + + private static int compare(final String s1, final String s2) { + // Treat null as larger + if (s1 == null) { + return 1; + } else if (s2 == null) { + return -1; + } else { + return s1.compareTo(s2); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/SourceLanguage.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/SourceLanguage.java index 6f0749535d..6ac69b1c11 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/SourceLanguage.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/SourceLanguage.java @@ -1,35 +1,35 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.ant; - -/** - * Stores LanguageVersion terse name value. - */ -public class SourceLanguage { - - private String name; - private String version; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return ""; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.ant; + +/** + * Stores LanguageVersion terse name value. + */ +public class SourceLanguage { + + private String name; + private String version; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AbstractLanguage.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AbstractLanguage.java index a6485062b5..2df28ea101 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AbstractLanguage.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AbstractLanguage.java @@ -1,58 +1,58 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.cpd; - -import java.io.FilenameFilter; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - -import net.sourceforge.pmd.util.filter.Filters; - -public abstract class AbstractLanguage implements Language { - private final String name; - private final String terseName; - private final Tokenizer tokenizer; - private final FilenameFilter fileFilter; - private final List extensions; - - public AbstractLanguage(String name, String terseName, Tokenizer tokenizer, String... extensions) { - this.name = name; - this.terseName = terseName; - this.tokenizer = tokenizer; - fileFilter = Filters.toFilenameFilter(Filters.getFileExtensionOrDirectoryFilter(extensions)); - this.extensions = Arrays.asList(extensions); - } - - @Override - public FilenameFilter getFileFilter() { - return fileFilter; - } - - @Override - public Tokenizer getTokenizer() { - return tokenizer; - } - - @Override - public void setProperties(Properties properties) { - // needs to be implemented by subclasses. - } - - @Override - public String getName() { - return name; - } - - @Override - public String getTerseName() { - return terseName; - } - - @Override - public List getExtensions() { - return extensions; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +import java.io.FilenameFilter; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import net.sourceforge.pmd.util.filter.Filters; + +public abstract class AbstractLanguage implements Language { + private final String name; + private final String terseName; + private final Tokenizer tokenizer; + private final FilenameFilter fileFilter; + private final List extensions; + + public AbstractLanguage(String name, String terseName, Tokenizer tokenizer, String... extensions) { + this.name = name; + this.terseName = terseName; + this.tokenizer = tokenizer; + fileFilter = Filters.toFilenameFilter(Filters.getFileExtensionOrDirectoryFilter(extensions)); + this.extensions = Arrays.asList(extensions); + } + + @Override + public FilenameFilter getFileFilter() { + return fileFilter; + } + + @Override + public Tokenizer getTokenizer() { + return tokenizer; + } + + @Override + public void setProperties(Properties properties) { + // needs to be implemented by subclasses. + } + + @Override + public String getName() { + return name; + } + + @Override + public String getTerseName() { + return terseName; + } + + @Override + public List getExtensions() { + return extensions; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java index 11b34de5a1..21204cb355 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java @@ -1,172 +1,172 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * ClassLoader utilities. Useful for extracting additional details from a class - * hierarchy beyond the basic standard Java Reflection APIs. - */ -public class ClassLoaderUtil { - - public static final String CLINIT = ""; - - public static final String INIT = ""; - - private ClassLoaderUtil() { } - - public static String fromInternalForm(String internalForm) { - return internalForm.replace('/', '.'); - } - - public static String toInternalForm(String internalForm) { - return internalForm.replace('.', '/'); - } - - public static Class getClass(String name) { - try { - return ClassLoaderUtil.class.getClassLoader().loadClass(name); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } catch (NoClassDefFoundError e) { - throw new RuntimeException(e); - } - } - - public static Field getField(Class type, String name) { - try { - return myGetField(type, name); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } - } - - private static Field myGetField(Class type, String name) throws NoSuchFieldException { - // Scan the type hierarchy just like Class.getField(String) using - // Class.getDeclaredField(String) - try { - return type.getDeclaredField(name); - } catch (NoSuchFieldException e) { - // Try the super interfaces - for (Class superInterface : type.getInterfaces()) { - try { - return myGetField(superInterface, name); - } catch (NoSuchFieldException e2) { - // Okay - } - } - // Try the super classes - if (type.getSuperclass() != null) { - return myGetField(type.getSuperclass(), name); - } else { - throw new NoSuchFieldException(type.getName() + "." + name); - } - } - } - - public static Method getMethod(Class type, String name, Class... parameterTypes) { - try { - return myGetMethod(type, name, parameterTypes); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - private static Method myGetMethod(Class type, String name, Class... parameterTypes) - throws NoSuchMethodException { - // Scan the type hierarchy just like Class.getMethod(String, Class[]) - // using Class.getDeclaredMethod(String, Class[]) - // System.out.println("type: " + type); - // System.out.println("name: " + name); - // System.out - // .println("parameterTypes: " + Arrays.toString(parameterTypes)); - try { - // System.out.println("Checking getDeclaredMethod"); - // for (Method m : type.getDeclaredMethods()) { - // System.out.println("\t" + m); - // } - return type.getDeclaredMethod(name, parameterTypes); - } catch (NoSuchMethodException e) { - try { - // Try the super classes - if (type.getSuperclass() != null) { - // System.out.println("Checking super: " - // + type.getSuperclass()); - return myGetMethod(type.getSuperclass(), name, parameterTypes); - } - } catch (NoSuchMethodException e2) { - // Okay - } - // Try the super interfaces - for (Class superInterface : type.getInterfaces()) { - try { - // System.out.println("Checking super interface: " - // + superInterface); - return myGetMethod(superInterface, name, parameterTypes); - } catch (NoSuchMethodException e3) { - // Okay - } - } - throw new NoSuchMethodException(type.getName() + '.' + getMethodSignature(name, parameterTypes)); - } - } - - public static Constructor getConstructor(Class type, String name, Class... parameterTypes) { - try { - return type.getDeclaredConstructor(parameterTypes); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - public static String getMethodSignature(String name, Class... parameterTypes) { - StringBuilder builder = new StringBuilder(name); - if (!(name.equals(CLINIT) || name.equals(INIT))) { - builder.append('('); - if (parameterTypes != null && parameterTypes.length > 0) { - builder.append(parameterTypes[0].getName()); - for (int i = 1; i < parameterTypes.length; i++) { - builder.append(", ").append(parameterTypes[i].getName()); - } - } - builder.append(')'); - } - return builder.toString(); - } - - public static Class[] getParameterTypes(String... parameterTypeNames) { - Class[] parameterTypes = new Class[parameterTypeNames.length]; - for (int i = 0; i < parameterTypeNames.length; i++) { - parameterTypes[i] = getClass(parameterTypeNames[i]); - } - return parameterTypes; - } - - public static boolean isOverridenMethod(Class clazz, Method method, boolean checkThisClass) { - try { - if (checkThisClass) { - clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); - return true; - } - } catch (NoSuchMethodException e) { - } - // Check super class - if (clazz.getSuperclass() != null) { - if (isOverridenMethod(clazz.getSuperclass(), method, true)) { - return true; - } - } - // Check interfaces - for (Class anInterface : clazz.getInterfaces()) { - if (isOverridenMethod(anInterface, method, true)) { - return true; - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * ClassLoader utilities. Useful for extracting additional details from a class + * hierarchy beyond the basic standard Java Reflection APIs. + */ +public class ClassLoaderUtil { + + public static final String CLINIT = ""; + + public static final String INIT = ""; + + private ClassLoaderUtil() { } + + public static String fromInternalForm(String internalForm) { + return internalForm.replace('/', '.'); + } + + public static String toInternalForm(String internalForm) { + return internalForm.replace('.', '/'); + } + + public static Class getClass(String name) { + try { + return ClassLoaderUtil.class.getClassLoader().loadClass(name); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } catch (NoClassDefFoundError e) { + throw new RuntimeException(e); + } + } + + public static Field getField(Class type, String name) { + try { + return myGetField(type, name); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + private static Field myGetField(Class type, String name) throws NoSuchFieldException { + // Scan the type hierarchy just like Class.getField(String) using + // Class.getDeclaredField(String) + try { + return type.getDeclaredField(name); + } catch (NoSuchFieldException e) { + // Try the super interfaces + for (Class superInterface : type.getInterfaces()) { + try { + return myGetField(superInterface, name); + } catch (NoSuchFieldException e2) { + // Okay + } + } + // Try the super classes + if (type.getSuperclass() != null) { + return myGetField(type.getSuperclass(), name); + } else { + throw new NoSuchFieldException(type.getName() + "." + name); + } + } + } + + public static Method getMethod(Class type, String name, Class... parameterTypes) { + try { + return myGetMethod(type, name, parameterTypes); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private static Method myGetMethod(Class type, String name, Class... parameterTypes) + throws NoSuchMethodException { + // Scan the type hierarchy just like Class.getMethod(String, Class[]) + // using Class.getDeclaredMethod(String, Class[]) + // System.out.println("type: " + type); + // System.out.println("name: " + name); + // System.out + // .println("parameterTypes: " + Arrays.toString(parameterTypes)); + try { + // System.out.println("Checking getDeclaredMethod"); + // for (Method m : type.getDeclaredMethods()) { + // System.out.println("\t" + m); + // } + return type.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException e) { + try { + // Try the super classes + if (type.getSuperclass() != null) { + // System.out.println("Checking super: " + // + type.getSuperclass()); + return myGetMethod(type.getSuperclass(), name, parameterTypes); + } + } catch (NoSuchMethodException e2) { + // Okay + } + // Try the super interfaces + for (Class superInterface : type.getInterfaces()) { + try { + // System.out.println("Checking super interface: " + // + superInterface); + return myGetMethod(superInterface, name, parameterTypes); + } catch (NoSuchMethodException e3) { + // Okay + } + } + throw new NoSuchMethodException(type.getName() + '.' + getMethodSignature(name, parameterTypes)); + } + } + + public static Constructor getConstructor(Class type, String name, Class... parameterTypes) { + try { + return type.getDeclaredConstructor(parameterTypes); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public static String getMethodSignature(String name, Class... parameterTypes) { + StringBuilder builder = new StringBuilder(name); + if (!(name.equals(CLINIT) || name.equals(INIT))) { + builder.append('('); + if (parameterTypes != null && parameterTypes.length > 0) { + builder.append(parameterTypes[0].getName()); + for (int i = 1; i < parameterTypes.length; i++) { + builder.append(", ").append(parameterTypes[i].getName()); + } + } + builder.append(')'); + } + return builder.toString(); + } + + public static Class[] getParameterTypes(String... parameterTypeNames) { + Class[] parameterTypes = new Class[parameterTypeNames.length]; + for (int i = 0; i < parameterTypeNames.length; i++) { + parameterTypes[i] = getClass(parameterTypeNames[i]); + } + return parameterTypes; + } + + public static boolean isOverridenMethod(Class clazz, Method method, boolean checkThisClass) { + try { + if (checkThisClass) { + clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + return true; + } + } catch (NoSuchMethodException e) { + } + // Check super class + if (clazz.getSuperclass() != null) { + if (isOverridenMethod(clazz.getSuperclass(), method, true)) { + return true; + } + } + // Check interfaces + for (Class anInterface : clazz.getInterfaces()) { + if (isOverridenMethod(anInterface, method, true)) { + return true; + } + } + return false; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DCD.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DCD.java index 2f459651dd..eddc9a266e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DCD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DCD.java @@ -1,177 +1,177 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd; - -import java.io.File; -import java.io.FilenameFilter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import net.sourceforge.pmd.dcd.graph.UsageGraph; -import net.sourceforge.pmd.dcd.graph.UsageGraphBuilder; -import net.sourceforge.pmd.util.FileFinder; -import net.sourceforge.pmd.util.filter.Filter; -import net.sourceforge.pmd.util.filter.Filters; - -/** - * The Dead Code Detector is used to find dead code. What is dead code? Dead - * code is code which is not used by other code? It exists, but it not used. - * Unused code is clutter, which can generally be a candidate for removal. - * - *

When performing dead code detection, there are various sets of files/classes - * which must be identified. An analogy of the dead code analysis as a foot - * race is used to help clarify each of these sets:

- * - *
    - *
  1. The direct users is the set of Classes which will always be - * parsed to determine what code they use. This set is the starting point of the - * race.
  2. - *
  3. The indirect users is the set of Classes which will only be - * parsed if they are accessed by code in the direct users set, or in - * the indirect users set. This set is the course of the race.
  4. - *
  5. The dead code candidates are the set of Classes which are the - * focus of the dead code detection. This set is the finish line of the - * race.
  6. - *
- * - *

Typically there is intersection between the set of direct users, - * indirect users and dead code candidates, although it is not - * required. If the sets are defined too tightly, there the potential for a lot - * of code to be considered as dead code. You may need to expand the direct - * users or indirect users sets, or explore using different - * options.

- * - * @author Ryan Gustafson <ryan.gustafson@gmail.com> - */ -public class DCD { - // - // TODO Implement the direct users, indirect users, and dead code - // candidate sets. Use the pmd.util.filter.Filter APIs. Need to come up - // with something like Ant's capabilities for , it's a decent way - // to describe a collection of files in a directory structure. That or we - // just adopt Ant, and screw command line/external configuration? - // - // TODO Better yet, is there a way to enumerate all available classes using - // ClassLoaders instead of having to specify Java file names as surrogates - // for the Classes we truly desire? - // - // TODO Methods defined on classes/interfaces not within the scope of - // analysis which are implemented/overridden, are not usage violations. - // - // TODO Static final String and primitive types are often inlined by the - // compiler, so there may actually be no explicit usages. - // - // TODO Ignore "public static void main(String[])" - // - // TODO Check for method which is always overridden, and never called - // directly. - // - // TODO For methods, record which classes/interfaces methods they are - // overriding/implementing. - // - // TODO Allow recognition of indirect method patterns, like those used by - // EJB Home and Remote interfaces with corresponding implementation classes. - // - // TODO - // 1) For each class/member, a set of other class/members which reference. - // 2) For every class/member which is part of an interface or super-class, - // allocate those references to the interface/super-class. - // - - private DCD() { } - - public static void dump(UsageGraph usageGraph, boolean verbose) { - usageGraph.accept(new DumpNodeVisitor(), Boolean.valueOf(verbose)); - } - - public static void report(UsageGraph usageGraph, boolean verbose) { - usageGraph.accept(new UsageNodeVisitor(), Boolean.valueOf(verbose)); - } - - public static void main(String[] args) throws Exception { - // 1) Directories - List directories = new ArrayList<>(); - directories.add(new File("C:/pmd/workspace/pmd-trunk/src")); - - // Basic filter - FilenameFilter javaFilter = new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - // Recurse on directories - if (new File(dir, name).isDirectory()) { - return true; - } else { - return name.endsWith(".java"); - } - } - }; - - // 2) Filename filters - List filters = new ArrayList<>(); - filters.add(javaFilter); - - assert directories.size() == filters.size(); - - // Find all files, convert to class names - List classes = new ArrayList<>(); - for (int i = 0; i < directories.size(); i++) { - File directory = directories.get(i); - FilenameFilter filter = filters.get(i); - List files = new FileFinder().findFilesFrom(directory, filter, true); - for (File file : files) { - String name = file.getPath(); - - // Chop off directory - name = name.substring(directory.getPath().length() + 1); - - // Drop extension - name = name.replaceAll("\\.java$", ""); - - // Trim path separators - name = name.replace('\\', '.'); - name = name.replace('/', '.'); - - classes.add(name); - } - } - - long start = System.currentTimeMillis(); - - // Define filter for "indirect users" and "dead code candidates". - // TODO Need to support these are different concepts. - List includeRegexes = Arrays.asList(new String[] { "net\\.sourceforge\\.pmd\\.dcd.*", "us\\..*" }); - List excludeRegexes = Arrays.asList(new String[] { "java\\..*", "javax\\..*", ".*\\.twa\\..*" }); - Filter classFilter = Filters.buildRegexFilterExcludeOverInclude(includeRegexes, excludeRegexes); - System.out.println("Class filter: " + classFilter); - - // Index each of the "direct users" - UsageGraphBuilder builder = new UsageGraphBuilder(classFilter); - int total = 0; - for (String clazz : classes) { - System.out.println("indexing class: " + clazz); - builder.index(clazz); - total++; - if (total % 20 == 0) { - System.out.println(total + " : " + total / ((System.currentTimeMillis() - start) / 1000.0)); - } - } - - // Reporting - boolean dump = true; - boolean deadCode = true; - UsageGraph usageGraph = builder.getUsageGraph(); - if (dump) { - System.out.println("--- Dump ---"); - dump(usageGraph, true); - } - if (deadCode) { - System.out.println("--- Dead Code ---"); - report(usageGraph, true); - } - long end = System.currentTimeMillis(); - System.out.println("Time: " + (end - start) / 1000.0); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import net.sourceforge.pmd.dcd.graph.UsageGraph; +import net.sourceforge.pmd.dcd.graph.UsageGraphBuilder; +import net.sourceforge.pmd.util.FileFinder; +import net.sourceforge.pmd.util.filter.Filter; +import net.sourceforge.pmd.util.filter.Filters; + +/** + * The Dead Code Detector is used to find dead code. What is dead code? Dead + * code is code which is not used by other code? It exists, but it not used. + * Unused code is clutter, which can generally be a candidate for removal. + * + *

When performing dead code detection, there are various sets of files/classes + * which must be identified. An analogy of the dead code analysis as a foot + * race is used to help clarify each of these sets:

+ * + *
    + *
  1. The direct users is the set of Classes which will always be + * parsed to determine what code they use. This set is the starting point of the + * race.
  2. + *
  3. The indirect users is the set of Classes which will only be + * parsed if they are accessed by code in the direct users set, or in + * the indirect users set. This set is the course of the race.
  4. + *
  5. The dead code candidates are the set of Classes which are the + * focus of the dead code detection. This set is the finish line of the + * race.
  6. + *
+ * + *

Typically there is intersection between the set of direct users, + * indirect users and dead code candidates, although it is not + * required. If the sets are defined too tightly, there the potential for a lot + * of code to be considered as dead code. You may need to expand the direct + * users or indirect users sets, or explore using different + * options.

+ * + * @author Ryan Gustafson <ryan.gustafson@gmail.com> + */ +public class DCD { + // + // TODO Implement the direct users, indirect users, and dead code + // candidate sets. Use the pmd.util.filter.Filter APIs. Need to come up + // with something like Ant's capabilities for , it's a decent way + // to describe a collection of files in a directory structure. That or we + // just adopt Ant, and screw command line/external configuration? + // + // TODO Better yet, is there a way to enumerate all available classes using + // ClassLoaders instead of having to specify Java file names as surrogates + // for the Classes we truly desire? + // + // TODO Methods defined on classes/interfaces not within the scope of + // analysis which are implemented/overridden, are not usage violations. + // + // TODO Static final String and primitive types are often inlined by the + // compiler, so there may actually be no explicit usages. + // + // TODO Ignore "public static void main(String[])" + // + // TODO Check for method which is always overridden, and never called + // directly. + // + // TODO For methods, record which classes/interfaces methods they are + // overriding/implementing. + // + // TODO Allow recognition of indirect method patterns, like those used by + // EJB Home and Remote interfaces with corresponding implementation classes. + // + // TODO + // 1) For each class/member, a set of other class/members which reference. + // 2) For every class/member which is part of an interface or super-class, + // allocate those references to the interface/super-class. + // + + private DCD() { } + + public static void dump(UsageGraph usageGraph, boolean verbose) { + usageGraph.accept(new DumpNodeVisitor(), Boolean.valueOf(verbose)); + } + + public static void report(UsageGraph usageGraph, boolean verbose) { + usageGraph.accept(new UsageNodeVisitor(), Boolean.valueOf(verbose)); + } + + public static void main(String[] args) throws Exception { + // 1) Directories + List directories = new ArrayList<>(); + directories.add(new File("C:/pmd/workspace/pmd-trunk/src")); + + // Basic filter + FilenameFilter javaFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + // Recurse on directories + if (new File(dir, name).isDirectory()) { + return true; + } else { + return name.endsWith(".java"); + } + } + }; + + // 2) Filename filters + List filters = new ArrayList<>(); + filters.add(javaFilter); + + assert directories.size() == filters.size(); + + // Find all files, convert to class names + List classes = new ArrayList<>(); + for (int i = 0; i < directories.size(); i++) { + File directory = directories.get(i); + FilenameFilter filter = filters.get(i); + List files = new FileFinder().findFilesFrom(directory, filter, true); + for (File file : files) { + String name = file.getPath(); + + // Chop off directory + name = name.substring(directory.getPath().length() + 1); + + // Drop extension + name = name.replaceAll("\\.java$", ""); + + // Trim path separators + name = name.replace('\\', '.'); + name = name.replace('/', '.'); + + classes.add(name); + } + } + + long start = System.currentTimeMillis(); + + // Define filter for "indirect users" and "dead code candidates". + // TODO Need to support these are different concepts. + List includeRegexes = Arrays.asList(new String[] { "net\\.sourceforge\\.pmd\\.dcd.*", "us\\..*" }); + List excludeRegexes = Arrays.asList(new String[] { "java\\..*", "javax\\..*", ".*\\.twa\\..*" }); + Filter classFilter = Filters.buildRegexFilterExcludeOverInclude(includeRegexes, excludeRegexes); + System.out.println("Class filter: " + classFilter); + + // Index each of the "direct users" + UsageGraphBuilder builder = new UsageGraphBuilder(classFilter); + int total = 0; + for (String clazz : classes) { + System.out.println("indexing class: " + clazz); + builder.index(clazz); + total++; + if (total % 20 == 0) { + System.out.println(total + " : " + total / ((System.currentTimeMillis() - start) / 1000.0)); + } + } + + // Reporting + boolean dump = true; + boolean deadCode = true; + UsageGraph usageGraph = builder.getUsageGraph(); + if (dump) { + System.out.println("--- Dump ---"); + dump(usageGraph, true); + } + if (deadCode) { + System.out.println("--- Dead Code ---"); + report(usageGraph, true); + } + long end = System.currentTimeMillis(); + System.out.println("Time: " + (end - start) / 1000.0); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DumpNodeVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DumpNodeVisitor.java index 91e92f7d1f..382201530d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DumpNodeVisitor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/DumpNodeVisitor.java @@ -1,106 +1,106 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd; - -import net.sourceforge.pmd.dcd.graph.ClassNode; -import net.sourceforge.pmd.dcd.graph.ConstructorNode; -import net.sourceforge.pmd.dcd.graph.FieldNode; -import net.sourceforge.pmd.dcd.graph.MemberNode; -import net.sourceforge.pmd.dcd.graph.MethodNode; -import net.sourceforge.pmd.dcd.graph.NodeVisitorAdapter; -import net.sourceforge.pmd.dcd.graph.UsageGraph; - -/** - * Dump a UsageGraph to System.out. - */ -public class DumpNodeVisitor extends NodeVisitorAdapter { - - @Override - public Object visit(UsageGraph usageGraph, Object data) { - System.out.println("----------------------------------------"); - super.visit(usageGraph, data); - System.out.println("----------------------------------------"); - return data; - } - - @Override - public Object visit(ClassNode classNode, Object data) { - System.out.println("Class: " + ClassLoaderUtil.fromInternalForm(classNode.getName())); - return super.visit(classNode, data); - } - - @Override - public Object visitFields(ClassNode classNode, Object data) { - System.out.println("\tFields (" + classNode.getFieldNodes().size() + "):"); - return super.visitFields(classNode, data); - } - - @Override - public Object visit(FieldNode fieldNode, Object data) { - printMember(fieldNode); - return super.visit(fieldNode, data); - } - - @Override - public Object visitConstructors(ClassNode classNode, Object data) { - System.out.println("\tConstructors (" + classNode.getConstructorNodes().size() + "):"); - return super.visitConstructors(classNode, data); - } - - @Override - public Object visit(ConstructorNode constructorNode, Object data) { - printMember(constructorNode); - return super.visit(constructorNode, data); - } - - @Override - public Object visitMethods(ClassNode classNode, Object data) { - System.out.println("\tMethods (" + classNode.getMethodNodes().size() + "):"); - return super.visitMethods(classNode, data); - } - - @Override - public Object visit(MethodNode methodNode, Object data) { - printMember(methodNode); - return super.visit(methodNode, data); - } - - @Override - public Object visitUses(MemberNode memberNode, Object data) { - if (Boolean.TRUE == data && !memberNode.getUses().isEmpty()) { - System.out.println("\t\t\tUses:"); - } - return super.visitUses(memberNode, data); - } - - @Override - public Object visitUse(MemberNode use, Object data) { - if (Boolean.TRUE == data) { - System.out.println("\t\t\t\t" + use.toStringLong()); - } - return super.visitUse(use, data); - } - - @Override - public Object visitUsers(MemberNode memberNode, Object data) { - if (Boolean.TRUE == data && !memberNode.getUsers().isEmpty()) { - System.out.println("\t\t\tUsers:"); - } - return super.visitUsers(memberNode, data); - } - - @Override - public Object visitUser(MemberNode user, Object data) { - if (Boolean.TRUE == data) { - System.out.println("\t\t\t\t" + user.toStringLong()); - } - return super.visitUser(user, data); - } - - protected void printMember(MemberNode memberNode) { - System.out.println("\t\t(" + memberNode.getUses().size() + ", " + memberNode.getUsers().size() + ") " - + memberNode.toStringLong()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd; + +import net.sourceforge.pmd.dcd.graph.ClassNode; +import net.sourceforge.pmd.dcd.graph.ConstructorNode; +import net.sourceforge.pmd.dcd.graph.FieldNode; +import net.sourceforge.pmd.dcd.graph.MemberNode; +import net.sourceforge.pmd.dcd.graph.MethodNode; +import net.sourceforge.pmd.dcd.graph.NodeVisitorAdapter; +import net.sourceforge.pmd.dcd.graph.UsageGraph; + +/** + * Dump a UsageGraph to System.out. + */ +public class DumpNodeVisitor extends NodeVisitorAdapter { + + @Override + public Object visit(UsageGraph usageGraph, Object data) { + System.out.println("----------------------------------------"); + super.visit(usageGraph, data); + System.out.println("----------------------------------------"); + return data; + } + + @Override + public Object visit(ClassNode classNode, Object data) { + System.out.println("Class: " + ClassLoaderUtil.fromInternalForm(classNode.getName())); + return super.visit(classNode, data); + } + + @Override + public Object visitFields(ClassNode classNode, Object data) { + System.out.println("\tFields (" + classNode.getFieldNodes().size() + "):"); + return super.visitFields(classNode, data); + } + + @Override + public Object visit(FieldNode fieldNode, Object data) { + printMember(fieldNode); + return super.visit(fieldNode, data); + } + + @Override + public Object visitConstructors(ClassNode classNode, Object data) { + System.out.println("\tConstructors (" + classNode.getConstructorNodes().size() + "):"); + return super.visitConstructors(classNode, data); + } + + @Override + public Object visit(ConstructorNode constructorNode, Object data) { + printMember(constructorNode); + return super.visit(constructorNode, data); + } + + @Override + public Object visitMethods(ClassNode classNode, Object data) { + System.out.println("\tMethods (" + classNode.getMethodNodes().size() + "):"); + return super.visitMethods(classNode, data); + } + + @Override + public Object visit(MethodNode methodNode, Object data) { + printMember(methodNode); + return super.visit(methodNode, data); + } + + @Override + public Object visitUses(MemberNode memberNode, Object data) { + if (Boolean.TRUE == data && !memberNode.getUses().isEmpty()) { + System.out.println("\t\t\tUses:"); + } + return super.visitUses(memberNode, data); + } + + @Override + public Object visitUse(MemberNode use, Object data) { + if (Boolean.TRUE == data) { + System.out.println("\t\t\t\t" + use.toStringLong()); + } + return super.visitUse(use, data); + } + + @Override + public Object visitUsers(MemberNode memberNode, Object data) { + if (Boolean.TRUE == data && !memberNode.getUsers().isEmpty()) { + System.out.println("\t\t\tUsers:"); + } + return super.visitUsers(memberNode, data); + } + + @Override + public Object visitUser(MemberNode user, Object data) { + if (Boolean.TRUE == data) { + System.out.println("\t\t\t\t" + user.toStringLong()); + } + return super.visitUser(user, data); + } + + protected void printMember(MemberNode memberNode) { + System.out.println("\t\t(" + memberNode.getUses().size() + ", " + memberNode.getUsers().size() + ") " + + memberNode.toStringLong()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/UsageNodeVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/UsageNodeVisitor.java index 9d543cb201..98a8b17ee6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/UsageNodeVisitor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/UsageNodeVisitor.java @@ -1,233 +1,233 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import net.sourceforge.pmd.dcd.graph.ClassNode; -import net.sourceforge.pmd.dcd.graph.ConstructorNode; -import net.sourceforge.pmd.dcd.graph.FieldNode; -import net.sourceforge.pmd.dcd.graph.MemberNode; -import net.sourceforge.pmd.dcd.graph.MethodNode; -import net.sourceforge.pmd.dcd.graph.NodeVisitorAdapter; -import net.sourceforge.pmd.dcd.graph.UsageGraph; - -/** - * Perform a visitation a UsageGraph, looking for dead code, which is - * essential code which is not used by any other code. There are various options - * for configuration how this determination is made. - */ -public class UsageNodeVisitor extends NodeVisitorAdapter { - - /** - * Configuration options for usage analysis. - */ - public static final class Options { - private boolean ignoreClassAnonymous = true; - - private boolean ignoreConstructorStaticInitializer = true; - - private boolean ignoreConstructorSinglePrivateNoArg = true; - - private boolean ignoreConstructorAllPrivate = false; - - private boolean ignoreMethodJavaLangObjectOverride = true; - - private boolean ignoreMethodAllOverride = false; - - private boolean ignoreMethodMain = true; - - private boolean ignoreFieldInlinable = true; - - public boolean isIgnoreClassAnonymous() { - return ignoreClassAnonymous; - } - - public void setIgnoreClassAnonymous(boolean ignoreClassAnonymous) { - this.ignoreClassAnonymous = ignoreClassAnonymous; - } - - public boolean isIgnoreConstructorStaticInitializer() { - return ignoreConstructorStaticInitializer; - } - - public void setIgnoreConstructorStaticInitializer(boolean ignoreConstructorStaticInitializer) { - this.ignoreConstructorStaticInitializer = ignoreConstructorStaticInitializer; - } - - public boolean isIgnoreConstructorSinglePrivateNoArg() { - return ignoreConstructorSinglePrivateNoArg; - } - - public void setIgnoreConstructorSinglePrivateNoArg(boolean ignoreConstructorSinglePrivateNoArg) { - this.ignoreConstructorSinglePrivateNoArg = ignoreConstructorSinglePrivateNoArg; - } - - public boolean isIgnoreConstructorAllPrivate() { - return ignoreConstructorAllPrivate; - } - - public void setIgnoreConstructorAllPrivate(boolean ignoreConstructorAllPrivate) { - this.ignoreConstructorAllPrivate = ignoreConstructorAllPrivate; - } - - public boolean isIgnoreMethodJavaLangObjectOverride() { - return ignoreMethodJavaLangObjectOverride; - } - - public void setIgnoreMethodJavaLangObjectOverride(boolean ignoreMethodJavaLangObjectOverride) { - this.ignoreMethodJavaLangObjectOverride = ignoreMethodJavaLangObjectOverride; - } - - public boolean isIgnoreMethodAllOverride() { - return ignoreMethodAllOverride; - } - - public void setIgnoreMethodAllOverride(boolean ignoreMethodAllOverride) { - this.ignoreMethodAllOverride = ignoreMethodAllOverride; - } - - public boolean isIgnoreMethodMain() { - return ignoreMethodMain; - } - - public void setIgnoreMethodMain(boolean ignoreMethodMain) { - this.ignoreMethodMain = ignoreMethodMain; - } - - public boolean isIgnoreFieldInlinable() { - return ignoreFieldInlinable; - } - - public void setIgnoreFieldInlinable(boolean ignoreFieldInlinable) { - this.ignoreFieldInlinable = ignoreFieldInlinable; - } - - } - - private final Options options = new Options(); - - @Override - public Object visit(UsageGraph usageGraph, Object data) { - System.out.println("----------------------------------------"); - super.visit(usageGraph, data); - System.out.println("----------------------------------------"); - return data; - } - - @Override - public Object visit(ClassNode classNode, Object data) { - boolean log = true; - if (options.isIgnoreClassAnonymous() && classNode.getType().isAnonymousClass()) { - ignore("class anonymous", classNode); - log = false; - } - if (log) { - System.out.println("--- " + classNode.getName() + " ---"); - return super.visit(classNode, data); - } else { - return data; - } - } - - @Override - public Object visit(FieldNode fieldNode, Object data) { - if (fieldNode.getUsers().isEmpty()) { - boolean log = true; - // A field is inlinable if: - // 1) It is final - // 2) It is a primitive, or a java.lang.String - if (options.isIgnoreFieldInlinable()) { - if (Modifier.isFinal(fieldNode.getMember().getModifiers()) - && fieldNode.getMember().getType().isPrimitive() - || fieldNode.getMember().getType().getName().equals("java.lang.String")) { - ignore("field inlinable", fieldNode); - log = false; - } - } - if (log) { - System.out.println("\t" + fieldNode.toStringLong()); - } - } - return super.visit(fieldNode, data); - } - - @Override - public Object visit(ConstructorNode constructorNode, Object data) { - if (constructorNode.getUsers().isEmpty()) { - boolean log = true; - if (constructorNode.isStaticInitializer()) { - if (options.isIgnoreConstructorStaticInitializer()) { - ignore("constructor static initializer", constructorNode); - log = false; - } - } else if (constructorNode.isInstanceInitializer()) { - if (Modifier.isPrivate(constructorNode.getMember().getModifiers())) { - if (options.isIgnoreConstructorAllPrivate()) { - ignore("constructor all private", constructorNode); - log = false; - } else if (options.isIgnoreConstructorSinglePrivateNoArg() - && constructorNode.getMember().getParameterTypes().length == 0 - && constructorNode.getClassNode().getConstructorNodes().size() == 1) { - ignore("constructor single private no-arg", constructorNode); - log = false; - } - } - } - if (log) { - System.out.println("\t" + constructorNode.toStringLong()); - } - } - return super.visit(constructorNode, data); - } - - private static boolean isMainMethod(MethodNode node) { - - final Method method = node.getMember(); - - return method.getName().equals("main") && Modifier.isPublic(method.getModifiers()) - && Modifier.isStatic(method.getModifiers()) && method.getReturnType() == Void.TYPE - && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isArray() - && method.getParameterTypes()[0].getComponentType().equals(java.lang.String.class); - } - - @Override - public Object visit(MethodNode methodNode, Object data) { - if (methodNode.getUsers().isEmpty()) { - boolean log = true; - if (options.isIgnoreMethodAllOverride()) { - if (ClassLoaderUtil.isOverridenMethod(methodNode.getClassNode().getClass(), methodNode.getMember(), - false)) { - ignore("method all override", methodNode); - log = false; - } - } else if (options.isIgnoreMethodJavaLangObjectOverride()) { - if (ClassLoaderUtil.isOverridenMethod(java.lang.Object.class, methodNode.getMember(), true)) { - ignore("method java.lang.Object override", methodNode); - log = false; - } - } - if (options.isIgnoreMethodMain()) { - if (isMainMethod(methodNode)) { - ignore("method public static void main(String[])", methodNode); - log = false; - } - } - if (log) { - System.out.println("\t" + methodNode.toStringLong()); - } - } - return super.visit(methodNode, data); - } - - private void ignore(String description, ClassNode classNode) { - System.out.println("Ignoring " + description + ": " + classNode.getName()); - } - - private void ignore(String description, MemberNode memberNode) { - System.out.println("Ignoring " + description + ": " + memberNode.toStringLong()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import net.sourceforge.pmd.dcd.graph.ClassNode; +import net.sourceforge.pmd.dcd.graph.ConstructorNode; +import net.sourceforge.pmd.dcd.graph.FieldNode; +import net.sourceforge.pmd.dcd.graph.MemberNode; +import net.sourceforge.pmd.dcd.graph.MethodNode; +import net.sourceforge.pmd.dcd.graph.NodeVisitorAdapter; +import net.sourceforge.pmd.dcd.graph.UsageGraph; + +/** + * Perform a visitation a UsageGraph, looking for dead code, which is + * essential code which is not used by any other code. There are various options + * for configuration how this determination is made. + */ +public class UsageNodeVisitor extends NodeVisitorAdapter { + + /** + * Configuration options for usage analysis. + */ + public static final class Options { + private boolean ignoreClassAnonymous = true; + + private boolean ignoreConstructorStaticInitializer = true; + + private boolean ignoreConstructorSinglePrivateNoArg = true; + + private boolean ignoreConstructorAllPrivate = false; + + private boolean ignoreMethodJavaLangObjectOverride = true; + + private boolean ignoreMethodAllOverride = false; + + private boolean ignoreMethodMain = true; + + private boolean ignoreFieldInlinable = true; + + public boolean isIgnoreClassAnonymous() { + return ignoreClassAnonymous; + } + + public void setIgnoreClassAnonymous(boolean ignoreClassAnonymous) { + this.ignoreClassAnonymous = ignoreClassAnonymous; + } + + public boolean isIgnoreConstructorStaticInitializer() { + return ignoreConstructorStaticInitializer; + } + + public void setIgnoreConstructorStaticInitializer(boolean ignoreConstructorStaticInitializer) { + this.ignoreConstructorStaticInitializer = ignoreConstructorStaticInitializer; + } + + public boolean isIgnoreConstructorSinglePrivateNoArg() { + return ignoreConstructorSinglePrivateNoArg; + } + + public void setIgnoreConstructorSinglePrivateNoArg(boolean ignoreConstructorSinglePrivateNoArg) { + this.ignoreConstructorSinglePrivateNoArg = ignoreConstructorSinglePrivateNoArg; + } + + public boolean isIgnoreConstructorAllPrivate() { + return ignoreConstructorAllPrivate; + } + + public void setIgnoreConstructorAllPrivate(boolean ignoreConstructorAllPrivate) { + this.ignoreConstructorAllPrivate = ignoreConstructorAllPrivate; + } + + public boolean isIgnoreMethodJavaLangObjectOverride() { + return ignoreMethodJavaLangObjectOverride; + } + + public void setIgnoreMethodJavaLangObjectOverride(boolean ignoreMethodJavaLangObjectOverride) { + this.ignoreMethodJavaLangObjectOverride = ignoreMethodJavaLangObjectOverride; + } + + public boolean isIgnoreMethodAllOverride() { + return ignoreMethodAllOverride; + } + + public void setIgnoreMethodAllOverride(boolean ignoreMethodAllOverride) { + this.ignoreMethodAllOverride = ignoreMethodAllOverride; + } + + public boolean isIgnoreMethodMain() { + return ignoreMethodMain; + } + + public void setIgnoreMethodMain(boolean ignoreMethodMain) { + this.ignoreMethodMain = ignoreMethodMain; + } + + public boolean isIgnoreFieldInlinable() { + return ignoreFieldInlinable; + } + + public void setIgnoreFieldInlinable(boolean ignoreFieldInlinable) { + this.ignoreFieldInlinable = ignoreFieldInlinable; + } + + } + + private final Options options = new Options(); + + @Override + public Object visit(UsageGraph usageGraph, Object data) { + System.out.println("----------------------------------------"); + super.visit(usageGraph, data); + System.out.println("----------------------------------------"); + return data; + } + + @Override + public Object visit(ClassNode classNode, Object data) { + boolean log = true; + if (options.isIgnoreClassAnonymous() && classNode.getType().isAnonymousClass()) { + ignore("class anonymous", classNode); + log = false; + } + if (log) { + System.out.println("--- " + classNode.getName() + " ---"); + return super.visit(classNode, data); + } else { + return data; + } + } + + @Override + public Object visit(FieldNode fieldNode, Object data) { + if (fieldNode.getUsers().isEmpty()) { + boolean log = true; + // A field is inlinable if: + // 1) It is final + // 2) It is a primitive, or a java.lang.String + if (options.isIgnoreFieldInlinable()) { + if (Modifier.isFinal(fieldNode.getMember().getModifiers()) + && fieldNode.getMember().getType().isPrimitive() + || fieldNode.getMember().getType().getName().equals("java.lang.String")) { + ignore("field inlinable", fieldNode); + log = false; + } + } + if (log) { + System.out.println("\t" + fieldNode.toStringLong()); + } + } + return super.visit(fieldNode, data); + } + + @Override + public Object visit(ConstructorNode constructorNode, Object data) { + if (constructorNode.getUsers().isEmpty()) { + boolean log = true; + if (constructorNode.isStaticInitializer()) { + if (options.isIgnoreConstructorStaticInitializer()) { + ignore("constructor static initializer", constructorNode); + log = false; + } + } else if (constructorNode.isInstanceInitializer()) { + if (Modifier.isPrivate(constructorNode.getMember().getModifiers())) { + if (options.isIgnoreConstructorAllPrivate()) { + ignore("constructor all private", constructorNode); + log = false; + } else if (options.isIgnoreConstructorSinglePrivateNoArg() + && constructorNode.getMember().getParameterTypes().length == 0 + && constructorNode.getClassNode().getConstructorNodes().size() == 1) { + ignore("constructor single private no-arg", constructorNode); + log = false; + } + } + } + if (log) { + System.out.println("\t" + constructorNode.toStringLong()); + } + } + return super.visit(constructorNode, data); + } + + private static boolean isMainMethod(MethodNode node) { + + final Method method = node.getMember(); + + return method.getName().equals("main") && Modifier.isPublic(method.getModifiers()) + && Modifier.isStatic(method.getModifiers()) && method.getReturnType() == Void.TYPE + && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isArray() + && method.getParameterTypes()[0].getComponentType().equals(java.lang.String.class); + } + + @Override + public Object visit(MethodNode methodNode, Object data) { + if (methodNode.getUsers().isEmpty()) { + boolean log = true; + if (options.isIgnoreMethodAllOverride()) { + if (ClassLoaderUtil.isOverridenMethod(methodNode.getClassNode().getClass(), methodNode.getMember(), + false)) { + ignore("method all override", methodNode); + log = false; + } + } else if (options.isIgnoreMethodJavaLangObjectOverride()) { + if (ClassLoaderUtil.isOverridenMethod(java.lang.Object.class, methodNode.getMember(), true)) { + ignore("method java.lang.Object override", methodNode); + log = false; + } + } + if (options.isIgnoreMethodMain()) { + if (isMainMethod(methodNode)) { + ignore("method public static void main(String[])", methodNode); + log = false; + } + } + if (log) { + System.out.println("\t" + methodNode.toStringLong()); + } + } + return super.visit(methodNode, data); + } + + private void ignore(String description, ClassNode classNode) { + System.out.println("Ignoring " + description + ": " + classNode.getName()); + } + + private void ignore(String description, MemberNode memberNode) { + System.out.println("Ignoring " + description + ": " + memberNode.toStringLong()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/PrintVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/PrintVisitor.java index 7ac1d2c255..4cebe449f9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/PrintVisitor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/PrintVisitor.java @@ -1,39 +1,39 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.asm; - -public class PrintVisitor { - - private static final String INDENT = "\t"; - - private final int level; - - public PrintVisitor() { - this(0); - } - - public PrintVisitor(PrintVisitor parent) { - this(parent.level + 2); - } - - public PrintVisitor(int level) { - this.level = level; - } - - public void println(String s) { - println(this.level, s); - } - - public void printlnIndent(String s) { - println(this.level + 1, s); - } - - private void println(int level, String s) { - for (int i = 0; i < level; i++) { - System.out.print(INDENT); - } - System.out.println(s); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.asm; + +public class PrintVisitor { + + private static final String INDENT = "\t"; + + private final int level; + + public PrintVisitor() { + this(0); + } + + public PrintVisitor(PrintVisitor parent) { + this(parent.level + 2); + } + + public PrintVisitor(int level) { + this.level = level; + } + + public void println(String s) { + println(this.level, s); + } + + public void printlnIndent(String s) { + println(this.level + 1, s); + } + + private void println(int level, String s) { + for (int i = 0; i < level; i++) { + System.out.print(INDENT); + } + System.out.println(s); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/TypeSignatureVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/TypeSignatureVisitor.java index ffa558f76f..1d34c106a8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/TypeSignatureVisitor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/asm/TypeSignatureVisitor.java @@ -1,307 +1,307 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.asm; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.List; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.signature.SignatureVisitor; - -import net.sourceforge.pmd.dcd.ClassLoaderUtil; - -public class TypeSignatureVisitor extends SignatureVisitor { - - private static final boolean TRACE = false; - - private static final int NO_TYPE = 0; - - private static final int FIELD_TYPE = 1; - - private static final int RETURN_TYPE = 2; - - private static final int PARAMETER_TYPE = 3; - - // The type of the current Type - private int typeType; - - // The current Type identified. - private Class type; - - // The number of dimensions on an array for the current Type. - private int arrayDimensions = 0; - - // Completed Field Type is stored here - private Class fieldType; - - // Completed Return Type is stored here - private Class returnType; - - // Completed Parameter Types are stored here - private List> parameterTypes = new ArrayList<>(0); - - private final PrintVisitor p; - - public TypeSignatureVisitor() { - super(Opcodes.ASM5); - p = new PrintVisitor(); - init(); - } - - public TypeSignatureVisitor(PrintVisitor parent) { - super(Opcodes.ASM5); - p = new PrintVisitor(parent); - init(); - } - - protected void println(String s) { - p.println(s); - } - - protected void printlnIndent(String s) { - p.printlnIndent(s); - } - - public void init() { - typeType = FIELD_TYPE; - type = null; - arrayDimensions = 0; - parameterTypes.clear(); - } - - public Class getFieldType() { - popType(); - if (fieldType == null) { - throw new RuntimeException(); - } - return fieldType; - } - - public Class getMethodReturnType() { - popType(); - if (returnType == null) { - throw new RuntimeException(); - } - return returnType; - } - - public Class[] getMethodParameterTypes() { - popType(); - if (parameterTypes == null) { - throw new RuntimeException(); - } - if (parameterTypes != null) { - return parameterTypes.toArray(new Class[parameterTypes.size()]); - } else { - return null; - } - } - - private void pushType(int type) { - this.typeType = type; - } - - private void popType() { - switch (typeType) { - case NO_TYPE: - break; - case FIELD_TYPE: - fieldType = getType(); - break; - case RETURN_TYPE: - returnType = getType(); - break; - case PARAMETER_TYPE: - parameterTypes.add(getType()); - break; - default: - throw new RuntimeException("Unknown type type: " + typeType); - } - - typeType = NO_TYPE; - type = null; - arrayDimensions = 0; - } - - private Class getType() { - Class type = null; - if (this.type != null) { - type = this.type; - for (int i = 0; i < arrayDimensions; i++) { - // Is there another way to get Array Classes? - Object array = Array.newInstance(type, 0); - type = array.getClass(); - } - } - return type; - } - - @Override - public SignatureVisitor visitArrayType() { - if (TRACE) { - println("visitArrayType:"); - } - arrayDimensions++; - return this; - } - - @Override - public void visitBaseType(char descriptor) { - if (TRACE) { - println("visitBaseType:"); - printlnIndent("descriptor: " + descriptor); - } - switch (descriptor) { - case 'B': - type = Byte.TYPE; - break; - case 'C': - type = Character.TYPE; - break; - case 'D': - type = Double.TYPE; - break; - case 'F': - type = Float.TYPE; - break; - case 'I': - type = Integer.TYPE; - break; - case 'J': - type = Long.TYPE; - break; - case 'S': - type = Short.TYPE; - break; - case 'Z': - type = Boolean.TYPE; - break; - case 'V': - type = Void.TYPE; - break; - default: - throw new RuntimeException("Unknown baseType descriptor: " + descriptor); - } - } - - @Override - public SignatureVisitor visitClassBound() { - if (TRACE) { - println("visitClassBound:"); - } - return this; - } - - @Override - public void visitClassType(String name) { - if (TRACE) { - println("visitClassType:"); - printlnIndent("name: " + name); - } - name = ClassLoaderUtil.fromInternalForm(name); - this.type = ClassLoaderUtil.getClass(name); - } - - @Override - public void visitEnd() { - if (TRACE) { - println("visitEnd:"); - } - popType(); - } - - @Override - public SignatureVisitor visitExceptionType() { - if (TRACE) { - println("visitExceptionType:"); - } - return this; - } - - @Override - public void visitFormalTypeParameter(String name) { - if (TRACE) { - println("visitFormalTypeParameter:"); - printlnIndent("name: " + name); - } - } - - @Override - public void visitInnerClassType(String name) { - if (TRACE) { - println("visitInnerClassType:"); - printlnIndent("name: " + name); - } - } - - @Override - public SignatureVisitor visitInterface() { - if (TRACE) { - println("visitInterface:"); - } - return this; - } - - @Override - public SignatureVisitor visitInterfaceBound() { - if (TRACE) { - println("visitInterfaceBound:"); - } - return this; - } - - @Override - public SignatureVisitor visitParameterType() { - if (TRACE) { - println("visitParameterType:"); - } - popType(); - pushType(PARAMETER_TYPE); - return this; - } - - @Override - public SignatureVisitor visitReturnType() { - if (TRACE) { - println("visitReturnType:"); - } - popType(); - pushType(RETURN_TYPE); - return this; - } - - @Override - public SignatureVisitor visitSuperclass() { - if (TRACE) { - println("visitSuperclass:"); - } - return this; - } - - @Override - public void visitTypeArgument() { - if (TRACE) { - println("visitTypeArgument:"); - } - } - - @Override - public SignatureVisitor visitTypeArgument(char wildcard) { - if (TRACE) { - println("visitTypeArgument:"); - printlnIndent("wildcard: " + wildcard); - } - return this; - } - - @Override - public void visitTypeVariable(String name) { - if (TRACE) { - println("visitTypeVariable:"); - printlnIndent("name: " + name); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.asm; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.signature.SignatureVisitor; + +import net.sourceforge.pmd.dcd.ClassLoaderUtil; + +public class TypeSignatureVisitor extends SignatureVisitor { + + private static final boolean TRACE = false; + + private static final int NO_TYPE = 0; + + private static final int FIELD_TYPE = 1; + + private static final int RETURN_TYPE = 2; + + private static final int PARAMETER_TYPE = 3; + + // The type of the current Type + private int typeType; + + // The current Type identified. + private Class type; + + // The number of dimensions on an array for the current Type. + private int arrayDimensions = 0; + + // Completed Field Type is stored here + private Class fieldType; + + // Completed Return Type is stored here + private Class returnType; + + // Completed Parameter Types are stored here + private List> parameterTypes = new ArrayList<>(0); + + private final PrintVisitor p; + + public TypeSignatureVisitor() { + super(Opcodes.ASM5); + p = new PrintVisitor(); + init(); + } + + public TypeSignatureVisitor(PrintVisitor parent) { + super(Opcodes.ASM5); + p = new PrintVisitor(parent); + init(); + } + + protected void println(String s) { + p.println(s); + } + + protected void printlnIndent(String s) { + p.printlnIndent(s); + } + + public void init() { + typeType = FIELD_TYPE; + type = null; + arrayDimensions = 0; + parameterTypes.clear(); + } + + public Class getFieldType() { + popType(); + if (fieldType == null) { + throw new RuntimeException(); + } + return fieldType; + } + + public Class getMethodReturnType() { + popType(); + if (returnType == null) { + throw new RuntimeException(); + } + return returnType; + } + + public Class[] getMethodParameterTypes() { + popType(); + if (parameterTypes == null) { + throw new RuntimeException(); + } + if (parameterTypes != null) { + return parameterTypes.toArray(new Class[parameterTypes.size()]); + } else { + return null; + } + } + + private void pushType(int type) { + this.typeType = type; + } + + private void popType() { + switch (typeType) { + case NO_TYPE: + break; + case FIELD_TYPE: + fieldType = getType(); + break; + case RETURN_TYPE: + returnType = getType(); + break; + case PARAMETER_TYPE: + parameterTypes.add(getType()); + break; + default: + throw new RuntimeException("Unknown type type: " + typeType); + } + + typeType = NO_TYPE; + type = null; + arrayDimensions = 0; + } + + private Class getType() { + Class type = null; + if (this.type != null) { + type = this.type; + for (int i = 0; i < arrayDimensions; i++) { + // Is there another way to get Array Classes? + Object array = Array.newInstance(type, 0); + type = array.getClass(); + } + } + return type; + } + + @Override + public SignatureVisitor visitArrayType() { + if (TRACE) { + println("visitArrayType:"); + } + arrayDimensions++; + return this; + } + + @Override + public void visitBaseType(char descriptor) { + if (TRACE) { + println("visitBaseType:"); + printlnIndent("descriptor: " + descriptor); + } + switch (descriptor) { + case 'B': + type = Byte.TYPE; + break; + case 'C': + type = Character.TYPE; + break; + case 'D': + type = Double.TYPE; + break; + case 'F': + type = Float.TYPE; + break; + case 'I': + type = Integer.TYPE; + break; + case 'J': + type = Long.TYPE; + break; + case 'S': + type = Short.TYPE; + break; + case 'Z': + type = Boolean.TYPE; + break; + case 'V': + type = Void.TYPE; + break; + default: + throw new RuntimeException("Unknown baseType descriptor: " + descriptor); + } + } + + @Override + public SignatureVisitor visitClassBound() { + if (TRACE) { + println("visitClassBound:"); + } + return this; + } + + @Override + public void visitClassType(String name) { + if (TRACE) { + println("visitClassType:"); + printlnIndent("name: " + name); + } + name = ClassLoaderUtil.fromInternalForm(name); + this.type = ClassLoaderUtil.getClass(name); + } + + @Override + public void visitEnd() { + if (TRACE) { + println("visitEnd:"); + } + popType(); + } + + @Override + public SignatureVisitor visitExceptionType() { + if (TRACE) { + println("visitExceptionType:"); + } + return this; + } + + @Override + public void visitFormalTypeParameter(String name) { + if (TRACE) { + println("visitFormalTypeParameter:"); + printlnIndent("name: " + name); + } + } + + @Override + public void visitInnerClassType(String name) { + if (TRACE) { + println("visitInnerClassType:"); + printlnIndent("name: " + name); + } + } + + @Override + public SignatureVisitor visitInterface() { + if (TRACE) { + println("visitInterface:"); + } + return this; + } + + @Override + public SignatureVisitor visitInterfaceBound() { + if (TRACE) { + println("visitInterfaceBound:"); + } + return this; + } + + @Override + public SignatureVisitor visitParameterType() { + if (TRACE) { + println("visitParameterType:"); + } + popType(); + pushType(PARAMETER_TYPE); + return this; + } + + @Override + public SignatureVisitor visitReturnType() { + if (TRACE) { + println("visitReturnType:"); + } + popType(); + pushType(RETURN_TYPE); + return this; + } + + @Override + public SignatureVisitor visitSuperclass() { + if (TRACE) { + println("visitSuperclass:"); + } + return this; + } + + @Override + public void visitTypeArgument() { + if (TRACE) { + println("visitTypeArgument:"); + } + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + if (TRACE) { + println("visitTypeArgument:"); + printlnIndent("wildcard: " + wildcard); + } + return this; + } + + @Override + public void visitTypeVariable(String name) { + if (TRACE) { + println("visitTypeVariable:"); + printlnIndent("name: " + name); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNode.java index 72b8ab5e70..39059fa201 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNode.java @@ -1,128 +1,128 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import net.sourceforge.pmd.dcd.ClassLoaderUtil; - -/** - * Represents a Class in a UsageGraph. Contains lists of FieldNodes, - * ConstructorNodes, and MethodNodes. - */ -public class ClassNode implements NodeVisitorAcceptor, Comparable { - - private final String name; - - private WeakReference> typeReference; - - private List fieldNodes; - - private List constructorNodes; - - private List methodNodes; - - public ClassNode(String name) { - this.name = name; - } - - @Override - public Object accept(NodeVisitor visitor, Object data) { - visitor.visitFields(this, data); - visitor.visitConstructors(this, data); - visitor.visitMethods(this, data); - return data; - } - - public String getName() { - return name; - } - - public Class getType() { - Class type = typeReference == null ? null : typeReference.get(); - if (type == null) { - type = ClassLoaderUtil.getClass(ClassLoaderUtil.fromInternalForm(name)); - typeReference = new WeakReference>(type); - } - return type; - } - - public FieldNode defineField(String name, String desc) { - if (fieldNodes == null) { - fieldNodes = new ArrayList<>(1); - } - for (FieldNode fieldNode : fieldNodes) { - if (fieldNode.equals(name, desc)) { - return fieldNode; - } - } - FieldNode fieldNode = new FieldNode(this, name, desc); - fieldNodes.add(fieldNode); - return fieldNode; - } - - public ConstructorNode defineConstructor(String name, String desc) { - if (constructorNodes == null) { - constructorNodes = new ArrayList<>(1); - } - for (ConstructorNode constructorNode : constructorNodes) { - if (constructorNode.equals(name, desc)) { - return constructorNode; - } - } - - ConstructorNode constructorNode = new ConstructorNode(this, name, desc); - constructorNodes.add(constructorNode); - return constructorNode; - } - - public MethodNode defineMethod(String name, String desc) { - if (methodNodes == null) { - methodNodes = new ArrayList<>(1); - } - for (MethodNode methodNode : methodNodes) { - if (methodNode.equals(name, desc)) { - return methodNode; - } - } - - MethodNode methodNode = new MethodNode(this, name, desc); - methodNodes.add(methodNode); - return methodNode; - } - - public List getFieldNodes() { - return fieldNodes != null ? fieldNodes : Collections.emptyList(); - } - - public List getConstructorNodes() { - return constructorNodes != null ? constructorNodes : Collections.emptyList(); - } - - public List getMethodNodes() { - return methodNodes != null ? methodNodes : Collections.emptyList(); - } - - @Override - public int compareTo(ClassNode that) { - return this.name.compareTo(that.name); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ClassNode) { - return this.name.equals(((ClassNode) obj).name); - } - return false; - } - - @Override - public int hashCode() { - return name.hashCode(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.dcd.ClassLoaderUtil; + +/** + * Represents a Class in a UsageGraph. Contains lists of FieldNodes, + * ConstructorNodes, and MethodNodes. + */ +public class ClassNode implements NodeVisitorAcceptor, Comparable { + + private final String name; + + private WeakReference> typeReference; + + private List fieldNodes; + + private List constructorNodes; + + private List methodNodes; + + public ClassNode(String name) { + this.name = name; + } + + @Override + public Object accept(NodeVisitor visitor, Object data) { + visitor.visitFields(this, data); + visitor.visitConstructors(this, data); + visitor.visitMethods(this, data); + return data; + } + + public String getName() { + return name; + } + + public Class getType() { + Class type = typeReference == null ? null : typeReference.get(); + if (type == null) { + type = ClassLoaderUtil.getClass(ClassLoaderUtil.fromInternalForm(name)); + typeReference = new WeakReference>(type); + } + return type; + } + + public FieldNode defineField(String name, String desc) { + if (fieldNodes == null) { + fieldNodes = new ArrayList<>(1); + } + for (FieldNode fieldNode : fieldNodes) { + if (fieldNode.equals(name, desc)) { + return fieldNode; + } + } + FieldNode fieldNode = new FieldNode(this, name, desc); + fieldNodes.add(fieldNode); + return fieldNode; + } + + public ConstructorNode defineConstructor(String name, String desc) { + if (constructorNodes == null) { + constructorNodes = new ArrayList<>(1); + } + for (ConstructorNode constructorNode : constructorNodes) { + if (constructorNode.equals(name, desc)) { + return constructorNode; + } + } + + ConstructorNode constructorNode = new ConstructorNode(this, name, desc); + constructorNodes.add(constructorNode); + return constructorNode; + } + + public MethodNode defineMethod(String name, String desc) { + if (methodNodes == null) { + methodNodes = new ArrayList<>(1); + } + for (MethodNode methodNode : methodNodes) { + if (methodNode.equals(name, desc)) { + return methodNode; + } + } + + MethodNode methodNode = new MethodNode(this, name, desc); + methodNodes.add(methodNode); + return methodNode; + } + + public List getFieldNodes() { + return fieldNodes != null ? fieldNodes : Collections.emptyList(); + } + + public List getConstructorNodes() { + return constructorNodes != null ? constructorNodes : Collections.emptyList(); + } + + public List getMethodNodes() { + return methodNodes != null ? methodNodes : Collections.emptyList(); + } + + @Override + public int compareTo(ClassNode that) { + return this.name.compareTo(that.name); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ClassNode) { + return this.name.equals(((ClassNode) obj).name); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNodeComparator.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNodeComparator.java index 1053396d49..165b8a809d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNodeComparator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ClassNodeComparator.java @@ -1,32 +1,32 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.util.Comparator; - -/** - * Compares ClassNodes by the name of the class. Can also compare String class - * names to ClassNodes. - */ -public final class ClassNodeComparator implements Comparator { - - public static final ClassNodeComparator INSTANCE = new ClassNodeComparator(); - - private ClassNodeComparator() { - } - - @Override - public int compare(Object obj1, Object obj2) { - if (obj1 instanceof String && obj2 instanceof String) { - return ((String) obj1).compareTo((String) obj2); - } else if (obj1 instanceof String) { - return ((String) obj1).compareTo(((ClassNode) obj2).getName()); - } else if (obj2 instanceof String) { - return ((ClassNode) obj1).getName().compareTo((String) obj2); - } else { - return ((ClassNode) obj1).compareTo((ClassNode) obj2); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.util.Comparator; + +/** + * Compares ClassNodes by the name of the class. Can also compare String class + * names to ClassNodes. + */ +public final class ClassNodeComparator implements Comparator { + + public static final ClassNodeComparator INSTANCE = new ClassNodeComparator(); + + private ClassNodeComparator() { + } + + @Override + public int compare(Object obj1, Object obj2) { + if (obj1 instanceof String && obj2 instanceof String) { + return ((String) obj1).compareTo((String) obj2); + } else if (obj1 instanceof String) { + return ((String) obj1).compareTo(((ClassNode) obj2).getName()); + } else if (obj2 instanceof String) { + return ((ClassNode) obj1).getName().compareTo((String) obj2); + } else { + return ((ClassNode) obj1).compareTo((ClassNode) obj2); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ConstructorNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ConstructorNode.java index 6f2c6b1319..7dd9c2bada 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ConstructorNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/ConstructorNode.java @@ -1,100 +1,100 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Constructor; - -import org.objectweb.asm.signature.SignatureReader; - -import net.sourceforge.pmd.dcd.ClassLoaderUtil; -import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor; - -/** - * Represents a Class Constructor in a UsageGraph. - */ -@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode") -public class ConstructorNode extends MemberNode> { - - private WeakReference> constructorReference; - - public ConstructorNode(ClassNode classNode, String name, String desc) { - super(classNode, name, desc); - // getMember(); - } - - public boolean isStaticInitializer() { - return ClassLoaderUtil.CLINIT.equals(name); - } - - public boolean isInstanceInitializer() { - return ClassLoaderUtil.INIT.equals(name); - } - - @Override - public Constructor getMember() { - if (ClassLoaderUtil.CLINIT.equals(name)) { - return null; - } else { - Constructor constructor = constructorReference == null ? null : constructorReference.get(); - if (constructor == null) { - SignatureReader signatureReader = new SignatureReader(desc); - TypeSignatureVisitor visitor = new TypeSignatureVisitor(); - signatureReader.accept(visitor); - constructor = ClassLoaderUtil.getConstructor(super.getClassNode().getType(), name, - visitor.getMethodParameterTypes()); - constructorReference = new WeakReference>(constructor); - } - return constructor; - } - } - - @Override - public String toStringLong() { - if (ClassLoaderUtil.CLINIT.equals(name)) { - return name; - } else { - return super.toStringLong(); - } - } - - @Override - public int compareTo(ConstructorNode that) { - // Order by name - int cmp = this.getName().compareTo(that.getName()); - if (cmp == 0) { - // Order by parameter list length - cmp = this.getMember().getParameterTypes().length - that.getMember().getParameterTypes().length; - if (cmp == 0) { - // Order by parameter class name - for (int i = 0; i < this.getMember().getParameterTypes().length; i++) { - cmp = this.getMember().getParameterTypes()[i].getName() - .compareTo(that.getMember().getParameterTypes()[i].getName()); - if (cmp != 0) { - break; - } - } - } - } - return cmp; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ConstructorNode) { - ConstructorNode that = (ConstructorNode) obj; - return super.equals(that); - } - return false; - } - - /* (non-Javadoc) - * @see net.sourceforge.pmd.dcd.graph.MemberNode#hashCode() - */ - @Override - public int hashCode() { - return super.hashCode(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; + +import org.objectweb.asm.signature.SignatureReader; + +import net.sourceforge.pmd.dcd.ClassLoaderUtil; +import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor; + +/** + * Represents a Class Constructor in a UsageGraph. + */ +@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode") +public class ConstructorNode extends MemberNode> { + + private WeakReference> constructorReference; + + public ConstructorNode(ClassNode classNode, String name, String desc) { + super(classNode, name, desc); + // getMember(); + } + + public boolean isStaticInitializer() { + return ClassLoaderUtil.CLINIT.equals(name); + } + + public boolean isInstanceInitializer() { + return ClassLoaderUtil.INIT.equals(name); + } + + @Override + public Constructor getMember() { + if (ClassLoaderUtil.CLINIT.equals(name)) { + return null; + } else { + Constructor constructor = constructorReference == null ? null : constructorReference.get(); + if (constructor == null) { + SignatureReader signatureReader = new SignatureReader(desc); + TypeSignatureVisitor visitor = new TypeSignatureVisitor(); + signatureReader.accept(visitor); + constructor = ClassLoaderUtil.getConstructor(super.getClassNode().getType(), name, + visitor.getMethodParameterTypes()); + constructorReference = new WeakReference>(constructor); + } + return constructor; + } + } + + @Override + public String toStringLong() { + if (ClassLoaderUtil.CLINIT.equals(name)) { + return name; + } else { + return super.toStringLong(); + } + } + + @Override + public int compareTo(ConstructorNode that) { + // Order by name + int cmp = this.getName().compareTo(that.getName()); + if (cmp == 0) { + // Order by parameter list length + cmp = this.getMember().getParameterTypes().length - that.getMember().getParameterTypes().length; + if (cmp == 0) { + // Order by parameter class name + for (int i = 0; i < this.getMember().getParameterTypes().length; i++) { + cmp = this.getMember().getParameterTypes()[i].getName() + .compareTo(that.getMember().getParameterTypes()[i].getName()); + if (cmp != 0) { + break; + } + } + } + } + return cmp; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConstructorNode) { + ConstructorNode that = (ConstructorNode) obj; + return super.equals(that); + } + return false; + } + + /* (non-Javadoc) + * @see net.sourceforge.pmd.dcd.graph.MemberNode#hashCode() + */ + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/FieldNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/FieldNode.java index 9722fbc6da..1944e4baf6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/FieldNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/FieldNode.java @@ -1,56 +1,56 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; - -import net.sourceforge.pmd.dcd.ClassLoaderUtil; - -/** - * Represents a Class Field in a UsageGraph. - */ -@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode") -public class FieldNode extends MemberNode { - - private WeakReference fieldReference; - - public FieldNode(ClassNode classNode, String name, String desc) { - super(classNode, name, desc); - getMember(); - } - - @Override - public Field getMember() { - Field field = fieldReference == null ? null : fieldReference.get(); - if (field == null) { - field = ClassLoaderUtil.getField(getClassNode().getType(), name); - this.fieldReference = new WeakReference<>(field); - } - return field; - } - - @Override - public int compareTo(FieldNode that) { - return this.name.compareTo(that.name); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof FieldNode) { - FieldNode that = (FieldNode) obj; - return super.equals(that); - } - return false; - } - - /* (non-Javadoc) - * @see net.sourceforge.pmd.dcd.graph.MemberNode#hashCode() - */ - @Override - public int hashCode() { - return super.hashCode(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; + +import net.sourceforge.pmd.dcd.ClassLoaderUtil; + +/** + * Represents a Class Field in a UsageGraph. + */ +@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode") +public class FieldNode extends MemberNode { + + private WeakReference fieldReference; + + public FieldNode(ClassNode classNode, String name, String desc) { + super(classNode, name, desc); + getMember(); + } + + @Override + public Field getMember() { + Field field = fieldReference == null ? null : fieldReference.get(); + if (field == null) { + field = ClassLoaderUtil.getField(getClassNode().getType(), name); + this.fieldReference = new WeakReference<>(field); + } + return field; + } + + @Override + public int compareTo(FieldNode that) { + return this.name.compareTo(that.name); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FieldNode) { + FieldNode that = (FieldNode) obj; + return super.equals(that); + } + return false; + } + + /* (non-Javadoc) + * @see net.sourceforge.pmd.dcd.graph.MemberNode#hashCode() + */ + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNode.java index 2df26997ad..8f85abe991 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNode.java @@ -1,143 +1,143 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.lang.reflect.Member; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Represents a Class Member in a UsageGraph. - */ -public abstract class MemberNode, T extends Member> - implements NodeVisitorAcceptor, Comparable { - protected final ClassNode classNode; - - protected final String name; - - protected final String desc; - - private List uses; - - private List users; - - private Object decoration; - - public MemberNode(ClassNode classNode, String name, String desc) { - this.classNode = classNode; - this.name = name; - this.desc = desc; - } - - @Override - public Object accept(NodeVisitor visitor, Object data) { - visitor.visitUses(this, data); - visitor.visitUsers(this, data); - return data; - } - - public ClassNode getClassNode() { - return classNode; - } - - public String getName() { - return name; - } - - public String getDesc() { - return desc; - } - - public abstract T getMember(); - - public void addUse(MemberNode use) { - if (uses == null) { - uses = new ArrayList<>(1); - } - if (!uses.contains(use)) { - uses.add(use); - } - } - - public List getUses() { - return uses != null ? uses : Collections.emptyList(); - } - - public void addUser(MemberNode user) { - if (users == null) { - users = new ArrayList<>(1); - } - if (!users.contains(user)) { - users.add(user); - } - } - - public List getUsers() { - return users != null ? users : Collections.emptyList(); - } - - @Override - public String toString() { - return name + " " + desc; - } - - public String toStringLong() { - return getMember().toString(); - } - - @SuppressWarnings("PMD.SuspiciousEqualsMethodName") - public boolean equals(S that) { - return equals(that.name, that.desc); - } - - public boolean equals(String name, String desc) { - return this.name.equals(name) && this.desc.equals(desc); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((desc == null) ? 0 : desc.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - MemberNode other = (MemberNode) obj; - if (desc == null) { - if (other.desc != null) { - return false; - } - } else if (!desc.equals(other.desc)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - return true; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.lang.reflect.Member; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Represents a Class Member in a UsageGraph. + */ +public abstract class MemberNode, T extends Member> + implements NodeVisitorAcceptor, Comparable { + protected final ClassNode classNode; + + protected final String name; + + protected final String desc; + + private List uses; + + private List users; + + private Object decoration; + + public MemberNode(ClassNode classNode, String name, String desc) { + this.classNode = classNode; + this.name = name; + this.desc = desc; + } + + @Override + public Object accept(NodeVisitor visitor, Object data) { + visitor.visitUses(this, data); + visitor.visitUsers(this, data); + return data; + } + + public ClassNode getClassNode() { + return classNode; + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public abstract T getMember(); + + public void addUse(MemberNode use) { + if (uses == null) { + uses = new ArrayList<>(1); + } + if (!uses.contains(use)) { + uses.add(use); + } + } + + public List getUses() { + return uses != null ? uses : Collections.emptyList(); + } + + public void addUser(MemberNode user) { + if (users == null) { + users = new ArrayList<>(1); + } + if (!users.contains(user)) { + users.add(user); + } + } + + public List getUsers() { + return users != null ? users : Collections.emptyList(); + } + + @Override + public String toString() { + return name + " " + desc; + } + + public String toStringLong() { + return getMember().toString(); + } + + @SuppressWarnings("PMD.SuspiciousEqualsMethodName") + public boolean equals(S that) { + return equals(that.name, that.desc); + } + + public boolean equals(String name, String desc) { + return this.name.equals(name) && this.desc.equals(desc); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((desc == null) ? 0 : desc.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MemberNode other = (MemberNode) obj; + if (desc == null) { + if (other.desc != null) { + return false; + } + } else if (!desc.equals(other.desc)) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNodeComparator.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNodeComparator.java index 23455143d8..a9dcfc1460 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNodeComparator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MemberNodeComparator.java @@ -1,44 +1,44 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.util.Comparator; - -/** - * Compares MemberNodes. FieldNodes are smaller than ConstructorNodes which are - * smaller than MethodNodes. - */ -public final class MemberNodeComparator implements Comparator { - - public static final MemberNodeComparator INSTANCE = new MemberNodeComparator(); - - private MemberNodeComparator() { - } - - @Override - public int compare(MemberNode node1, MemberNode node2) { - if (node1 instanceof FieldNode) { - if (node2 instanceof FieldNode) { - return node1.compareTo(node2); - } else { - return -1; - } - } else if (node1 instanceof ConstructorNode) { - if (node2 instanceof FieldNode) { - return 1; - } else if (node2 instanceof ConstructorNode) { - return node1.compareTo(node2); - } else { - return -1; - } - } else { - if (node2 instanceof MethodNode) { - return node1.compareTo(node2); - } else { - return 1; - } - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.util.Comparator; + +/** + * Compares MemberNodes. FieldNodes are smaller than ConstructorNodes which are + * smaller than MethodNodes. + */ +public final class MemberNodeComparator implements Comparator { + + public static final MemberNodeComparator INSTANCE = new MemberNodeComparator(); + + private MemberNodeComparator() { + } + + @Override + public int compare(MemberNode node1, MemberNode node2) { + if (node1 instanceof FieldNode) { + if (node2 instanceof FieldNode) { + return node1.compareTo(node2); + } else { + return -1; + } + } else if (node1 instanceof ConstructorNode) { + if (node2 instanceof FieldNode) { + return 1; + } else if (node2 instanceof ConstructorNode) { + return node1.compareTo(node2); + } else { + return -1; + } + } else { + if (node2 instanceof MethodNode) { + return node1.compareTo(node2); + } else { + return 1; + } + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MethodNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MethodNode.java index 67a4c656b2..8559bb762c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MethodNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/MethodNode.java @@ -1,78 +1,78 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Method; - -import org.objectweb.asm.signature.SignatureReader; - -import net.sourceforge.pmd.dcd.ClassLoaderUtil; -import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor; - -/** - * Represents a Class Method in a UsageGraph. - */ -@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode") -public class MethodNode extends MemberNode { - - private WeakReference methodReference; - - public MethodNode(ClassNode classNode, String name, String desc) { - super(classNode, name, desc); - // getMember(); - } - - @Override - public Method getMember() { - Method method = methodReference == null ? null : methodReference.get(); - if (method == null) { - SignatureReader signatureReader = new SignatureReader(desc); - TypeSignatureVisitor visitor = new TypeSignatureVisitor(); - signatureReader.accept(visitor); - method = ClassLoaderUtil.getMethod(super.getClassNode().getType(), name, visitor.getMethodParameterTypes()); - methodReference = new WeakReference<>(method); - } - return method; - } - - @Override - public int compareTo(MethodNode that) { - // Order by method name - int cmp = this.getName().compareTo(that.getName()); - if (cmp == 0) { - // Order by parameter list length - cmp = this.getMember().getParameterTypes().length - that.getMember().getParameterTypes().length; - if (cmp == 0) { - // Order by parameter class name - for (int i = 0; i < this.getMember().getParameterTypes().length; i++) { - cmp = this.getMember().getParameterTypes()[i].getName() - .compareTo(that.getMember().getParameterTypes()[i].getName()); - if (cmp != 0) { - break; - } - } - } - } - return cmp; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof MethodNode) { - MethodNode that = (MethodNode) obj; - return super.equals(that); - } - return false; - } - - /* (non-Javadoc) - * @see net.sourceforge.pmd.dcd.graph.MemberNode#hashCode() - */ - @Override - public int hashCode() { - return super.hashCode(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; + +import org.objectweb.asm.signature.SignatureReader; + +import net.sourceforge.pmd.dcd.ClassLoaderUtil; +import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor; + +/** + * Represents a Class Method in a UsageGraph. + */ +@SuppressWarnings("PMD.OverrideBothEqualsAndHashcode") +public class MethodNode extends MemberNode { + + private WeakReference methodReference; + + public MethodNode(ClassNode classNode, String name, String desc) { + super(classNode, name, desc); + // getMember(); + } + + @Override + public Method getMember() { + Method method = methodReference == null ? null : methodReference.get(); + if (method == null) { + SignatureReader signatureReader = new SignatureReader(desc); + TypeSignatureVisitor visitor = new TypeSignatureVisitor(); + signatureReader.accept(visitor); + method = ClassLoaderUtil.getMethod(super.getClassNode().getType(), name, visitor.getMethodParameterTypes()); + methodReference = new WeakReference<>(method); + } + return method; + } + + @Override + public int compareTo(MethodNode that) { + // Order by method name + int cmp = this.getName().compareTo(that.getName()); + if (cmp == 0) { + // Order by parameter list length + cmp = this.getMember().getParameterTypes().length - that.getMember().getParameterTypes().length; + if (cmp == 0) { + // Order by parameter class name + for (int i = 0; i < this.getMember().getParameterTypes().length; i++) { + cmp = this.getMember().getParameterTypes()[i].getName() + .compareTo(that.getMember().getParameterTypes()[i].getName()); + if (cmp != 0) { + break; + } + } + } + } + return cmp; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MethodNode) { + MethodNode that = (MethodNode) obj; + return super.equals(that); + } + return false; + } + + /* (non-Javadoc) + * @see net.sourceforge.pmd.dcd.graph.MemberNode#hashCode() + */ + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitor.java index bbe362b412..b985a5f585 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitor.java @@ -1,35 +1,35 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -/** - * Visitor for nodes in a UsageGraph. - */ -public interface NodeVisitor { - - Object visit(UsageGraph usageGraph, Object data); - - Object visit(ClassNode classNode, Object data); - - Object visitFields(ClassNode classNode, Object data); - - Object visit(FieldNode fieldNode, Object data); - - Object visitConstructors(ClassNode classNode, Object data); - - Object visit(ConstructorNode constructorNode, Object data); - - Object visitMethods(ClassNode classNode, Object data); - - Object visit(MethodNode methodNode, Object data); - - Object visitUses(MemberNode memberNode, Object data); - - Object visitUse(MemberNode use, Object data); - - Object visitUsers(MemberNode memberNode, Object data); - - Object visitUser(MemberNode user, Object data); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +/** + * Visitor for nodes in a UsageGraph. + */ +public interface NodeVisitor { + + Object visit(UsageGraph usageGraph, Object data); + + Object visit(ClassNode classNode, Object data); + + Object visitFields(ClassNode classNode, Object data); + + Object visit(FieldNode fieldNode, Object data); + + Object visitConstructors(ClassNode classNode, Object data); + + Object visit(ConstructorNode constructorNode, Object data); + + Object visitMethods(ClassNode classNode, Object data); + + Object visit(MethodNode methodNode, Object data); + + Object visitUses(MemberNode memberNode, Object data); + + Object visitUse(MemberNode use, Object data); + + Object visitUsers(MemberNode memberNode, Object data); + + Object visitUser(MemberNode user, Object data); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAcceptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAcceptor.java index a6d63aafc0..6bd0e0cad7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAcceptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAcceptor.java @@ -1,13 +1,13 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -/** - * Interface for how a node should accept a NodeVisitor. The node may choose to - * send the visitor to it's contained nodes. - */ -public interface NodeVisitorAcceptor { - Object accept(NodeVisitor visitor, Object data); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +/** + * Interface for how a node should accept a NodeVisitor. The node may choose to + * send the visitor to it's contained nodes. + */ +public interface NodeVisitorAcceptor { + Object accept(NodeVisitor visitor, Object data); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAdapter.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAdapter.java index bbabb24f84..0bc0c66cbe 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAdapter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/NodeVisitorAdapter.java @@ -1,90 +1,90 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.util.List; - -/** - * Adapter class for easy implementation of a NodeVisitor. Subclasses need only - * override methods to add behavior, and call super to continue the - * visitation. - */ -public class NodeVisitorAdapter implements NodeVisitor { - - @Override - public Object visit(UsageGraph usageGraph, Object data) { - return usageGraph.accept(this, data); - } - - @Override - public Object visit(ClassNode classNode, Object data) { - return classNode.accept(this, data); - } - - @Override - public Object visitFields(ClassNode classNode, Object data) { - for (FieldNode fieldNode : classNode.getFieldNodes()) { - visit(fieldNode, data); - } - return data; - } - - @Override - public Object visit(FieldNode fieldNode, Object data) { - return fieldNode.accept(this, data); - } - - @Override - public Object visitConstructors(ClassNode classNode, Object data) { - for (ConstructorNode constructorNode : classNode.getConstructorNodes()) { - visit(constructorNode, data); - } - return data; - } - - @Override - public Object visit(ConstructorNode constructorNode, Object data) { - return constructorNode.accept(this, data); - } - - @Override - public Object visitMethods(ClassNode classNode, Object data) { - for (MethodNode methodNode : classNode.getMethodNodes()) { - visit(methodNode, data); - } - return data; - } - - @Override - public Object visit(MethodNode methodNode, Object data) { - return methodNode.accept(this, data); - } - - @Override - public Object visitUses(MemberNode memberNode, Object data) { - for (MemberNode use : (List) memberNode.getUses()) { - this.visitUse(use, data); - } - return data; - } - - @Override - public Object visitUse(MemberNode memberNode, Object data) { - return data; - } - - @Override - public Object visitUsers(MemberNode memberNode, Object data) { - for (MemberNode user : (List) memberNode.getUsers()) { - this.visitUser(user, data); - } - return data; - } - - @Override - public Object visitUser(MemberNode memberNode, Object data) { - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.util.List; + +/** + * Adapter class for easy implementation of a NodeVisitor. Subclasses need only + * override methods to add behavior, and call super to continue the + * visitation. + */ +public class NodeVisitorAdapter implements NodeVisitor { + + @Override + public Object visit(UsageGraph usageGraph, Object data) { + return usageGraph.accept(this, data); + } + + @Override + public Object visit(ClassNode classNode, Object data) { + return classNode.accept(this, data); + } + + @Override + public Object visitFields(ClassNode classNode, Object data) { + for (FieldNode fieldNode : classNode.getFieldNodes()) { + visit(fieldNode, data); + } + return data; + } + + @Override + public Object visit(FieldNode fieldNode, Object data) { + return fieldNode.accept(this, data); + } + + @Override + public Object visitConstructors(ClassNode classNode, Object data) { + for (ConstructorNode constructorNode : classNode.getConstructorNodes()) { + visit(constructorNode, data); + } + return data; + } + + @Override + public Object visit(ConstructorNode constructorNode, Object data) { + return constructorNode.accept(this, data); + } + + @Override + public Object visitMethods(ClassNode classNode, Object data) { + for (MethodNode methodNode : classNode.getMethodNodes()) { + visit(methodNode, data); + } + return data; + } + + @Override + public Object visit(MethodNode methodNode, Object data) { + return methodNode.accept(this, data); + } + + @Override + public Object visitUses(MemberNode memberNode, Object data) { + for (MemberNode use : (List) memberNode.getUses()) { + this.visitUse(use, data); + } + return data; + } + + @Override + public Object visitUse(MemberNode memberNode, Object data) { + return data; + } + + @Override + public Object visitUsers(MemberNode memberNode, Object data) { + for (MemberNode user : (List) memberNode.getUsers()) { + this.visitUser(user, data); + } + return data; + } + + @Override + public Object visitUser(MemberNode memberNode, Object data) { + return data; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraph.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraph.java index 544f62a226..d7b4738477 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraph.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraph.java @@ -1,134 +1,134 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import net.sourceforge.pmd.dcd.ClassLoaderUtil; -import net.sourceforge.pmd.util.filter.Filter; - -/** - * A UsageGraph tracks usage references between Java classes, based upon a - * parsing of the class files. Once the UsageGraph is built, it may be visited - * to perform additional post-processing, or usage relationship analysis. - *

- * The UsageGraph is composed of ClassNodes. Each ClassNode has various - * MemberNodes, specifically ConstructorNodes, FieldNodes, and MethodNodes. Each - * of these MemberNodes keeps track of other MemberNodes which it uses - * and other MemberNodes which are users of it. In this sense, the - * graph can navigated bi-directionally across the use relationship - * between MemberNodes. - *

- * Great effort is taken to keep the bookkeeping of the UsageGraph as tight as - * possible, so that rather large code bases can be analyzed. While nodes can - * grant access to the underlying Java Reflection APIs (e.g. Class, Constructor, - * Field, Member), the results are stored using WeakReferences to assist with - * memory usage. - *

- * A class Filter can be specified to limit the set of classes on which usage - * references will be tracked. This is often done to limit memory usage to - * interesting classes. For example, the java.util package is very - * often used, and tracking usages would require a massive bookkeeping effort - * which has little value. - * - * @see UsageGraphBuilder - * @see ClassNode - * @see MemberNode - * @see ConstructorNode - * @see FieldNode - * @see MethodNode - * @see NodeVisitor - * @see NodeVisitorAcceptor - */ -public class UsageGraph implements NodeVisitorAcceptor { - - private final List classNodes = new ArrayList<>(); - - protected final Filter classFilter; - - public UsageGraph(Filter classFilter) { - this.classFilter = classFilter; - } - - @Override - public Object accept(NodeVisitor visitor, Object data) { - for (ClassNode classNode : classNodes) { - visitor.visit(classNode, data); - } - return data; - } - - public boolean isClass(String className) { - checkClassName(className); - return Collections.binarySearch(classNodes, className, ClassNodeComparator.INSTANCE) >= 0; - } - - public ClassNode defineClass(String className) { - checkClassName(className); - int index = Collections.binarySearch(classNodes, className, ClassNodeComparator.INSTANCE); - ClassNode classNode; - if (index >= 0) { - classNode = classNodes.get(index); - } else { - classNode = new ClassNode(className); - classNodes.add(-(index + 1), classNode); - } - return classNode; - } - - public FieldNode defineField(String className, String name, String desc) { - ClassNode classNode = defineClass(className); - return classNode.defineField(name, desc); - } - - public MemberNode defineConstructor(String className, String name, String desc) { - ClassNode classNode = defineClass(className); - return classNode.defineConstructor(name, desc); - } - - public MemberNode defineMethod(String className, String name, String desc) { - ClassNode classNode = defineClass(className); - if (ClassLoaderUtil.CLINIT.equals(name) || ClassLoaderUtil.INIT.equals(name)) { - return classNode.defineConstructor(name, desc); - } else { - return classNode.defineMethod(name, desc); - } - } - - public void usageField(String className, String name, String desc, MemberNode usingMemberNode) { - checkClassName(className); - if (classFilter.filter(className)) { - FieldNode fieldNode = defineField(className, name, desc); - usage(fieldNode, usingMemberNode); - } - } - - public void usageMethod(String className, String name, String desc, MemberNode usingMemberNode) { - checkClassName(className); - if (classFilter.filter(className)) { - MemberNode memberNode; - if (ClassLoaderUtil.CLINIT.equals(name) || ClassLoaderUtil.INIT.equals(name)) { - memberNode = defineConstructor(className, name, desc); - } else { - memberNode = defineMethod(className, name, desc); - } - usage(memberNode, usingMemberNode); - } - } - - private void usage(MemberNode use, MemberNode user) { - use.addUser(user); - user.addUse(use); - } - - private void checkClassName(String className) { - // Make sure it's not in byte code internal format, or file system path. - if (className.indexOf('/') >= 0 || className.indexOf('\\') >= 0) { - throw new IllegalArgumentException("Invalid class name: " + className); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.dcd.ClassLoaderUtil; +import net.sourceforge.pmd.util.filter.Filter; + +/** + * A UsageGraph tracks usage references between Java classes, based upon a + * parsing of the class files. Once the UsageGraph is built, it may be visited + * to perform additional post-processing, or usage relationship analysis. + *

+ * The UsageGraph is composed of ClassNodes. Each ClassNode has various + * MemberNodes, specifically ConstructorNodes, FieldNodes, and MethodNodes. Each + * of these MemberNodes keeps track of other MemberNodes which it uses + * and other MemberNodes which are users of it. In this sense, the + * graph can navigated bi-directionally across the use relationship + * between MemberNodes. + *

+ * Great effort is taken to keep the bookkeeping of the UsageGraph as tight as + * possible, so that rather large code bases can be analyzed. While nodes can + * grant access to the underlying Java Reflection APIs (e.g. Class, Constructor, + * Field, Member), the results are stored using WeakReferences to assist with + * memory usage. + *

+ * A class Filter can be specified to limit the set of classes on which usage + * references will be tracked. This is often done to limit memory usage to + * interesting classes. For example, the java.util package is very + * often used, and tracking usages would require a massive bookkeeping effort + * which has little value. + * + * @see UsageGraphBuilder + * @see ClassNode + * @see MemberNode + * @see ConstructorNode + * @see FieldNode + * @see MethodNode + * @see NodeVisitor + * @see NodeVisitorAcceptor + */ +public class UsageGraph implements NodeVisitorAcceptor { + + private final List classNodes = new ArrayList<>(); + + protected final Filter classFilter; + + public UsageGraph(Filter classFilter) { + this.classFilter = classFilter; + } + + @Override + public Object accept(NodeVisitor visitor, Object data) { + for (ClassNode classNode : classNodes) { + visitor.visit(classNode, data); + } + return data; + } + + public boolean isClass(String className) { + checkClassName(className); + return Collections.binarySearch(classNodes, className, ClassNodeComparator.INSTANCE) >= 0; + } + + public ClassNode defineClass(String className) { + checkClassName(className); + int index = Collections.binarySearch(classNodes, className, ClassNodeComparator.INSTANCE); + ClassNode classNode; + if (index >= 0) { + classNode = classNodes.get(index); + } else { + classNode = new ClassNode(className); + classNodes.add(-(index + 1), classNode); + } + return classNode; + } + + public FieldNode defineField(String className, String name, String desc) { + ClassNode classNode = defineClass(className); + return classNode.defineField(name, desc); + } + + public MemberNode defineConstructor(String className, String name, String desc) { + ClassNode classNode = defineClass(className); + return classNode.defineConstructor(name, desc); + } + + public MemberNode defineMethod(String className, String name, String desc) { + ClassNode classNode = defineClass(className); + if (ClassLoaderUtil.CLINIT.equals(name) || ClassLoaderUtil.INIT.equals(name)) { + return classNode.defineConstructor(name, desc); + } else { + return classNode.defineMethod(name, desc); + } + } + + public void usageField(String className, String name, String desc, MemberNode usingMemberNode) { + checkClassName(className); + if (classFilter.filter(className)) { + FieldNode fieldNode = defineField(className, name, desc); + usage(fieldNode, usingMemberNode); + } + } + + public void usageMethod(String className, String name, String desc, MemberNode usingMemberNode) { + checkClassName(className); + if (classFilter.filter(className)) { + MemberNode memberNode; + if (ClassLoaderUtil.CLINIT.equals(name) || ClassLoaderUtil.INIT.equals(name)) { + memberNode = defineConstructor(className, name, desc); + } else { + memberNode = defineMethod(className, name, desc); + } + usage(memberNode, usingMemberNode); + } + } + + private void usage(MemberNode use, MemberNode user) { + use.addUser(user); + user.addUse(use); + } + + private void checkClassName(String className) { + // Make sure it's not in byte code internal format, or file system path. + if (className.indexOf('/') >= 0 || className.indexOf('\\') >= 0) { + throw new IllegalArgumentException("Invalid class name: " + className); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraphBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraphBuilder.java index 5fbcd31c61..954e7acee0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraphBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/graph/UsageGraphBuilder.java @@ -1,489 +1,489 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.dcd.graph; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.io.IOUtils; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Attribute; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.signature.SignatureReader; - -import net.sourceforge.pmd.dcd.asm.PrintVisitor; -import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor; -import net.sourceforge.pmd.util.filter.Filter; - -/** - * Utility class used to build a UsageGraph. - */ -public class UsageGraphBuilder { - - /** - * Should trace level logging be enabled. This is a development debugging - * option. - */ - private static final boolean TRACE = false; - private static final boolean INDEX = true; - - protected final UsageGraph usageGraph; - protected final Filter classFilter; - - public UsageGraphBuilder(Filter classFilter) { - this.classFilter = classFilter; - this.usageGraph = new UsageGraph(classFilter); - } - - public void index(String name) { - try { - String className = getClassName(name); - String classResourceName = getResourceName(name); - if (classFilter.filter(className)) { - if (!usageGraph.isClass(className)) { - usageGraph.defineClass(className); - InputStream inputStream = this.getClass().getClassLoader() - .getResourceAsStream(classResourceName + ".class"); - ClassReader classReader = new ClassReader(inputStream); - try { - classReader.accept(getNewClassVisitor(), 0); - } finally { - IOUtils.closeQuietly(inputStream); - } - } - } - } catch (IOException e) { - throw new RuntimeException("For " + name + ": " + e.getMessage(), e); - } - } - - public UsageGraph getUsageGraph() { - return usageGraph; - } - - private ClassVisitor getNewClassVisitor() { - return new MyClassVisitor(); - } - - // ASM visitor to on Class files to build a UsageGraph - class MyClassVisitor extends ClassVisitor { - private final PrintVisitor p; - private String className; - - MyClassVisitor() { - super(Opcodes.ASM5); - p = new PrintVisitor(); - } - - protected void println(String s) { - p.println(s); - } - - protected void printlnIndent(String s) { - p.printlnIndent(s); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, - String[] interfaces) { - if (TRACE) { - println("visit:"); - printlnIndent("version: " + version); - printlnIndent("access: " + access); - printlnIndent("name: " + name); - printlnIndent("signature: " + signature); - printlnIndent("superName: " + superName); - printlnIndent("interfaces: " + asList(interfaces)); - } - this.className = getClassName(name); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (TRACE) { - println("visitAnnotation:"); - printlnIndent("desc: " + desc); - printlnIndent("visible: " + visible); - } - return null; - } - - @Override - public void visitAttribute(Attribute attr) { - if (TRACE) { - println("visitAttribute:"); - printlnIndent("attr: " + attr); - } - } - - @Override - public void visitEnd() { - if (TRACE) { - println("visitEnd:"); - } - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - if (TRACE) { - println("visitField:"); - printlnIndent("access: " + access); - printlnIndent("name: " + name); - printlnIndent("desc: " + desc); - printlnIndent("signature: " + signature); - printlnIndent("value: " + value); - } - if (INDEX) { - SignatureReader signatureReader = new SignatureReader(desc); - TypeSignatureVisitor visitor = new TypeSignatureVisitor(p); - signatureReader.acceptType(visitor); - if (TRACE) { - printlnIndent("fieldType: " + visitor.getFieldType()); - } - - usageGraph.defineField(className, name, desc); - } - return null; - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - if (TRACE) { - println("visitInnerClass:"); - printlnIndent("name: " + name); - printlnIndent("outerName: " + outerName); - printlnIndent("innerName: " + innerName); - printlnIndent("access: " + access); - } - index(name); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MemberNode memberNode = null; - if (TRACE) { - println("visitMethod:"); - printlnIndent("access: " + access); - printlnIndent("name: " + name); - printlnIndent("desc: " + desc); - printlnIndent("signature: " + signature); - printlnIndent("exceptions: " + asList(exceptions)); - } - if (INDEX) { - memberNode = usageGraph.defineMethod(className, name, desc); - } - return getNewMethodVisitor(p, memberNode); - } - - @Override - public void visitOuterClass(String owner, String name, String desc) { - if (TRACE) { - println("visitOuterClass:"); - printlnIndent("owner: " + owner); - printlnIndent("name: " + name); - printlnIndent("desc: " + desc); - } - } - - @Override - public void visitSource(String source, String debug) { - if (TRACE) { - println("visitSource:"); - printlnIndent("source: " + source); - printlnIndent("debug: " + debug); - } - } - } - - protected MethodVisitor getNewMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) { - return new MyMethodVisitor(parent, usingMemberNode); - } - - protected class MyMethodVisitor extends MethodVisitor { - private final PrintVisitor p; - - protected void println(String s) { - p.println(s); - } - - protected void printlnIndent(String s) { - p.printlnIndent(s); - } - - private final MemberNode usingMemberNode; - - public MyMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) { - super(Opcodes.ASM5); - p = parent; - this.usingMemberNode = usingMemberNode; - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (TRACE) { - println("visitAnnotation:"); - printlnIndent("desc: " + desc); - printlnIndent("visible: " + visible); - } - return null; - } - - @Override - public AnnotationVisitor visitAnnotationDefault() { - if (TRACE) { - println("visitAnnotationDefault:"); - } - return null; - } - - @Override - public void visitAttribute(Attribute attr) { - if (TRACE) { - println("visitAttribute:"); - printlnIndent("attr: " + attr); - } - } - - @Override - public void visitCode() { - if (TRACE) { - println("visitCode:"); - } - } - - @Override - public void visitEnd() { - if (TRACE) { - println("visitEnd:"); - } - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (TRACE) { - println("visitFieldInsn:"); - printlnIndent("opcode: " + opcode); - printlnIndent("owner: " + owner); - printlnIndent("name: " + name); - printlnIndent("desc: " + desc); - } - if (INDEX) { - String className = getClassName(owner); - usageGraph.usageField(className, name, desc, usingMemberNode); - } - } - - @Override - public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) { - if (TRACE) { - println("visitFrame:"); - printlnIndent("type: " + type); - printlnIndent("local: " + local); - printlnIndent("local2: " + asList(local2)); - printlnIndent("stack: " + stack); - printlnIndent("stack2: " + asList(stack2)); - } - } - - @Override - public void visitIincInsn(int var, int increment) { - if (TRACE) { - println("visitIincInsn:"); - printlnIndent("var: " + var); - printlnIndent("increment: " + increment); - } - } - - @Override - public void visitInsn(int opcode) { - if (TRACE) { - println("visitInsn:"); - printlnIndent("opcode: " + opcode); - } - } - - @Override - public void visitIntInsn(int opcode, int operand) { - if (TRACE) { - println("visitIntInsn:"); - printlnIndent("opcode: " + opcode); - printlnIndent("operand: " + operand); - } - } - - @Override - public void visitJumpInsn(int opcode, Label label) { - if (TRACE) { - println("visitJumpInsn:"); - printlnIndent("opcode: " + opcode); - printlnIndent("label: " + label); - } - } - - @Override - public void visitLabel(Label label) { - if (TRACE) { - println("visitLabel:"); - printlnIndent("label: " + label); - } - } - - @Override - public void visitLdcInsn(Object cst) { - if (TRACE) { - println("visitLdcInsn:"); - printlnIndent("cst: " + cst); - } - } - - @Override - public void visitLineNumber(int line, Label start) { - if (TRACE) { - println("visitLineNumber:"); - printlnIndent("line: " + line); - printlnIndent("start: " + start); - } - } - - @Override - public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { - if (TRACE) { - println("visitLocalVariable:"); - printlnIndent("name: " + name); - printlnIndent("desc: " + desc); - printlnIndent("signature: " + signature); - printlnIndent("start: " + start); - printlnIndent("end: " + end); - printlnIndent("index: " + index); - } - } - - @Override - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - if (TRACE) { - println("visitLookupSwitchInsn:"); - printlnIndent("dflt: " + dflt); - printlnIndent("keys: " + asList(keys)); - printlnIndent("labels: " + asList(labels)); - } - } - - @Override - public void visitMaxs(int maxStack, int maxLocals) { - if (TRACE) { - println("visitMaxs:"); - printlnIndent("maxStack: " + maxStack); - printlnIndent("maxLocals: " + maxLocals); - } - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - if (TRACE) { - println("visitMethodInsn:"); - printlnIndent("opcode: " + opcode); - printlnIndent("owner: " + owner); - printlnIndent("name: " + name); - printlnIndent("desc: " + desc); - printlnIndent("itf: " + itf); - } - if (INDEX) { - String className = getClassName(owner); - usageGraph.usageMethod(className, name, desc, usingMemberNode); - } - } - - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - if (TRACE) { - println("visitMultiANewArrayInsn:"); - printlnIndent("desc: " + desc); - printlnIndent("dims: " + dims); - } - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { - if (TRACE) { - println("visitParameterAnnotation:"); - printlnIndent("parameter: " + parameter); - printlnIndent("desc: " + desc); - printlnIndent("visible: " + visible); - } - return null; - } - - @Override - public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { - if (TRACE) { - println("visitTableSwitchInsn:"); - printlnIndent("min: " + min); - printlnIndent("max: " + max); - printlnIndent("dflt: " + dflt); - printlnIndent("labels: " + asList(labels)); - } - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - if (TRACE) { - println("visitTryCatchBlock:"); - printlnIndent("start: " + start); - printlnIndent("end: " + end); - printlnIndent("handler: " + handler); - printlnIndent("type: " + type); - } - } - - @Override - public void visitTypeInsn(int opcode, String desc) { - if (TRACE) { - println("visitTypeInsn:"); - printlnIndent("opcode: " + opcode); - printlnIndent("desc: " + desc); - } - } - - @Override - public void visitVarInsn(int opcode, int var) { - if (TRACE) { - println("visitVarInsn:"); - printlnIndent("opcode: " + opcode); - printlnIndent("var: " + var); - } - } - } - - private static String getResourceName(String name) { - return name.replace('.', '/'); - } - - static String getClassName(String name) { - return name.replace('/', '.'); - } - - private static List asList(int[] array) { - List list = null; - if (array != null) { - list = new ArrayList<>(array.length); - for (int i : array) { - list.add(i); - } - } - return list; - } - - private static List asList(Object[] array) { - return array != null ? Arrays.asList(array) : null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.dcd.graph; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.signature.SignatureReader; + +import net.sourceforge.pmd.dcd.asm.PrintVisitor; +import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor; +import net.sourceforge.pmd.util.filter.Filter; + +/** + * Utility class used to build a UsageGraph. + */ +public class UsageGraphBuilder { + + /** + * Should trace level logging be enabled. This is a development debugging + * option. + */ + private static final boolean TRACE = false; + private static final boolean INDEX = true; + + protected final UsageGraph usageGraph; + protected final Filter classFilter; + + public UsageGraphBuilder(Filter classFilter) { + this.classFilter = classFilter; + this.usageGraph = new UsageGraph(classFilter); + } + + public void index(String name) { + try { + String className = getClassName(name); + String classResourceName = getResourceName(name); + if (classFilter.filter(className)) { + if (!usageGraph.isClass(className)) { + usageGraph.defineClass(className); + InputStream inputStream = this.getClass().getClassLoader() + .getResourceAsStream(classResourceName + ".class"); + ClassReader classReader = new ClassReader(inputStream); + try { + classReader.accept(getNewClassVisitor(), 0); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + } + } catch (IOException e) { + throw new RuntimeException("For " + name + ": " + e.getMessage(), e); + } + } + + public UsageGraph getUsageGraph() { + return usageGraph; + } + + private ClassVisitor getNewClassVisitor() { + return new MyClassVisitor(); + } + + // ASM visitor to on Class files to build a UsageGraph + class MyClassVisitor extends ClassVisitor { + private final PrintVisitor p; + private String className; + + MyClassVisitor() { + super(Opcodes.ASM5); + p = new PrintVisitor(); + } + + protected void println(String s) { + p.println(s); + } + + protected void printlnIndent(String s) { + p.printlnIndent(s); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, + String[] interfaces) { + if (TRACE) { + println("visit:"); + printlnIndent("version: " + version); + printlnIndent("access: " + access); + printlnIndent("name: " + name); + printlnIndent("signature: " + signature); + printlnIndent("superName: " + superName); + printlnIndent("interfaces: " + asList(interfaces)); + } + this.className = getClassName(name); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (TRACE) { + println("visitAnnotation:"); + printlnIndent("desc: " + desc); + printlnIndent("visible: " + visible); + } + return null; + } + + @Override + public void visitAttribute(Attribute attr) { + if (TRACE) { + println("visitAttribute:"); + printlnIndent("attr: " + attr); + } + } + + @Override + public void visitEnd() { + if (TRACE) { + println("visitEnd:"); + } + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { + if (TRACE) { + println("visitField:"); + printlnIndent("access: " + access); + printlnIndent("name: " + name); + printlnIndent("desc: " + desc); + printlnIndent("signature: " + signature); + printlnIndent("value: " + value); + } + if (INDEX) { + SignatureReader signatureReader = new SignatureReader(desc); + TypeSignatureVisitor visitor = new TypeSignatureVisitor(p); + signatureReader.acceptType(visitor); + if (TRACE) { + printlnIndent("fieldType: " + visitor.getFieldType()); + } + + usageGraph.defineField(className, name, desc); + } + return null; + } + + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + if (TRACE) { + println("visitInnerClass:"); + printlnIndent("name: " + name); + printlnIndent("outerName: " + outerName); + printlnIndent("innerName: " + innerName); + printlnIndent("access: " + access); + } + index(name); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MemberNode memberNode = null; + if (TRACE) { + println("visitMethod:"); + printlnIndent("access: " + access); + printlnIndent("name: " + name); + printlnIndent("desc: " + desc); + printlnIndent("signature: " + signature); + printlnIndent("exceptions: " + asList(exceptions)); + } + if (INDEX) { + memberNode = usageGraph.defineMethod(className, name, desc); + } + return getNewMethodVisitor(p, memberNode); + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + if (TRACE) { + println("visitOuterClass:"); + printlnIndent("owner: " + owner); + printlnIndent("name: " + name); + printlnIndent("desc: " + desc); + } + } + + @Override + public void visitSource(String source, String debug) { + if (TRACE) { + println("visitSource:"); + printlnIndent("source: " + source); + printlnIndent("debug: " + debug); + } + } + } + + protected MethodVisitor getNewMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) { + return new MyMethodVisitor(parent, usingMemberNode); + } + + protected class MyMethodVisitor extends MethodVisitor { + private final PrintVisitor p; + + protected void println(String s) { + p.println(s); + } + + protected void printlnIndent(String s) { + p.printlnIndent(s); + } + + private final MemberNode usingMemberNode; + + public MyMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) { + super(Opcodes.ASM5); + p = parent; + this.usingMemberNode = usingMemberNode; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (TRACE) { + println("visitAnnotation:"); + printlnIndent("desc: " + desc); + printlnIndent("visible: " + visible); + } + return null; + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + if (TRACE) { + println("visitAnnotationDefault:"); + } + return null; + } + + @Override + public void visitAttribute(Attribute attr) { + if (TRACE) { + println("visitAttribute:"); + printlnIndent("attr: " + attr); + } + } + + @Override + public void visitCode() { + if (TRACE) { + println("visitCode:"); + } + } + + @Override + public void visitEnd() { + if (TRACE) { + println("visitEnd:"); + } + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (TRACE) { + println("visitFieldInsn:"); + printlnIndent("opcode: " + opcode); + printlnIndent("owner: " + owner); + printlnIndent("name: " + name); + printlnIndent("desc: " + desc); + } + if (INDEX) { + String className = getClassName(owner); + usageGraph.usageField(className, name, desc, usingMemberNode); + } + } + + @Override + public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) { + if (TRACE) { + println("visitFrame:"); + printlnIndent("type: " + type); + printlnIndent("local: " + local); + printlnIndent("local2: " + asList(local2)); + printlnIndent("stack: " + stack); + printlnIndent("stack2: " + asList(stack2)); + } + } + + @Override + public void visitIincInsn(int var, int increment) { + if (TRACE) { + println("visitIincInsn:"); + printlnIndent("var: " + var); + printlnIndent("increment: " + increment); + } + } + + @Override + public void visitInsn(int opcode) { + if (TRACE) { + println("visitInsn:"); + printlnIndent("opcode: " + opcode); + } + } + + @Override + public void visitIntInsn(int opcode, int operand) { + if (TRACE) { + println("visitIntInsn:"); + printlnIndent("opcode: " + opcode); + printlnIndent("operand: " + operand); + } + } + + @Override + public void visitJumpInsn(int opcode, Label label) { + if (TRACE) { + println("visitJumpInsn:"); + printlnIndent("opcode: " + opcode); + printlnIndent("label: " + label); + } + } + + @Override + public void visitLabel(Label label) { + if (TRACE) { + println("visitLabel:"); + printlnIndent("label: " + label); + } + } + + @Override + public void visitLdcInsn(Object cst) { + if (TRACE) { + println("visitLdcInsn:"); + printlnIndent("cst: " + cst); + } + } + + @Override + public void visitLineNumber(int line, Label start) { + if (TRACE) { + println("visitLineNumber:"); + printlnIndent("line: " + line); + printlnIndent("start: " + start); + } + } + + @Override + public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { + if (TRACE) { + println("visitLocalVariable:"); + printlnIndent("name: " + name); + printlnIndent("desc: " + desc); + printlnIndent("signature: " + signature); + printlnIndent("start: " + start); + printlnIndent("end: " + end); + printlnIndent("index: " + index); + } + } + + @Override + public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { + if (TRACE) { + println("visitLookupSwitchInsn:"); + printlnIndent("dflt: " + dflt); + printlnIndent("keys: " + asList(keys)); + printlnIndent("labels: " + asList(labels)); + } + } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + if (TRACE) { + println("visitMaxs:"); + printlnIndent("maxStack: " + maxStack); + printlnIndent("maxLocals: " + maxLocals); + } + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (TRACE) { + println("visitMethodInsn:"); + printlnIndent("opcode: " + opcode); + printlnIndent("owner: " + owner); + printlnIndent("name: " + name); + printlnIndent("desc: " + desc); + printlnIndent("itf: " + itf); + } + if (INDEX) { + String className = getClassName(owner); + usageGraph.usageMethod(className, name, desc, usingMemberNode); + } + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + if (TRACE) { + println("visitMultiANewArrayInsn:"); + printlnIndent("desc: " + desc); + printlnIndent("dims: " + dims); + } + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { + if (TRACE) { + println("visitParameterAnnotation:"); + printlnIndent("parameter: " + parameter); + printlnIndent("desc: " + desc); + printlnIndent("visible: " + visible); + } + return null; + } + + @Override + public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { + if (TRACE) { + println("visitTableSwitchInsn:"); + printlnIndent("min: " + min); + printlnIndent("max: " + max); + printlnIndent("dflt: " + dflt); + printlnIndent("labels: " + asList(labels)); + } + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + if (TRACE) { + println("visitTryCatchBlock:"); + printlnIndent("start: " + start); + printlnIndent("end: " + end); + printlnIndent("handler: " + handler); + printlnIndent("type: " + type); + } + } + + @Override + public void visitTypeInsn(int opcode, String desc) { + if (TRACE) { + println("visitTypeInsn:"); + printlnIndent("opcode: " + opcode); + printlnIndent("desc: " + desc); + } + } + + @Override + public void visitVarInsn(int opcode, int var) { + if (TRACE) { + println("visitVarInsn:"); + printlnIndent("opcode: " + opcode); + printlnIndent("var: " + var); + } + } + } + + private static String getResourceName(String name) { + return name.replace('.', '/'); + } + + static String getClassName(String name) { + return name.replace('/', '.'); + } + + private static List asList(int[] array) { + List list = null; + if (array != null) { + list = new ArrayList<>(array.length); + for (int i : array) { + list.add(i); + } + } + return list; + } + + private static List asList(Object[] array) { + return array != null ? Arrays.asList(array) : null; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java index cd702f081c..06164b6690 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java @@ -1,62 +1,62 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import java.io.Writer; - -import net.sourceforge.pmd.lang.dfa.DFAGraphRule; - -/** - * This is a generic implementation of the LanguageVersionHandler interface. - * - * @see LanguageVersionHandler - */ -public abstract class AbstractLanguageVersionHandler implements LanguageVersionHandler { - - @Override - public DataFlowHandler getDataFlowHandler() { - return DataFlowHandler.DUMMY; - } - - @Override - public XPathHandler getXPathHandler() { - return XPathHandler.DUMMY; - } - - @Override - public ParserOptions getDefaultParserOptions() { - return new ParserOptions(); - } - - @Override - public VisitorStarter getDataFlowFacade() { - return VisitorStarter.DUMMY; - } - - @Override - public VisitorStarter getSymbolFacade() { - return VisitorStarter.DUMMY; - } - - @Override - public VisitorStarter getSymbolFacade(ClassLoader classLoader) { - return VisitorStarter.DUMMY; - } - - @Override - public VisitorStarter getTypeResolutionFacade(ClassLoader classLoader) { - return VisitorStarter.DUMMY; - } - - @Override - public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) { - return VisitorStarter.DUMMY; - } - - @Override - public DFAGraphRule getDFAGraphRule() { - return null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import java.io.Writer; + +import net.sourceforge.pmd.lang.dfa.DFAGraphRule; + +/** + * This is a generic implementation of the LanguageVersionHandler interface. + * + * @see LanguageVersionHandler + */ +public abstract class AbstractLanguageVersionHandler implements LanguageVersionHandler { + + @Override + public DataFlowHandler getDataFlowHandler() { + return DataFlowHandler.DUMMY; + } + + @Override + public XPathHandler getXPathHandler() { + return XPathHandler.DUMMY; + } + + @Override + public ParserOptions getDefaultParserOptions() { + return new ParserOptions(); + } + + @Override + public VisitorStarter getDataFlowFacade() { + return VisitorStarter.DUMMY; + } + + @Override + public VisitorStarter getSymbolFacade() { + return VisitorStarter.DUMMY; + } + + @Override + public VisitorStarter getSymbolFacade(ClassLoader classLoader) { + return VisitorStarter.DUMMY; + } + + @Override + public VisitorStarter getTypeResolutionFacade(ClassLoader classLoader) { + return VisitorStarter.DUMMY; + } + + @Override + public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) { + return VisitorStarter.DUMMY; + } + + @Override + public DFAGraphRule getDFAGraphRule() { + return null; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java index 93fa30f49e..870fb72440 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java @@ -1,34 +1,34 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import java.io.Reader; - -/** - * This is a generic implementation of the Parser interface. - * - * @see Parser - */ -public abstract class AbstractParser implements Parser { - protected final ParserOptions parserOptions; - - public AbstractParser(ParserOptions parserOptions) { - this.parserOptions = parserOptions; - } - - @Override - public ParserOptions getParserOptions() { - return parserOptions; - } - - @Override - public TokenManager getTokenManager(String fileName, Reader source) { - TokenManager tokenManager = createTokenManager(source); - tokenManager.setFileName(fileName); - return tokenManager; - } - - protected abstract TokenManager createTokenManager(Reader source); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import java.io.Reader; + +/** + * This is a generic implementation of the Parser interface. + * + * @see Parser + */ +public abstract class AbstractParser implements Parser { + protected final ParserOptions parserOptions; + + public AbstractParser(ParserOptions parserOptions) { + this.parserOptions = parserOptions; + } + + @Override + public ParserOptions getParserOptions() { + return parserOptions; + } + + @Override + public TokenManager getTokenManager(String fileName, Reader source) { + TokenManager tokenManager = createTokenManager(source); + tokenManager.setFileName(fileName); + return tokenManager; + } + + protected abstract TokenManager createTokenManager(Reader source); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/DataFlowHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/DataFlowHandler.java index 4ee375057a..212916e6b0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/DataFlowHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/DataFlowHandler.java @@ -1,29 +1,29 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.dfa.DataFlowNode; - -public interface DataFlowHandler { - - DataFlowHandler DUMMY = new DataFlowHandler() { - @Override - public DataFlowNode createDataFlowNode(List dataFlow, Node node) { - return null; - } - - @Override - public Class getLabelStatementNodeClass() { - return null; - } - }; - - DataFlowNode createDataFlowNode(List dataFlow, Node node); - - Class getLabelStatementNodeClass(); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.dfa.DataFlowNode; + +public interface DataFlowHandler { + + DataFlowHandler DUMMY = new DataFlowHandler() { + @Override + public DataFlowNode createDataFlowNode(List dataFlow, Node node) { + return null; + } + + @Override + public Class getLabelStatementNodeClass() { + return null; + } + }; + + DataFlowNode createDataFlowNode(List dataFlow, Node node); + + Class getLabelStatementNodeClass(); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java index d0c1ec9b56..61e997c29c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java @@ -1,116 +1,116 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This class can discover the LanguageVersion of a source file. Further, every - * Language has a default LanguageVersion, which can be temporarily overridden - * here. - */ -public class LanguageVersionDiscoverer { - private Map languageToLanguageVersion = new HashMap<>(); - - /** - * Set the given LanguageVersion as the current default for it's Language. - * - * @param languageVersion - * The new default for the Language. - * @return The previous default version for the language. - */ - public LanguageVersion setDefaultLanguageVersion(LanguageVersion languageVersion) { - LanguageVersion currentLanguageVersion = languageToLanguageVersion.put(languageVersion.getLanguage(), - languageVersion); - if (currentLanguageVersion == null) { - currentLanguageVersion = languageVersion.getLanguage().getDefaultVersion(); - } - return currentLanguageVersion; - } - - /** - * Get the current default LanguageVersion for the given Language. - * - * @param language - * The Language. - * @return The current default version for the language. - */ - public LanguageVersion getDefaultLanguageVersion(Language language) { - LanguageVersion languageVersion = languageToLanguageVersion.get(language); - if (languageVersion == null) { - languageVersion = language.getDefaultVersion(); - } - return languageVersion; - } - - /** - * Get the default LanguageVersion for the first Language of a given source - * file. - * - * @param sourceFile - * The file. - * @return The currently configured LanguageVersion for the source file, or - * null if there are no supported Languages for the - * file. - */ - public LanguageVersion getDefaultLanguageVersionForFile(File sourceFile) { - return getDefaultLanguageVersionForFile(sourceFile.getName()); - } - - /** - * Get the LanguageVersion for the first Language of a source file with the - * given name. - * - * @param fileName - * The file name. - * @return The currently configured LanguageVersion for the source file or - * null if there are no supported Languages for the - * file. - */ - public LanguageVersion getDefaultLanguageVersionForFile(String fileName) { - List languages = getLanguagesForFile(fileName); - LanguageVersion languageVersion = null; - if (!languages.isEmpty()) { - languageVersion = getDefaultLanguageVersion(languages.get(0)); - } - return languageVersion; - } - - /** - * Get the Languages of a given source file. - * - * @param sourceFile - * The file. - * @return The Languages for the source file, may be empty. - */ - public List getLanguagesForFile(File sourceFile) { - return getLanguagesForFile(sourceFile.getName()); - } - - /** - * Get the Languages of a given source file. - * - * @param fileName - * The file name. - * @return The Languages for the source file, may be empty. - */ - public List getLanguagesForFile(String fileName) { - String extension = getExtension(fileName); - return LanguageRegistry.findByExtension(extension); - } - - // Get the extensions from a file - private String getExtension(String fileName) { - String extension = null; - int extensionIndex = 1 + fileName.lastIndexOf('.'); - if (extensionIndex > 0) { - extension = fileName.substring(extensionIndex); - } - return extension; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class can discover the LanguageVersion of a source file. Further, every + * Language has a default LanguageVersion, which can be temporarily overridden + * here. + */ +public class LanguageVersionDiscoverer { + private Map languageToLanguageVersion = new HashMap<>(); + + /** + * Set the given LanguageVersion as the current default for it's Language. + * + * @param languageVersion + * The new default for the Language. + * @return The previous default version for the language. + */ + public LanguageVersion setDefaultLanguageVersion(LanguageVersion languageVersion) { + LanguageVersion currentLanguageVersion = languageToLanguageVersion.put(languageVersion.getLanguage(), + languageVersion); + if (currentLanguageVersion == null) { + currentLanguageVersion = languageVersion.getLanguage().getDefaultVersion(); + } + return currentLanguageVersion; + } + + /** + * Get the current default LanguageVersion for the given Language. + * + * @param language + * The Language. + * @return The current default version for the language. + */ + public LanguageVersion getDefaultLanguageVersion(Language language) { + LanguageVersion languageVersion = languageToLanguageVersion.get(language); + if (languageVersion == null) { + languageVersion = language.getDefaultVersion(); + } + return languageVersion; + } + + /** + * Get the default LanguageVersion for the first Language of a given source + * file. + * + * @param sourceFile + * The file. + * @return The currently configured LanguageVersion for the source file, or + * null if there are no supported Languages for the + * file. + */ + public LanguageVersion getDefaultLanguageVersionForFile(File sourceFile) { + return getDefaultLanguageVersionForFile(sourceFile.getName()); + } + + /** + * Get the LanguageVersion for the first Language of a source file with the + * given name. + * + * @param fileName + * The file name. + * @return The currently configured LanguageVersion for the source file or + * null if there are no supported Languages for the + * file. + */ + public LanguageVersion getDefaultLanguageVersionForFile(String fileName) { + List languages = getLanguagesForFile(fileName); + LanguageVersion languageVersion = null; + if (!languages.isEmpty()) { + languageVersion = getDefaultLanguageVersion(languages.get(0)); + } + return languageVersion; + } + + /** + * Get the Languages of a given source file. + * + * @param sourceFile + * The file. + * @return The Languages for the source file, may be empty. + */ + public List getLanguagesForFile(File sourceFile) { + return getLanguagesForFile(sourceFile.getName()); + } + + /** + * Get the Languages of a given source file. + * + * @param fileName + * The file name. + * @return The Languages for the source file, may be empty. + */ + public List getLanguagesForFile(String fileName) { + String extension = getExtension(fileName); + return LanguageRegistry.findByExtension(extension); + } + + // Get the extensions from a file + private String getExtension(String fileName) { + String extension = null; + int extensionIndex = 1 + fileName.lastIndexOf('.'); + if (extensionIndex > 0) { + extension = fileName.substring(extensionIndex); + } + return extension; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java index 4642ea7898..356857e031 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java @@ -1,91 +1,91 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import java.io.Writer; - -import net.sourceforge.pmd.lang.dfa.DFAGraphRule; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; - -/** - * Interface for obtaining the classes necessary for checking source files of a - * specific language. - * - * @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be - */ -public interface LanguageVersionHandler { - - /** - * Get the DataFlowHandler. - */ - DataFlowHandler getDataFlowHandler(); - - /** - * Get the XPathHandler. - */ - XPathHandler getXPathHandler(); - - /** - * Get the RuleViolationFactory. - */ - RuleViolationFactory getRuleViolationFactory(); - - /** - * Get the default ParserOptions. - * - * @return ParserOptions - */ - ParserOptions getDefaultParserOptions(); - - /** - * Get the Parser. - * - * @return Parser - */ - Parser getParser(ParserOptions parserOptions); - - /** - * Get the DataFlowFacade. - * - * @return VisitorStarter - */ - VisitorStarter getDataFlowFacade(); - - /** - * Get the SymbolFacade. - * - * @return VisitorStarter - */ - VisitorStarter getSymbolFacade(); - - /** - * Get the SymbolFacade. - * - * @param classLoader - * A ClassLoader to use for resolving Types. - * @return VisitorStarter - */ - VisitorStarter getSymbolFacade(ClassLoader classLoader); - - /** - * Get the TypeResolutionFacade. - * - * @param classLoader - * A ClassLoader to use for resolving Types. - * @return VisitorStarter - */ - VisitorStarter getTypeResolutionFacade(ClassLoader classLoader); - - /** - * Get the DumpFacade. - * - * @param writer - * The writer to dump to. - * @return VisitorStarter - */ - VisitorStarter getDumpFacade(Writer writer, String prefix, boolean recurse); - - DFAGraphRule getDFAGraphRule(); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import java.io.Writer; + +import net.sourceforge.pmd.lang.dfa.DFAGraphRule; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +/** + * Interface for obtaining the classes necessary for checking source files of a + * specific language. + * + * @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be + */ +public interface LanguageVersionHandler { + + /** + * Get the DataFlowHandler. + */ + DataFlowHandler getDataFlowHandler(); + + /** + * Get the XPathHandler. + */ + XPathHandler getXPathHandler(); + + /** + * Get the RuleViolationFactory. + */ + RuleViolationFactory getRuleViolationFactory(); + + /** + * Get the default ParserOptions. + * + * @return ParserOptions + */ + ParserOptions getDefaultParserOptions(); + + /** + * Get the Parser. + * + * @return Parser + */ + Parser getParser(ParserOptions parserOptions); + + /** + * Get the DataFlowFacade. + * + * @return VisitorStarter + */ + VisitorStarter getDataFlowFacade(); + + /** + * Get the SymbolFacade. + * + * @return VisitorStarter + */ + VisitorStarter getSymbolFacade(); + + /** + * Get the SymbolFacade. + * + * @param classLoader + * A ClassLoader to use for resolving Types. + * @return VisitorStarter + */ + VisitorStarter getSymbolFacade(ClassLoader classLoader); + + /** + * Get the TypeResolutionFacade. + * + * @param classLoader + * A ClassLoader to use for resolving Types. + * @return VisitorStarter + */ + VisitorStarter getTypeResolutionFacade(ClassLoader classLoader); + + /** + * Get the DumpFacade. + * + * @param writer + * The writer to dump to. + * @return VisitorStarter + */ + VisitorStarter getDumpFacade(Writer writer, String prefix, boolean recurse); + + DFAGraphRule getDFAGraphRule(); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ParserOptions.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ParserOptions.java index 038bd08c06..e379d05e5f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ParserOptions.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ParserOptions.java @@ -1,40 +1,40 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -/** - * Represents a set of configuration options for a {@link Parser}. For each - * unique combination of ParserOptions a Parser will be used to create an AST. - * Therefore, implementations must implement {@link Object#equals(Object)} and - * {@link Object#hashCode()}. - */ -public class ParserOptions { - protected String suppressMarker; - - public String getSuppressMarker() { - return suppressMarker; - } - - public void setSuppressMarker(String suppressMarker) { - this.suppressMarker = suppressMarker; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final ParserOptions that = (ParserOptions) obj; - return this.suppressMarker.equals(that.suppressMarker); - } - - @Override - public int hashCode() { - return suppressMarker != null ? suppressMarker.hashCode() : 0; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +/** + * Represents a set of configuration options for a {@link Parser}. For each + * unique combination of ParserOptions a Parser will be used to create an AST. + * Therefore, implementations must implement {@link Object#equals(Object)} and + * {@link Object#hashCode()}. + */ +public class ParserOptions { + protected String suppressMarker; + + public String getSuppressMarker() { + return suppressMarker; + } + + public void setSuppressMarker(String suppressMarker) { + this.suppressMarker = suppressMarker; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ParserOptions that = (ParserOptions) obj; + return this.suppressMarker.equals(that.suppressMarker); + } + + @Override + public int hashCode() { + return suppressMarker != null ? suppressMarker.hashCode() : 0; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/TokenManager.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/TokenManager.java index 205c6a1e9e..6673d13a68 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/TokenManager.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/TokenManager.java @@ -1,14 +1,14 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -/** - * Common interface for interacting with parser Token Managers. - */ -public interface TokenManager { - Object getNextToken(); - - void setFileName(String fileName); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +/** + * Common interface for interacting with parser Token Managers. + */ +public interface TokenManager { + Object getNextToken(); + + void setFileName(String fileName); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java index 323182f616..c6407e1a20 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java @@ -1,51 +1,51 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import org.jaxen.Navigator; - -import net.sourceforge.pmd.lang.xpath.Initializer; - -import net.sf.saxon.sxpath.IndependentContext; - -/** - * Interface for performing Language specific XPath handling, such as - * initialization and navigation. - */ -public interface XPathHandler { - - XPathHandler DUMMY = new XPathHandler() { - @Override - public void initialize() { - } - - @Override - public void initialize(IndependentContext context) { - } - - @Override - public Navigator getNavigator() { - return null; - } - }; - - /** - * Initialize. This is intended to be called by {@link Initializer} to - * perform Language specific initialization. - */ - void initialize(); - - /** - * Initialize. This is intended to be called by {@link Initializer} to - * perform Language specific initialization for Saxon. - */ - void initialize(IndependentContext context); - - /** - * Get a Jaxen Navigator for this Language. May return null if - * there is no Jaxen Navigation for this language. - */ - Navigator getNavigator(); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import org.jaxen.Navigator; + +import net.sourceforge.pmd.lang.xpath.Initializer; + +import net.sf.saxon.sxpath.IndependentContext; + +/** + * Interface for performing Language specific XPath handling, such as + * initialization and navigation. + */ +public interface XPathHandler { + + XPathHandler DUMMY = new XPathHandler() { + @Override + public void initialize() { + } + + @Override + public void initialize(IndependentContext context) { + } + + @Override + public Navigator getNavigator() { + return null; + } + }; + + /** + * Initialize. This is intended to be called by {@link Initializer} to + * perform Language specific initialization. + */ + void initialize(); + + /** + * Initialize. This is intended to be called by {@link Initializer} to + * perform Language specific initialization for Saxon. + */ + void initialize(IndependentContext context); + + /** + * Get a Jaxen Navigator for this Language. May return null if + * there is no Jaxen Navigation for this language. + */ + Navigator getNavigator(); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index 0ca4d7e66f..61805a03f5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -1,463 +1,463 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.jaxen.BaseXPath; -import org.jaxen.JaxenException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator; -import net.sourceforge.pmd.lang.dfa.DataFlowNode; - -public abstract class AbstractNode implements Node { - - protected Node parent; - protected Node[] children; - protected int childIndex; - protected int id; - - private String image; - protected int beginLine = -1; - protected int endLine; - protected int beginColumn = -1; - protected int endColumn; - private DataFlowNode dataFlowNode; - private Object userData; - protected GenericToken firstToken; - protected GenericToken lastToken; - - public AbstractNode(int id) { - this.id = id; - } - - public AbstractNode(int id, int theBeginLine, int theEndLine, int theBeginColumn, int theEndColumn) { - this(id); - - beginLine = theBeginLine; - endLine = theEndLine; - beginColumn = theBeginColumn; - endColumn = theEndColumn; - } - - public boolean isSingleLine() { - return beginLine == endLine; - } - - @Override - public void jjtOpen() { - // to be overridden by subclasses - } - - @Override - public void jjtClose() { - // to be overridden by subclasses - } - - @Override - public void jjtSetParent(Node parent) { - this.parent = parent; - } - - @Override - public Node jjtGetParent() { - return parent; - } - - @Override - public void jjtAddChild(Node child, int index) { - if (children == null) { - children = new Node[index + 1]; - } else if (index >= children.length) { - Node[] newChildren = new Node[index + 1]; - System.arraycopy(children, 0, newChildren, 0, children.length); - children = newChildren; - } - children[index] = child; - child.jjtSetChildIndex(index); - } - - @Override - public void jjtSetChildIndex(int index) { - childIndex = index; - } - - @Override - public int jjtGetChildIndex() { - return childIndex; - } - - @Override - public Node jjtGetChild(int index) { - return children[index]; - } - - @Override - public int jjtGetNumChildren() { - return children == null ? 0 : children.length; - } - - @Override - public int jjtGetId() { - return id; - } - - /** - * Subclasses should implement this method to return a name usable with - * XPathRule for evaluating Element Names. - */ - @Override - public abstract String toString(); - - @Override - public String getImage() { - return image; - } - - @Override - public void setImage(String image) { - this.image = image; - } - - @Override - public boolean hasImageEqualTo(String image) { - return this.getImage() != null && this.getImage().equals(image); - } - - @Override - public int getBeginLine() { - return beginLine; - } - - public void testingOnlySetBeginLine(int i) { - this.beginLine = i; - } - - @Override - public int getBeginColumn() { - if (beginColumn != -1) { - return beginColumn; - } else { - if (children != null && children.length > 0) { - return children[0].getBeginColumn(); - } else { - throw new RuntimeException("Unable to determine beginning line of Node."); - } - } - } - - public void testingOnlySetBeginColumn(int i) { - this.beginColumn = i; - } - - @Override - public int getEndLine() { - return endLine; - } - - public void testingOnlySetEndLine(int i) { - this.endLine = i; - } - - @Override - public int getEndColumn() { - return endColumn; - } - - public void testingOnlySetEndColumn(int i) { - this.endColumn = i; - } - - @Override - public DataFlowNode getDataFlowNode() { - if (this.dataFlowNode == null) { - if (this.parent != null) { - return parent.getDataFlowNode(); - } - return null; // TODO wise? - } - return dataFlowNode; - } - - @Override - public void setDataFlowNode(DataFlowNode dataFlowNode) { - this.dataFlowNode = dataFlowNode; - } - - /** - * Returns the n-th parent or null if there are not n ancestors - * - * @param n - * how many ancestors to iterate over. - * @return the n-th parent or null. - * @throws IllegalArgumentException - * if n is not positive. - */ - @Override - public Node getNthParent(int n) { - if (n <= 0) { - throw new IllegalArgumentException(); - } - Node result = this.jjtGetParent(); - for (int i = 1; i < n; i++) { - if (result == null) { - return null; - } - result = result.jjtGetParent(); - } - return result; - } - - /** - * Traverses up the tree to find the first parent instance of type - * parentType - * - * @param parentType - * class which you want to find. - * @return Node of type parentType. Returns null if none found. - */ - @Override - public T getFirstParentOfType(Class parentType) { - Node parentNode = jjtGetParent(); - while (parentNode != null && parentNode.getClass() != parentType) { - parentNode = parentNode.jjtGetParent(); - } - return (T) parentNode; - } - - /** - * Traverses up the tree to find all of the parent instances of type - * parentType - * - * @param parentType - * classes which you want to find. - * @return List of parentType instances found. - */ - @Override - public List getParentsOfType(Class parentType) { - List parents = new ArrayList<>(); - Node parentNode = jjtGetParent(); - while (parentNode != null) { - if (parentNode.getClass() == parentType) { - parents.add((T) parentNode); - } - parentNode = parentNode.jjtGetParent(); - } - return parents; - } - - /** - * {@inheritDoc} - */ - @Override - public List findDescendantsOfType(Class targetType) { - List list = new ArrayList<>(); - findDescendantsOfType(this, targetType, list, true); - return list; - } - - /** - * {@inheritDoc} - */ - @Override - public void findDescendantsOfType(Class targetType, List results, boolean crossBoundaries) { - findDescendantsOfType(this, targetType, results, crossBoundaries); - } - - private static void findDescendantsOfType(Node node, Class targetType, List results, - boolean crossFindBoundaries) { - - if (!crossFindBoundaries && node.isFindBoundary()) { - return; - } - - int n = node.jjtGetNumChildren(); - for (int i = 0; i < n; i++) { - Node child = node.jjtGetChild(i); - if (child.getClass() == targetType) { - results.add((T) child); - } - - findDescendantsOfType(child, targetType, results, crossFindBoundaries); - } - } - - /** - * {@inheritDoc} - */ - @Override - public List findChildrenOfType(Class targetType) { - List list = new ArrayList<>(); - int n = jjtGetNumChildren(); - for (int i = 0; i < n; i++) { - Node child = jjtGetChild(i); - if (child.getClass() == targetType) { - list.add((T) child); - } - } - return list; - } - - @Override - public boolean isFindBoundary() { - return false; - } - - @Override - public Document getAsDocument() { - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document document = db.newDocument(); - appendElement(document); - return document; - } catch (ParserConfigurationException pce) { - throw new RuntimeException(pce); - } - } - - protected void appendElement(org.w3c.dom.Node parentNode) { - DocumentNavigator docNav = new DocumentNavigator(); - Document ownerDocument = parentNode.getOwnerDocument(); - if (ownerDocument == null) { - // If the parentNode is a Document itself, it's ownerDocument is - // null - ownerDocument = (Document) parentNode; - } - String elementName = docNav.getElementName(this); - Element element = ownerDocument.createElement(elementName); - parentNode.appendChild(element); - for (Iterator iter = docNav.getAttributeAxisIterator(this); iter.hasNext();) { - Attribute attr = iter.next(); - element.setAttribute(attr.getName(), attr.getStringValue()); - } - for (Iterator iter = docNav.getChildAxisIterator(this); iter.hasNext();) { - AbstractNode child = (AbstractNode) iter.next(); - child.appendElement(element); - } - } - - /** - * {@inheritDoc} - */ - @Override - public T getFirstDescendantOfType(Class descendantType) { - return getFirstDescendantOfType(descendantType, this); - } - - /** - * {@inheritDoc} - */ - @Override - public T getFirstChildOfType(Class childType) { - int n = jjtGetNumChildren(); - for (int i = 0; i < n; i++) { - Node child = jjtGetChild(i); - if (child.getClass() == childType) { - return (T) child; - } - } - return null; - } - - private static T getFirstDescendantOfType(Class descendantType, Node node) { - int n = node.jjtGetNumChildren(); - for (int i = 0; i < n; i++) { - Node n1 = node.jjtGetChild(i); - if (n1.getClass() == descendantType) { - return (T) n1; - } - T n2 = getFirstDescendantOfType(descendantType, n1); - if (n2 != null) { - return n2; - } - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean hasDescendantOfType(Class type) { - return getFirstDescendantOfType(type) != null; - } - - /** - * - * @param types - * @return boolean - */ - public final boolean hasDecendantOfAnyType(Class... types) { - for (Class type : types) { - if (hasDescendantOfType(type)) { - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - @SuppressWarnings("unchecked") - public List findChildNodesWithXPath(String xpathString) throws JaxenException { - return new BaseXPath(xpathString, new DocumentNavigator()).selectNodes(this); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasDescendantMatchingXPath(String xpathString) { - try { - return !findChildNodesWithXPath(xpathString).isEmpty(); - } catch (JaxenException e) { - throw new RuntimeException("XPath expression " + xpathString + " failed: " + e.getLocalizedMessage(), e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Object getUserData() { - return userData; - } - - /** - * {@inheritDoc} - */ - @Override - public void setUserData(Object userData) { - this.userData = userData; - } - - public GenericToken jjtGetFirstToken() { - return firstToken; - } - - public void jjtSetFirstToken(GenericToken token) { - this.firstToken = token; - } - - public GenericToken jjtGetLastToken() { - return lastToken; - } - - public void jjtSetLastToken(GenericToken token) { - this.lastToken = token; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.jaxen.BaseXPath; +import org.jaxen.JaxenException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator; +import net.sourceforge.pmd.lang.dfa.DataFlowNode; + +public abstract class AbstractNode implements Node { + + protected Node parent; + protected Node[] children; + protected int childIndex; + protected int id; + + private String image; + protected int beginLine = -1; + protected int endLine; + protected int beginColumn = -1; + protected int endColumn; + private DataFlowNode dataFlowNode; + private Object userData; + protected GenericToken firstToken; + protected GenericToken lastToken; + + public AbstractNode(int id) { + this.id = id; + } + + public AbstractNode(int id, int theBeginLine, int theEndLine, int theBeginColumn, int theEndColumn) { + this(id); + + beginLine = theBeginLine; + endLine = theEndLine; + beginColumn = theBeginColumn; + endColumn = theEndColumn; + } + + public boolean isSingleLine() { + return beginLine == endLine; + } + + @Override + public void jjtOpen() { + // to be overridden by subclasses + } + + @Override + public void jjtClose() { + // to be overridden by subclasses + } + + @Override + public void jjtSetParent(Node parent) { + this.parent = parent; + } + + @Override + public Node jjtGetParent() { + return parent; + } + + @Override + public void jjtAddChild(Node child, int index) { + if (children == null) { + children = new Node[index + 1]; + } else if (index >= children.length) { + Node[] newChildren = new Node[index + 1]; + System.arraycopy(children, 0, newChildren, 0, children.length); + children = newChildren; + } + children[index] = child; + child.jjtSetChildIndex(index); + } + + @Override + public void jjtSetChildIndex(int index) { + childIndex = index; + } + + @Override + public int jjtGetChildIndex() { + return childIndex; + } + + @Override + public Node jjtGetChild(int index) { + return children[index]; + } + + @Override + public int jjtGetNumChildren() { + return children == null ? 0 : children.length; + } + + @Override + public int jjtGetId() { + return id; + } + + /** + * Subclasses should implement this method to return a name usable with + * XPathRule for evaluating Element Names. + */ + @Override + public abstract String toString(); + + @Override + public String getImage() { + return image; + } + + @Override + public void setImage(String image) { + this.image = image; + } + + @Override + public boolean hasImageEqualTo(String image) { + return this.getImage() != null && this.getImage().equals(image); + } + + @Override + public int getBeginLine() { + return beginLine; + } + + public void testingOnlySetBeginLine(int i) { + this.beginLine = i; + } + + @Override + public int getBeginColumn() { + if (beginColumn != -1) { + return beginColumn; + } else { + if (children != null && children.length > 0) { + return children[0].getBeginColumn(); + } else { + throw new RuntimeException("Unable to determine beginning line of Node."); + } + } + } + + public void testingOnlySetBeginColumn(int i) { + this.beginColumn = i; + } + + @Override + public int getEndLine() { + return endLine; + } + + public void testingOnlySetEndLine(int i) { + this.endLine = i; + } + + @Override + public int getEndColumn() { + return endColumn; + } + + public void testingOnlySetEndColumn(int i) { + this.endColumn = i; + } + + @Override + public DataFlowNode getDataFlowNode() { + if (this.dataFlowNode == null) { + if (this.parent != null) { + return parent.getDataFlowNode(); + } + return null; // TODO wise? + } + return dataFlowNode; + } + + @Override + public void setDataFlowNode(DataFlowNode dataFlowNode) { + this.dataFlowNode = dataFlowNode; + } + + /** + * Returns the n-th parent or null if there are not n ancestors + * + * @param n + * how many ancestors to iterate over. + * @return the n-th parent or null. + * @throws IllegalArgumentException + * if n is not positive. + */ + @Override + public Node getNthParent(int n) { + if (n <= 0) { + throw new IllegalArgumentException(); + } + Node result = this.jjtGetParent(); + for (int i = 1; i < n; i++) { + if (result == null) { + return null; + } + result = result.jjtGetParent(); + } + return result; + } + + /** + * Traverses up the tree to find the first parent instance of type + * parentType + * + * @param parentType + * class which you want to find. + * @return Node of type parentType. Returns null if none found. + */ + @Override + public T getFirstParentOfType(Class parentType) { + Node parentNode = jjtGetParent(); + while (parentNode != null && parentNode.getClass() != parentType) { + parentNode = parentNode.jjtGetParent(); + } + return (T) parentNode; + } + + /** + * Traverses up the tree to find all of the parent instances of type + * parentType + * + * @param parentType + * classes which you want to find. + * @return List of parentType instances found. + */ + @Override + public List getParentsOfType(Class parentType) { + List parents = new ArrayList<>(); + Node parentNode = jjtGetParent(); + while (parentNode != null) { + if (parentNode.getClass() == parentType) { + parents.add((T) parentNode); + } + parentNode = parentNode.jjtGetParent(); + } + return parents; + } + + /** + * {@inheritDoc} + */ + @Override + public List findDescendantsOfType(Class targetType) { + List list = new ArrayList<>(); + findDescendantsOfType(this, targetType, list, true); + return list; + } + + /** + * {@inheritDoc} + */ + @Override + public void findDescendantsOfType(Class targetType, List results, boolean crossBoundaries) { + findDescendantsOfType(this, targetType, results, crossBoundaries); + } + + private static void findDescendantsOfType(Node node, Class targetType, List results, + boolean crossFindBoundaries) { + + if (!crossFindBoundaries && node.isFindBoundary()) { + return; + } + + int n = node.jjtGetNumChildren(); + for (int i = 0; i < n; i++) { + Node child = node.jjtGetChild(i); + if (child.getClass() == targetType) { + results.add((T) child); + } + + findDescendantsOfType(child, targetType, results, crossFindBoundaries); + } + } + + /** + * {@inheritDoc} + */ + @Override + public List findChildrenOfType(Class targetType) { + List list = new ArrayList<>(); + int n = jjtGetNumChildren(); + for (int i = 0; i < n; i++) { + Node child = jjtGetChild(i); + if (child.getClass() == targetType) { + list.add((T) child); + } + } + return list; + } + + @Override + public boolean isFindBoundary() { + return false; + } + + @Override + public Document getAsDocument() { + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document document = db.newDocument(); + appendElement(document); + return document; + } catch (ParserConfigurationException pce) { + throw new RuntimeException(pce); + } + } + + protected void appendElement(org.w3c.dom.Node parentNode) { + DocumentNavigator docNav = new DocumentNavigator(); + Document ownerDocument = parentNode.getOwnerDocument(); + if (ownerDocument == null) { + // If the parentNode is a Document itself, it's ownerDocument is + // null + ownerDocument = (Document) parentNode; + } + String elementName = docNav.getElementName(this); + Element element = ownerDocument.createElement(elementName); + parentNode.appendChild(element); + for (Iterator iter = docNav.getAttributeAxisIterator(this); iter.hasNext();) { + Attribute attr = iter.next(); + element.setAttribute(attr.getName(), attr.getStringValue()); + } + for (Iterator iter = docNav.getChildAxisIterator(this); iter.hasNext();) { + AbstractNode child = (AbstractNode) iter.next(); + child.appendElement(element); + } + } + + /** + * {@inheritDoc} + */ + @Override + public T getFirstDescendantOfType(Class descendantType) { + return getFirstDescendantOfType(descendantType, this); + } + + /** + * {@inheritDoc} + */ + @Override + public T getFirstChildOfType(Class childType) { + int n = jjtGetNumChildren(); + for (int i = 0; i < n; i++) { + Node child = jjtGetChild(i); + if (child.getClass() == childType) { + return (T) child; + } + } + return null; + } + + private static T getFirstDescendantOfType(Class descendantType, Node node) { + int n = node.jjtGetNumChildren(); + for (int i = 0; i < n; i++) { + Node n1 = node.jjtGetChild(i); + if (n1.getClass() == descendantType) { + return (T) n1; + } + T n2 = getFirstDescendantOfType(descendantType, n1); + if (n2 != null) { + return n2; + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean hasDescendantOfType(Class type) { + return getFirstDescendantOfType(type) != null; + } + + /** + * + * @param types + * @return boolean + */ + public final boolean hasDecendantOfAnyType(Class... types) { + for (Class type : types) { + if (hasDescendantOfType(type)) { + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public List findChildNodesWithXPath(String xpathString) throws JaxenException { + return new BaseXPath(xpathString, new DocumentNavigator()).selectNodes(this); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasDescendantMatchingXPath(String xpathString) { + try { + return !findChildNodesWithXPath(xpathString).isEmpty(); + } catch (JaxenException e) { + throw new RuntimeException("XPath expression " + xpathString + " failed: " + e.getLocalizedMessage(), e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUserData() { + return userData; + } + + /** + * {@inheritDoc} + */ + @Override + public void setUserData(Object userData) { + this.userData = userData; + } + + public GenericToken jjtGetFirstToken() { + return firstToken; + } + + public void jjtSetFirstToken(GenericToken token) { + this.firstToken = token; + } + + public GenericToken jjtGetLastToken() { + return lastToken; + } + + public void jjtSetLastToken(GenericToken token) { + this.lastToken = token; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractTokenManager.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractTokenManager.java index 28ca0a5c23..96c8e60c3d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractTokenManager.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractTokenManager.java @@ -1,38 +1,38 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast; - -import java.util.HashMap; -import java.util.Map; - -import net.sourceforge.pmd.PMD; - -public abstract class AbstractTokenManager { - - // Because the TokenMgrError class does not have access to the TokenManager - // instance, we - // cannot store the file name as an instance field, but must use a static. - private static ThreadLocal fileName = new ThreadLocal<>(); - - protected Map suppressMap = new HashMap<>(); - protected String suppressMarker = PMD.SUPPRESS_MARKER; - - public static void setFileName(String fileName) { - AbstractTokenManager.fileName.set(fileName); - } - - public static String getFileName() { - String fileName = AbstractTokenManager.fileName.get(); - return fileName == null ? "(no file name provided)" : fileName; - } - - public void setSuppressMarker(String marker) { - this.suppressMarker = marker; - } - - public Map getSuppressMap() { - return suppressMap; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +import java.util.HashMap; +import java.util.Map; + +import net.sourceforge.pmd.PMD; + +public abstract class AbstractTokenManager { + + // Because the TokenMgrError class does not have access to the TokenManager + // instance, we + // cannot store the file name as an instance field, but must use a static. + private static ThreadLocal fileName = new ThreadLocal<>(); + + protected Map suppressMap = new HashMap<>(); + protected String suppressMarker = PMD.SUPPRESS_MARKER; + + public static void setFileName(String fileName) { + AbstractTokenManager.fileName.set(fileName); + } + + public static String getFileName() { + String fileName = AbstractTokenManager.fileName.get(); + return fileName == null ? "(no file name provided)" : fileName; + } + + public void setSuppressMarker(String marker) { + this.suppressMarker = marker; + } + + public Map getSuppressMap() { + return suppressMap; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java index 9c123b71bc..600f58f258 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java @@ -1,220 +1,220 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ -/* Generated By:JJTree: Do not edit this line. Node.java */ - -package net.sourceforge.pmd.lang.ast; - -import java.util.List; - -import org.jaxen.JaxenException; -import org.w3c.dom.Document; - -import net.sourceforge.pmd.lang.dfa.DataFlowNode; - -/* All AST nodes must implement this interface. It provides basic - machinery for constructing the parent and child relationships - between nodes. */ - -public interface Node { - - /** - * This method is called after the node has been made the current node. It - * indicates that child nodes can now be added to it. - */ - void jjtOpen(); - - /** - * This method is called after all the child nodes have been added. - */ - void jjtClose(); - - /** - * This pair of methods are used to inform the node of its parent. - */ - void jjtSetParent(Node parent); - - Node jjtGetParent(); - - /** - * This method tells the node to add its argument to the node's list of - * children. - */ - void jjtAddChild(Node child, int index); - - /** - * Sets the index of this node from the perspective of its parent. This - * means: this.jjtGetParent().jjtGetChild(index) == this. - * - * @param index - * the child index - */ - void jjtSetChildIndex(int index); - - int jjtGetChildIndex(); - - /** - * This method returns a child node. The children are numbered from zero, - * left to right. - * - * @param index - * the child index. Must be nonnegative and less than - * {@link #jjtGetNumChildren}. - */ - Node jjtGetChild(int index); - - /** - * Return the number of children the node has. - */ - int jjtGetNumChildren(); - - int jjtGetId(); - - String getImage(); - - void setImage(String image); - - boolean hasImageEqualTo(String image); - - int getBeginLine(); - - int getBeginColumn(); - - int getEndLine(); - - int getEndColumn(); - - DataFlowNode getDataFlowNode(); - - void setDataFlowNode(DataFlowNode dataFlowNode); - - boolean isFindBoundary(); - - Node getNthParent(int n); - - T getFirstParentOfType(Class parentType); - - List getParentsOfType(Class parentType); - - /** - * Traverses the children to find all the instances of type childType. - * - * @see #findDescendantsOfType(Class) if traversal of the entire tree is - * needed. - * - * @param childType - * class which you want to find. - * @return List of all children of type childType. Returns an empty list if - * none found. - */ - List findChildrenOfType(Class childType); - - /** - * Traverses down the tree to find all the descendant instances of type - * descendantType. - * - * @param targetType - * class which you want to find. - * @return List of all children of type targetType. Returns an empty list if - * none found. - */ - List findDescendantsOfType(Class targetType); - - /** - * Traverses down the tree to find all the descendant instances of type - * descendantType. - * - * @param targetType - * class which you want to find. - * @param results - * list to store the matching descendants - * @param crossFindBoundaries - * if false, recursion stops for nodes for which - * {@link #isFindBoundary()} is true - */ - void findDescendantsOfType(Class targetType, List results, boolean crossFindBoundaries); - - /** - * Traverses the children to find the first instance of type childType. - * - * @see #getFirstDescendantOfType(Class) if traversal of the entire tree is - * needed. - * - * @param childType - * class which you want to find. - * @return Node of type childType. Returns null if none found. - */ - T getFirstChildOfType(Class childType); - - /** - * Traverses down the tree to find the first descendant instance of type - * descendantType. - * - * @param descendantType - * class which you want to find. - * @return Node of type descendantType. Returns null if none - * found. - */ - T getFirstDescendantOfType(Class descendantType); - - /** - * Finds if this node contains a descendant of the given type. - * - * @param type - * the node type to search - * @return true if there is at least one descendant of the - * given type - */ - boolean hasDescendantOfType(Class type); - - /** - * Returns all the nodes matching the xpath expression. - * - * @param xpathString - * the expression to check - * @return List of all matching nodes. Returns an empty list if none found. - * @throws JaxenException - */ - List findChildNodesWithXPath(String xpathString) throws JaxenException; - - /** - * Checks whether at least one descendant matches the xpath expression. - * - * @param xpathString - * the expression to check - * @return true if there is a match - */ - boolean hasDescendantMatchingXPath(String xpathString); - - /** - * Get a DOM Document which contains Elements and Attributes representative - * of this Node and it's children. Essentially a DOM tree representation of - * the Node AST, thereby allowing tools which can operate upon DOM to also - * indirectly operate on the AST. - */ - Document getAsDocument(); - - /** - * Get the user data associated with this node. By default there is no data, - * unless it has been set via {@link #setUserData(Object)}. - * - * @return The user data set on this node. - */ - Object getUserData(); - - /** - * Set the user data associated with this node. - *

- * PMD itself will never set user data onto a node. Nor should any Rule - * implementation, as the AST nodes are shared between concurrently - * executing Rules (i.e. it is not thread-safe). - *

- * This API is most useful for external applications looking to leverage - * PMD's robust support for AST structures, in which case application - * specific annotations on the AST nodes can be quite useful. - * - * @param userData - * The data to set on this node. - */ - void setUserData(Object userData); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +/* Generated By:JJTree: Do not edit this line. Node.java */ + +package net.sourceforge.pmd.lang.ast; + +import java.util.List; + +import org.jaxen.JaxenException; +import org.w3c.dom.Document; + +import net.sourceforge.pmd.lang.dfa.DataFlowNode; + +/* All AST nodes must implement this interface. It provides basic + machinery for constructing the parent and child relationships + between nodes. */ + +public interface Node { + + /** + * This method is called after the node has been made the current node. It + * indicates that child nodes can now be added to it. + */ + void jjtOpen(); + + /** + * This method is called after all the child nodes have been added. + */ + void jjtClose(); + + /** + * This pair of methods are used to inform the node of its parent. + */ + void jjtSetParent(Node parent); + + Node jjtGetParent(); + + /** + * This method tells the node to add its argument to the node's list of + * children. + */ + void jjtAddChild(Node child, int index); + + /** + * Sets the index of this node from the perspective of its parent. This + * means: this.jjtGetParent().jjtGetChild(index) == this. + * + * @param index + * the child index + */ + void jjtSetChildIndex(int index); + + int jjtGetChildIndex(); + + /** + * This method returns a child node. The children are numbered from zero, + * left to right. + * + * @param index + * the child index. Must be nonnegative and less than + * {@link #jjtGetNumChildren}. + */ + Node jjtGetChild(int index); + + /** + * Return the number of children the node has. + */ + int jjtGetNumChildren(); + + int jjtGetId(); + + String getImage(); + + void setImage(String image); + + boolean hasImageEqualTo(String image); + + int getBeginLine(); + + int getBeginColumn(); + + int getEndLine(); + + int getEndColumn(); + + DataFlowNode getDataFlowNode(); + + void setDataFlowNode(DataFlowNode dataFlowNode); + + boolean isFindBoundary(); + + Node getNthParent(int n); + + T getFirstParentOfType(Class parentType); + + List getParentsOfType(Class parentType); + + /** + * Traverses the children to find all the instances of type childType. + * + * @see #findDescendantsOfType(Class) if traversal of the entire tree is + * needed. + * + * @param childType + * class which you want to find. + * @return List of all children of type childType. Returns an empty list if + * none found. + */ + List findChildrenOfType(Class childType); + + /** + * Traverses down the tree to find all the descendant instances of type + * descendantType. + * + * @param targetType + * class which you want to find. + * @return List of all children of type targetType. Returns an empty list if + * none found. + */ + List findDescendantsOfType(Class targetType); + + /** + * Traverses down the tree to find all the descendant instances of type + * descendantType. + * + * @param targetType + * class which you want to find. + * @param results + * list to store the matching descendants + * @param crossFindBoundaries + * if false, recursion stops for nodes for which + * {@link #isFindBoundary()} is true + */ + void findDescendantsOfType(Class targetType, List results, boolean crossFindBoundaries); + + /** + * Traverses the children to find the first instance of type childType. + * + * @see #getFirstDescendantOfType(Class) if traversal of the entire tree is + * needed. + * + * @param childType + * class which you want to find. + * @return Node of type childType. Returns null if none found. + */ + T getFirstChildOfType(Class childType); + + /** + * Traverses down the tree to find the first descendant instance of type + * descendantType. + * + * @param descendantType + * class which you want to find. + * @return Node of type descendantType. Returns null if none + * found. + */ + T getFirstDescendantOfType(Class descendantType); + + /** + * Finds if this node contains a descendant of the given type. + * + * @param type + * the node type to search + * @return true if there is at least one descendant of the + * given type + */ + boolean hasDescendantOfType(Class type); + + /** + * Returns all the nodes matching the xpath expression. + * + * @param xpathString + * the expression to check + * @return List of all matching nodes. Returns an empty list if none found. + * @throws JaxenException + */ + List findChildNodesWithXPath(String xpathString) throws JaxenException; + + /** + * Checks whether at least one descendant matches the xpath expression. + * + * @param xpathString + * the expression to check + * @return true if there is a match + */ + boolean hasDescendantMatchingXPath(String xpathString); + + /** + * Get a DOM Document which contains Elements and Attributes representative + * of this Node and it's children. Essentially a DOM tree representation of + * the Node AST, thereby allowing tools which can operate upon DOM to also + * indirectly operate on the AST. + */ + Document getAsDocument(); + + /** + * Get the user data associated with this node. By default there is no data, + * unless it has been set via {@link #setUserData(Object)}. + * + * @return The user data set on this node. + */ + Object getUserData(); + + /** + * Set the user data associated with this node. + *

+ * PMD itself will never set user data onto a node. Nor should any Rule + * implementation, as the AST nodes are shared between concurrently + * executing Rules (i.e. it is not thread-safe). + *

+ * This API is most useful for external applications looking to leverage + * PMD's robust support for AST structures, in which case application + * specific annotations on the AST nodes can be quite useful. + * + * @param userData + * The data to set on this node. + */ + void setUserData(Object userData); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java index dd2eb8ad21..0a3e9e67b9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java @@ -1,24 +1,24 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast; - -public class ParseException extends RuntimeException { - - public ParseException() { - super(); - } - - public ParseException(String message) { - super(message); - } - - public ParseException(Throwable cause) { - super(cause); - } - - public ParseException(String message, Throwable cause) { - super(message, cause); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +public class ParseException extends RuntimeException { + + public ParseException() { + super(); + } + + public ParseException(String message) { + super(message); + } + + public ParseException(Throwable cause) { + super(cause); + } + + public ParseException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/RootNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/RootNode.java index 60e85bd4a5..65fc7dfa14 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/RootNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/RootNode.java @@ -1,12 +1,12 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast; - -/** - * This interface can be used to tag the root node of various ASTs. - */ -public interface RootNode { - // that's only a marker interface. -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +/** + * This interface can be used to tag the root node of various ASTs. + */ +public interface RootNode { + // that's only a marker interface. +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java index c645338204..4c9fad1fdf 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java @@ -1,24 +1,24 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath; - -import org.jaxen.Navigator; - -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.XPathHandler; - -import net.sf.saxon.sxpath.IndependentContext; - -public abstract class AbstractASTXPathHandler implements XPathHandler { - - @Override - public Navigator getNavigator() { - return new DocumentNavigator(); - } - - public void initialize(IndependentContext context, Language language, Class functionsClass) { - context.declareNamespace("pmd-" + language.getTerseName(), "java:" + functionsClass.getName()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath; + +import org.jaxen.Navigator; + +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.XPathHandler; + +import net.sf.saxon.sxpath.IndependentContext; + +public abstract class AbstractASTXPathHandler implements XPathHandler { + + @Override + public Navigator getNavigator() { + return new DocumentNavigator(); + } + + public void initialize(IndependentContext context, Language language, Class functionsClass) { + context.declareNamespace("pmd-" + language.getTerseName(), "java:" + functionsClass.getName()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeNode.java index 6a7e2b6eec..f34343f133 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeNode.java @@ -1,16 +1,16 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath; - -import java.util.Iterator; - -/** - * This interface can be used by an AST node to indicate it can directly provide - * access to it's attributes, versus having them be determined via - * introspection. - */ -public interface AttributeNode { - Iterator getAttributeIterator(); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath; + +import java.util.Iterator; + +/** + * This interface can be used by an AST node to indicate it can directly provide + * access to it's attributes, versus having them be determined via + * introspection. + */ +public interface AttributeNode { + Iterator getAttributeIterator(); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java index a04c381191..3c33db0368 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java @@ -1,381 +1,381 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -import net.sf.saxon.Configuration; -import net.sf.saxon.event.Receiver; -import net.sf.saxon.om.Axis; -import net.sf.saxon.om.AxisIterator; -import net.sf.saxon.om.DocumentInfo; -import net.sf.saxon.om.FastStringBuffer; -import net.sf.saxon.om.NamePool; -import net.sf.saxon.om.Navigator.AxisFilter; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.SiblingCountingNode; -import net.sf.saxon.om.VirtualNode; -import net.sf.saxon.pattern.NodeTest; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.value.Value; - -/** - * This is a basic implementation of the Saxon NodeInfo and related interfaces. - * Most methods are trivial implementations which immediately throw - * {@link UnsupportedOperationException}. A few of the methods actually have - * useful implementations, such as {@link #iterateAxis(byte, NodeTest)} and - * {@link #isSameNodeInfo(NodeInfo)}. - */ -public class AbstractNodeInfo implements VirtualNode, SiblingCountingNode { - /** - * {@inheritDoc} - */ - @Override - public String getSystemId() { - throw createUnsupportedOperationException("Source.getSystemId()"); - } - - /** - * {@inheritDoc} - */ - @Override - public void setSystemId(String systemId) { - throw createUnsupportedOperationException("Source.setSystemId(String)"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getStringValue() { - throw createUnsupportedOperationException("ValueRepresentation.getStringValue()"); - } - - /** - * {@inheritDoc} - */ - @Override - public CharSequence getStringValueCS() { - throw createUnsupportedOperationException("ValueRepresentation.getStringValueCS()"); - } - - /** - * {@inheritDoc} - */ - @Override - public SequenceIterator getTypedValue() throws XPathException { - throw createUnsupportedOperationException("Item.getTypedValue()"); - } - - /** - * {@inheritDoc} - */ - @Override - public Object getUnderlyingNode() { - throw createUnsupportedOperationException("VirtualNode.getUnderlyingNode()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getSiblingPosition() { - throw createUnsupportedOperationException("SiblingCountingNode.getSiblingPosition()"); - } - - /** - * {@inheritDoc} - */ - @Override - public Value atomize() throws XPathException { - throw createUnsupportedOperationException("NodeInfo.atomize()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int compareOrder(NodeInfo other) { - throw createUnsupportedOperationException("NodeInfo.compareOrder(NodeInfo)"); - } - - /** - * {@inheritDoc} - */ - @Override - public void copy(Receiver receiver, int whichNamespaces, boolean copyAnnotations, int locationId) - throws XPathException { - throw createUnsupportedOperationException("ValueRepresentation.copy(Receiver, int, boolean, int)"); - } - - /** - * This implementation considers to NodeInfo objects to be equal, if their - * underlying nodes are equal. - * - * {@inheritDoc} - */ - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other instanceof ElementNode) { - return this.getUnderlyingNode() == ((ElementNode) other).getUnderlyingNode(); - } - return false; - } - - @Override - public int hashCode() { - if (this.getUnderlyingNode() != null) { - return super.hashCode() + 31 * this.getUnderlyingNode().hashCode(); - } else { - return super.hashCode(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void generateId(FastStringBuffer buffer) { - throw createUnsupportedOperationException("NodeInfo.generateId(FastStringBuffer)"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getAttributeValue(int fingerprint) { - throw createUnsupportedOperationException("NodeInfo.getAttributeValue(int)"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getBaseURI() { - throw createUnsupportedOperationException("NodeInfo.getBaseURI()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getColumnNumber() { - throw createUnsupportedOperationException("NodeInfo.getColumnNumber()"); - } - - /** - * {@inheritDoc} - */ - @Override - public Configuration getConfiguration() { - throw createUnsupportedOperationException("NodeInfo.getConfiguration()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int[] getDeclaredNamespaces(int[] buffer) { - throw createUnsupportedOperationException("NodeInfo.getDeclaredNamespaces(int[])"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getDisplayName() { - throw createUnsupportedOperationException("NodeInfo.getDisplayName()"); - } - - /** - * This implementation always returns 0. - * - * {@inheritDoc} - */ - @Override - public int getDocumentNumber() { - return 0; - } - - /** - * {@inheritDoc} - */ - @Override - public DocumentInfo getDocumentRoot() { - throw createUnsupportedOperationException("NodeInfo.getDocumentRoot()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getFingerprint() { - throw createUnsupportedOperationException("NodeInfo.getFingerprint()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getLineNumber() { - throw createUnsupportedOperationException("NodeInfo.getLineNumber()"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getLocalPart() { - throw createUnsupportedOperationException("NodeInfo.getLocalPart()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getNameCode() { - throw createUnsupportedOperationException("NodeInfo.getNameCode()"); - } - - /** - * {@inheritDoc} - */ - @Override - public NamePool getNamePool() { - throw createUnsupportedOperationException("NodeInfo.getNamePool()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getNodeKind() { - throw createUnsupportedOperationException("NodeInfo.getNodeKind()"); - } - - /** - * {@inheritDoc} - */ - @Override - public NodeInfo getParent() { - throw createUnsupportedOperationException("NodeInfo.getParent()"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getPrefix() { - throw createUnsupportedOperationException("NodeInfo.getPrefix()"); - } - - /** - * {@inheritDoc} - */ - @Override - public NodeInfo getRoot() { - throw createUnsupportedOperationException("NodeInfo.getRoot()"); - } - - /** - * {@inheritDoc} - */ - @Override - public int getTypeAnnotation() { - throw createUnsupportedOperationException("NodeInfo.getTypeAnnotation()"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getURI() { - throw createUnsupportedOperationException("NodeInfo.getURI()"); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasChildNodes() { - throw createUnsupportedOperationException("NodeInfo.hasChildNodes()"); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isId() { - throw createUnsupportedOperationException("NodeInfo.isId()"); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isIdref() { - throw createUnsupportedOperationException("NodeInfo.isIdref()"); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isNilled() { - throw createUnsupportedOperationException("NodeInfo.isNilled()"); - } - - /** - * This implementation delegates to {@link #equals(Object)}, per the Saxon - * documentation's description of this method's behavior. - * - * {@inheritDoc} - */ - @Override - public boolean isSameNodeInfo(NodeInfo other) { - return this.equals(other); - } - - /** - * {@inheritDoc} - */ - @Override - public AxisIterator iterateAxis(byte axisNumber) { - throw createUnsupportedOperationException( - "NodeInfo.iterateAxis(byte) for axis '" + Axis.axisName[axisNumber] + "'"); - } - - /** - * This implementation calls {@link #iterateAxis(byte)} to get an - * {@link AxisIterator} which is then optionally filtered using - * {@link AxisFilter}. - * - * {@inheritDoc} - */ - @Override - public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { - AxisIterator axisIterator = iterateAxis(axisNumber); - if (nodeTest != null) { - axisIterator = new AxisFilter(axisIterator, nodeTest); - } - return axisIterator; - } - - /** - * Used to create a customized instance of UnsupportedOperationException. - * The caller of this method is intended to throw the - * exception. - * - * @param name - * Method name that is not supported. - * @return A UnsupportedOperationException indicated the method is not - * supported by the implementation class. - */ - protected UnsupportedOperationException createUnsupportedOperationException(String name) { - return new UnsupportedOperationException(name + " is not implemented by " + this.getClass().getName()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath.saxon; + +import net.sf.saxon.Configuration; +import net.sf.saxon.event.Receiver; +import net.sf.saxon.om.Axis; +import net.sf.saxon.om.AxisIterator; +import net.sf.saxon.om.DocumentInfo; +import net.sf.saxon.om.FastStringBuffer; +import net.sf.saxon.om.NamePool; +import net.sf.saxon.om.Navigator.AxisFilter; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.om.SiblingCountingNode; +import net.sf.saxon.om.VirtualNode; +import net.sf.saxon.pattern.NodeTest; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.Value; + +/** + * This is a basic implementation of the Saxon NodeInfo and related interfaces. + * Most methods are trivial implementations which immediately throw + * {@link UnsupportedOperationException}. A few of the methods actually have + * useful implementations, such as {@link #iterateAxis(byte, NodeTest)} and + * {@link #isSameNodeInfo(NodeInfo)}. + */ +public class AbstractNodeInfo implements VirtualNode, SiblingCountingNode { + /** + * {@inheritDoc} + */ + @Override + public String getSystemId() { + throw createUnsupportedOperationException("Source.getSystemId()"); + } + + /** + * {@inheritDoc} + */ + @Override + public void setSystemId(String systemId) { + throw createUnsupportedOperationException("Source.setSystemId(String)"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getStringValue() { + throw createUnsupportedOperationException("ValueRepresentation.getStringValue()"); + } + + /** + * {@inheritDoc} + */ + @Override + public CharSequence getStringValueCS() { + throw createUnsupportedOperationException("ValueRepresentation.getStringValueCS()"); + } + + /** + * {@inheritDoc} + */ + @Override + public SequenceIterator getTypedValue() throws XPathException { + throw createUnsupportedOperationException("Item.getTypedValue()"); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getUnderlyingNode() { + throw createUnsupportedOperationException("VirtualNode.getUnderlyingNode()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getSiblingPosition() { + throw createUnsupportedOperationException("SiblingCountingNode.getSiblingPosition()"); + } + + /** + * {@inheritDoc} + */ + @Override + public Value atomize() throws XPathException { + throw createUnsupportedOperationException("NodeInfo.atomize()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int compareOrder(NodeInfo other) { + throw createUnsupportedOperationException("NodeInfo.compareOrder(NodeInfo)"); + } + + /** + * {@inheritDoc} + */ + @Override + public void copy(Receiver receiver, int whichNamespaces, boolean copyAnnotations, int locationId) + throws XPathException { + throw createUnsupportedOperationException("ValueRepresentation.copy(Receiver, int, boolean, int)"); + } + + /** + * This implementation considers to NodeInfo objects to be equal, if their + * underlying nodes are equal. + * + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other instanceof ElementNode) { + return this.getUnderlyingNode() == ((ElementNode) other).getUnderlyingNode(); + } + return false; + } + + @Override + public int hashCode() { + if (this.getUnderlyingNode() != null) { + return super.hashCode() + 31 * this.getUnderlyingNode().hashCode(); + } else { + return super.hashCode(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void generateId(FastStringBuffer buffer) { + throw createUnsupportedOperationException("NodeInfo.generateId(FastStringBuffer)"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getAttributeValue(int fingerprint) { + throw createUnsupportedOperationException("NodeInfo.getAttributeValue(int)"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getBaseURI() { + throw createUnsupportedOperationException("NodeInfo.getBaseURI()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getColumnNumber() { + throw createUnsupportedOperationException("NodeInfo.getColumnNumber()"); + } + + /** + * {@inheritDoc} + */ + @Override + public Configuration getConfiguration() { + throw createUnsupportedOperationException("NodeInfo.getConfiguration()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int[] getDeclaredNamespaces(int[] buffer) { + throw createUnsupportedOperationException("NodeInfo.getDeclaredNamespaces(int[])"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getDisplayName() { + throw createUnsupportedOperationException("NodeInfo.getDisplayName()"); + } + + /** + * This implementation always returns 0. + * + * {@inheritDoc} + */ + @Override + public int getDocumentNumber() { + return 0; + } + + /** + * {@inheritDoc} + */ + @Override + public DocumentInfo getDocumentRoot() { + throw createUnsupportedOperationException("NodeInfo.getDocumentRoot()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getFingerprint() { + throw createUnsupportedOperationException("NodeInfo.getFingerprint()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getLineNumber() { + throw createUnsupportedOperationException("NodeInfo.getLineNumber()"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getLocalPart() { + throw createUnsupportedOperationException("NodeInfo.getLocalPart()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getNameCode() { + throw createUnsupportedOperationException("NodeInfo.getNameCode()"); + } + + /** + * {@inheritDoc} + */ + @Override + public NamePool getNamePool() { + throw createUnsupportedOperationException("NodeInfo.getNamePool()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getNodeKind() { + throw createUnsupportedOperationException("NodeInfo.getNodeKind()"); + } + + /** + * {@inheritDoc} + */ + @Override + public NodeInfo getParent() { + throw createUnsupportedOperationException("NodeInfo.getParent()"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getPrefix() { + throw createUnsupportedOperationException("NodeInfo.getPrefix()"); + } + + /** + * {@inheritDoc} + */ + @Override + public NodeInfo getRoot() { + throw createUnsupportedOperationException("NodeInfo.getRoot()"); + } + + /** + * {@inheritDoc} + */ + @Override + public int getTypeAnnotation() { + throw createUnsupportedOperationException("NodeInfo.getTypeAnnotation()"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getURI() { + throw createUnsupportedOperationException("NodeInfo.getURI()"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasChildNodes() { + throw createUnsupportedOperationException("NodeInfo.hasChildNodes()"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isId() { + throw createUnsupportedOperationException("NodeInfo.isId()"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIdref() { + throw createUnsupportedOperationException("NodeInfo.isIdref()"); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isNilled() { + throw createUnsupportedOperationException("NodeInfo.isNilled()"); + } + + /** + * This implementation delegates to {@link #equals(Object)}, per the Saxon + * documentation's description of this method's behavior. + * + * {@inheritDoc} + */ + @Override + public boolean isSameNodeInfo(NodeInfo other) { + return this.equals(other); + } + + /** + * {@inheritDoc} + */ + @Override + public AxisIterator iterateAxis(byte axisNumber) { + throw createUnsupportedOperationException( + "NodeInfo.iterateAxis(byte) for axis '" + Axis.axisName[axisNumber] + "'"); + } + + /** + * This implementation calls {@link #iterateAxis(byte)} to get an + * {@link AxisIterator} which is then optionally filtered using + * {@link AxisFilter}. + * + * {@inheritDoc} + */ + @Override + public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { + AxisIterator axisIterator = iterateAxis(axisNumber); + if (nodeTest != null) { + axisIterator = new AxisFilter(axisIterator, nodeTest); + } + return axisIterator; + } + + /** + * Used to create a customized instance of UnsupportedOperationException. + * The caller of this method is intended to throw the + * exception. + * + * @param name + * Method name that is not supported. + * @return A UnsupportedOperationException indicated the method is not + * supported by the implementation class. + */ + protected UnsupportedOperationException createUnsupportedOperationException(String name) { + return new UnsupportedOperationException(name + " is not implemented by " + this.getClass().getName()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java index 5062efbee4..b56cc1ac0d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java @@ -1,50 +1,50 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -import net.sourceforge.pmd.lang.ast.xpath.Attribute; - -import net.sf.saxon.om.Navigator; -import net.sf.saxon.om.SequenceIterator; - -/** - * This is an Attribute axis iterator. - */ -public class AttributeAxisIterator extends Navigator.BaseEnumeration { - - protected final ElementNode startNodeInfo; - protected final net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator iterator; - - /** - * Create an iterator over the Attribute axis for the given ElementNode. - * - * @see net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator - */ - public AttributeAxisIterator(ElementNode startNodeInfo) { - this.startNodeInfo = startNodeInfo; - this.iterator = new net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator(startNodeInfo.node); - } - - /** - * {@inheritDoc} - */ - @Override - public SequenceIterator getAnother() { - return new AttributeAxisIterator(startNodeInfo); - } - - /** - * {@inheritDoc} - */ - @Override - public void advance() { - if (this.iterator.hasNext()) { - Attribute attribute = this.iterator.next(); - super.current = new AttributeNode(attribute, super.position()); - } else { - super.current = null; - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath.saxon; + +import net.sourceforge.pmd.lang.ast.xpath.Attribute; + +import net.sf.saxon.om.Navigator; +import net.sf.saxon.om.SequenceIterator; + +/** + * This is an Attribute axis iterator. + */ +public class AttributeAxisIterator extends Navigator.BaseEnumeration { + + protected final ElementNode startNodeInfo; + protected final net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator iterator; + + /** + * Create an iterator over the Attribute axis for the given ElementNode. + * + * @see net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator + */ + public AttributeAxisIterator(ElementNode startNodeInfo) { + this.startNodeInfo = startNodeInfo; + this.iterator = new net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator(startNodeInfo.node); + } + + /** + * {@inheritDoc} + */ + @Override + public SequenceIterator getAnother() { + return new AttributeAxisIterator(startNodeInfo); + } + + /** + * {@inheritDoc} + */ + @Override + public void advance() { + if (this.iterator.hasNext()) { + Attribute attribute = this.iterator.next(); + super.current = new AttributeNode(attribute, super.position()); + } else { + super.current = null; + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java index 624250ef3f..8b859f1c38 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java @@ -1,83 +1,83 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -import net.sourceforge.pmd.lang.ast.xpath.Attribute; - -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.type.Type; -import net.sf.saxon.value.BooleanValue; -import net.sf.saxon.value.EmptySequence; -import net.sf.saxon.value.Int64Value; -import net.sf.saxon.value.StringValue; -import net.sf.saxon.value.Value; - -/** - * A Saxon OM Attribute node for an AST Node Attribute. - */ -public class AttributeNode extends AbstractNodeInfo { - protected final Attribute attribute; - protected final int id; - protected Value value; - - public AttributeNode(Attribute attribute, int id) { - this.attribute = attribute; - this.id = id; - } - - @Override - public int getNodeKind() { - return Type.ATTRIBUTE; - } - - @Override - public String getLocalPart() { - return attribute.getName(); - } - - @Override - public String getURI() { - return ""; - } - - @Override - public Value atomize() throws XPathException { - if (value == null) { - Object v = attribute.getValue(); - // TODO Need to handle the full range of types, is there something - // Saxon can do to help? - if (v instanceof String) { - value = new StringValue((String) v); - } else if (v instanceof Boolean) { - value = BooleanValue.get(((Boolean) v).booleanValue()); - } else if (v instanceof Integer) { - value = Int64Value.makeIntegerValue((Integer) v); - } else if (v == null) { - value = EmptySequence.getInstance(); - } else { - throw new RuntimeException( - "Unable to create ValueRepresentaton for attribute value: " + v + " of type " + v.getClass()); - } - } - return value; - } - - @Override - public CharSequence getStringValueCS() { - return attribute.getStringValue(); - } - - @Override - public SequenceIterator getTypedValue() throws XPathException { - return atomize().iterate(); - } - - @Override - public int compareOrder(NodeInfo other) { - return Integer.signum(this.id - ((AttributeNode) other).id); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath.saxon; + +import net.sourceforge.pmd.lang.ast.xpath.Attribute; + +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.type.Type; +import net.sf.saxon.value.BooleanValue; +import net.sf.saxon.value.EmptySequence; +import net.sf.saxon.value.Int64Value; +import net.sf.saxon.value.StringValue; +import net.sf.saxon.value.Value; + +/** + * A Saxon OM Attribute node for an AST Node Attribute. + */ +public class AttributeNode extends AbstractNodeInfo { + protected final Attribute attribute; + protected final int id; + protected Value value; + + public AttributeNode(Attribute attribute, int id) { + this.attribute = attribute; + this.id = id; + } + + @Override + public int getNodeKind() { + return Type.ATTRIBUTE; + } + + @Override + public String getLocalPart() { + return attribute.getName(); + } + + @Override + public String getURI() { + return ""; + } + + @Override + public Value atomize() throws XPathException { + if (value == null) { + Object v = attribute.getValue(); + // TODO Need to handle the full range of types, is there something + // Saxon can do to help? + if (v instanceof String) { + value = new StringValue((String) v); + } else if (v instanceof Boolean) { + value = BooleanValue.get(((Boolean) v).booleanValue()); + } else if (v instanceof Integer) { + value = Int64Value.makeIntegerValue((Integer) v); + } else if (v == null) { + value = EmptySequence.getInstance(); + } else { + throw new RuntimeException( + "Unable to create ValueRepresentaton for attribute value: " + v + " of type " + v.getClass()); + } + } + return value; + } + + @Override + public CharSequence getStringValueCS() { + return attribute.getStringValue(); + } + + @Override + public SequenceIterator getTypedValue() throws XPathException { + return atomize().iterate(); + } + + @Override + public int compareOrder(NodeInfo other) { + return Integer.signum(this.id - ((AttributeNode) other).id); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java index e1de476a16..a98308857b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java @@ -1,101 +1,101 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.sourceforge.pmd.lang.ast.Node; - -import net.sf.saxon.om.Axis; -import net.sf.saxon.om.AxisIterator; -import net.sf.saxon.om.DocumentInfo; -import net.sf.saxon.om.Navigator; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SingleNodeIterator; -import net.sf.saxon.type.Type; - -/** - * A Saxon OM Document node for an AST Node. - */ -public class DocumentNode extends AbstractNodeInfo implements DocumentInfo { - - /** - * The root ElementNode of the DocumentNode. - */ - protected final ElementNode rootNode; - - /** - * Mapping from AST Node to corresponding ElementNode. - */ - public final Map nodeToElementNode = new HashMap<>(); - - /** - * Construct a DocumentNode, with the given AST Node serving as the root - * ElementNode. - * - * @param node - * The root AST Node. - * - * @see ElementNode - */ - public DocumentNode(Node node) { - this.rootNode = new ElementNode(this, new IdGenerator(), null, node, -1); - } - - /** - * {@inheritDoc} - */ - @Override - public String[] getUnparsedEntity(String name) { - throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntity(String)"); - } - - /** - * {@inheritDoc} - */ - @Override - public Iterator getUnparsedEntityNames() { - throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntityNames()"); - } - - /** - * {@inheritDoc} - */ - @Override - public NodeInfo selectID(String id) { - throw createUnsupportedOperationException("DocumentInfo.selectID(String)"); - } - - @Override - public int getNodeKind() { - return Type.DOCUMENT; - } - - @Override - public DocumentInfo getDocumentRoot() { - return this; - } - - @Override - public boolean hasChildNodes() { - return true; - } - - @Override - public AxisIterator iterateAxis(byte axisNumber) { - switch (axisNumber) { - case Axis.DESCENDANT: - return new Navigator.DescendantEnumeration(this, false, true); - case Axis.DESCENDANT_OR_SELF: - return new Navigator.DescendantEnumeration(this, true, true); - case Axis.CHILD: - return SingleNodeIterator.makeIterator(rootNode); - default: - return super.iterateAxis(axisNumber); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath.saxon; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.sourceforge.pmd.lang.ast.Node; + +import net.sf.saxon.om.Axis; +import net.sf.saxon.om.AxisIterator; +import net.sf.saxon.om.DocumentInfo; +import net.sf.saxon.om.Navigator; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.om.SingleNodeIterator; +import net.sf.saxon.type.Type; + +/** + * A Saxon OM Document node for an AST Node. + */ +public class DocumentNode extends AbstractNodeInfo implements DocumentInfo { + + /** + * The root ElementNode of the DocumentNode. + */ + protected final ElementNode rootNode; + + /** + * Mapping from AST Node to corresponding ElementNode. + */ + public final Map nodeToElementNode = new HashMap<>(); + + /** + * Construct a DocumentNode, with the given AST Node serving as the root + * ElementNode. + * + * @param node + * The root AST Node. + * + * @see ElementNode + */ + public DocumentNode(Node node) { + this.rootNode = new ElementNode(this, new IdGenerator(), null, node, -1); + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getUnparsedEntity(String name) { + throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntity(String)"); + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator getUnparsedEntityNames() { + throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntityNames()"); + } + + /** + * {@inheritDoc} + */ + @Override + public NodeInfo selectID(String id) { + throw createUnsupportedOperationException("DocumentInfo.selectID(String)"); + } + + @Override + public int getNodeKind() { + return Type.DOCUMENT; + } + + @Override + public DocumentInfo getDocumentRoot() { + return this; + } + + @Override + public boolean hasChildNodes() { + return true; + } + + @Override + public AxisIterator iterateAxis(byte axisNumber) { + switch (axisNumber) { + case Axis.DESCENDANT: + return new Navigator.DescendantEnumeration(this, false, true); + case Axis.DESCENDANT_OR_SELF: + return new Navigator.DescendantEnumeration(this, true, true); + case Axis.CHILD: + return SingleNodeIterator.makeIterator(rootNode); + default: + return super.iterateAxis(axisNumber); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java index aa3d815a57..dc407538a1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java @@ -1,153 +1,153 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -import net.sourceforge.pmd.lang.ast.Node; - -import net.sf.saxon.om.Axis; -import net.sf.saxon.om.AxisIterator; -import net.sf.saxon.om.DocumentInfo; -import net.sf.saxon.om.EmptyIterator; -import net.sf.saxon.om.Navigator; -import net.sf.saxon.om.NodeArrayIterator; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SingleNodeIterator; -import net.sf.saxon.type.Type; - -/** - * A Saxon OM Element type node for an AST Node. - */ -public class ElementNode extends AbstractNodeInfo { - - protected final DocumentNode document; - protected final ElementNode parent; - protected final Node node; - protected final int id; - protected final int siblingPosition; - protected final NodeInfo[] children; - - public ElementNode(DocumentNode document, IdGenerator idGenerator, ElementNode parent, Node node, - int siblingPosition) { - this.document = document; - this.parent = parent; - this.node = node; - this.id = idGenerator.getNextId(); - this.siblingPosition = siblingPosition; - if (node.jjtGetNumChildren() > 0) { - this.children = new NodeInfo[node.jjtGetNumChildren()]; - for (int i = 0; i < children.length; i++) { - children[i] = new ElementNode(document, idGenerator, this, node.jjtGetChild(i), i); - } - } else { - this.children = null; - } - document.nodeToElementNode.put(node, this); - } - - @Override - public Object getUnderlyingNode() { - return node; - } - - @Override - public int getSiblingPosition() { - return siblingPosition; - } - - @Override - public int getColumnNumber() { - return node.getBeginColumn(); - } - - @Override - public int getLineNumber() { - return node.getBeginLine(); - } - - @Override - public boolean hasChildNodes() { - return children != null; - } - - @Override - public int getNodeKind() { - return Type.ELEMENT; - } - - @Override - public DocumentInfo getDocumentRoot() { - return document; - } - - @Override - public String getLocalPart() { - return node.toString(); - } - - @Override - public String getURI() { - return ""; - } - - @Override - public NodeInfo getParent() { - return parent; - } - - @Override - public int compareOrder(NodeInfo other) { - return Integer.signum(this.node.jjtGetId() - ((ElementNode) other).node.jjtGetId()); - } - - @SuppressWarnings("PMD.MissingBreakInSwitch") - @Override - public AxisIterator iterateAxis(byte axisNumber) { - switch (axisNumber) { - case Axis.ANCESTOR: - return new Navigator.AncestorEnumeration(this, false); - case Axis.ANCESTOR_OR_SELF: - return new Navigator.AncestorEnumeration(this, true); - case Axis.ATTRIBUTE: - return new AttributeAxisIterator(this); - case Axis.CHILD: - if (children == null) { - return EmptyIterator.getInstance(); - } else { - return new NodeArrayIterator(children); - } - case Axis.DESCENDANT: - return new Navigator.DescendantEnumeration(this, false, true); - case Axis.DESCENDANT_OR_SELF: - return new Navigator.DescendantEnumeration(this, true, true); - case Axis.FOLLOWING: - return new Navigator.FollowingEnumeration(this); - case Axis.FOLLOWING_SIBLING: - if (parent == null || siblingPosition == parent.children.length - 1) { - return EmptyIterator.getInstance(); - } else { - return new NodeArrayIterator(parent.children, siblingPosition + 1, parent.children.length); - } - case Axis.NAMESPACE: - return super.iterateAxis(axisNumber); - case Axis.PARENT: - return SingleNodeIterator.makeIterator(parent); - case Axis.PRECEDING: - return new Navigator.PrecedingEnumeration(this, false); - case Axis.PRECEDING_SIBLING: - if (parent == null || siblingPosition == 0) { - return EmptyIterator.getInstance(); - } else { - return new NodeArrayIterator(parent.children, 0, siblingPosition); - } - case Axis.SELF: - return SingleNodeIterator.makeIterator(this); - case Axis.PRECEDING_OR_ANCESTOR: - return new Navigator.PrecedingEnumeration(this, true); - default: - return super.iterateAxis(axisNumber); - } - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath.saxon; + +import net.sourceforge.pmd.lang.ast.Node; + +import net.sf.saxon.om.Axis; +import net.sf.saxon.om.AxisIterator; +import net.sf.saxon.om.DocumentInfo; +import net.sf.saxon.om.EmptyIterator; +import net.sf.saxon.om.Navigator; +import net.sf.saxon.om.NodeArrayIterator; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.om.SingleNodeIterator; +import net.sf.saxon.type.Type; + +/** + * A Saxon OM Element type node for an AST Node. + */ +public class ElementNode extends AbstractNodeInfo { + + protected final DocumentNode document; + protected final ElementNode parent; + protected final Node node; + protected final int id; + protected final int siblingPosition; + protected final NodeInfo[] children; + + public ElementNode(DocumentNode document, IdGenerator idGenerator, ElementNode parent, Node node, + int siblingPosition) { + this.document = document; + this.parent = parent; + this.node = node; + this.id = idGenerator.getNextId(); + this.siblingPosition = siblingPosition; + if (node.jjtGetNumChildren() > 0) { + this.children = new NodeInfo[node.jjtGetNumChildren()]; + for (int i = 0; i < children.length; i++) { + children[i] = new ElementNode(document, idGenerator, this, node.jjtGetChild(i), i); + } + } else { + this.children = null; + } + document.nodeToElementNode.put(node, this); + } + + @Override + public Object getUnderlyingNode() { + return node; + } + + @Override + public int getSiblingPosition() { + return siblingPosition; + } + + @Override + public int getColumnNumber() { + return node.getBeginColumn(); + } + + @Override + public int getLineNumber() { + return node.getBeginLine(); + } + + @Override + public boolean hasChildNodes() { + return children != null; + } + + @Override + public int getNodeKind() { + return Type.ELEMENT; + } + + @Override + public DocumentInfo getDocumentRoot() { + return document; + } + + @Override + public String getLocalPart() { + return node.toString(); + } + + @Override + public String getURI() { + return ""; + } + + @Override + public NodeInfo getParent() { + return parent; + } + + @Override + public int compareOrder(NodeInfo other) { + return Integer.signum(this.node.jjtGetId() - ((ElementNode) other).node.jjtGetId()); + } + + @SuppressWarnings("PMD.MissingBreakInSwitch") + @Override + public AxisIterator iterateAxis(byte axisNumber) { + switch (axisNumber) { + case Axis.ANCESTOR: + return new Navigator.AncestorEnumeration(this, false); + case Axis.ANCESTOR_OR_SELF: + return new Navigator.AncestorEnumeration(this, true); + case Axis.ATTRIBUTE: + return new AttributeAxisIterator(this); + case Axis.CHILD: + if (children == null) { + return EmptyIterator.getInstance(); + } else { + return new NodeArrayIterator(children); + } + case Axis.DESCENDANT: + return new Navigator.DescendantEnumeration(this, false, true); + case Axis.DESCENDANT_OR_SELF: + return new Navigator.DescendantEnumeration(this, true, true); + case Axis.FOLLOWING: + return new Navigator.FollowingEnumeration(this); + case Axis.FOLLOWING_SIBLING: + if (parent == null || siblingPosition == parent.children.length - 1) { + return EmptyIterator.getInstance(); + } else { + return new NodeArrayIterator(parent.children, siblingPosition + 1, parent.children.length); + } + case Axis.NAMESPACE: + return super.iterateAxis(axisNumber); + case Axis.PARENT: + return SingleNodeIterator.makeIterator(parent); + case Axis.PRECEDING: + return new Navigator.PrecedingEnumeration(this, false); + case Axis.PRECEDING_SIBLING: + if (parent == null || siblingPosition == 0) { + return EmptyIterator.getInstance(); + } else { + return new NodeArrayIterator(parent.children, 0, siblingPosition); + } + case Axis.SELF: + return SingleNodeIterator.makeIterator(this); + case Axis.PRECEDING_OR_ANCESTOR: + return new Navigator.PrecedingEnumeration(this, true); + default: + return super.iterateAxis(axisNumber); + } + } + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java index 208bffb59a..a014729421 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java @@ -1,16 +1,16 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -/** - * This class is used to generate unique IDs for nodes. - */ -public class IdGenerator { - private int id; - - public int getNextId() { - return id++; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast.xpath.saxon; + +/** + * This class is used to generate unique IDs for nodes. + */ +public class IdGenerator { + private int id; + + public int getNextId() { + return id++; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/AbstractDataFlowNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/AbstractDataFlowNode.java index 09e2332a78..0e18b1bea6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/AbstractDataFlowNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/AbstractDataFlowNode.java @@ -1,155 +1,155 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.List; -import java.util.StringTokenizer; - -import net.sourceforge.pmd.lang.ast.Node; - -/** - * Each data flow contains a set of DataFlowNodes. - * - * @author raik - */ -public abstract class AbstractDataFlowNode implements DataFlowNode { - - protected Node node; - - protected List parents = new ArrayList<>(); - protected List children = new ArrayList<>(); - protected BitSet type = new BitSet(); - protected List variableAccess = new ArrayList<>(); - protected List dataFlow; - protected int line; - - public AbstractDataFlowNode(List dataFlow) { - this.dataFlow = dataFlow; - if (!this.dataFlow.isEmpty()) { - DataFlowNode parent = this.dataFlow.get(this.dataFlow.size() - 1); - parent.addPathToChild(this); - } - this.dataFlow.add(this); - } - - public AbstractDataFlowNode(List dataFlow, Node node) { - this(dataFlow); - - this.node = node; - node.setDataFlowNode(this); - this.line = node.getBeginLine(); - } - - @Override - public void addPathToChild(DataFlowNode child) { - DataFlowNode thisChild = child; - // TODO - throw an exception if already contained in children list? - if (!this.children.contains(thisChild) || this.equals(thisChild)) { - this.children.add(thisChild); - thisChild.getParents().add(this); - } - } - - @Override - public boolean removePathToChild(DataFlowNode child) { - DataFlowNode thisChild = child; - thisChild.getParents().remove(this); - return this.children.remove(thisChild); - } - - @Override - public void reverseParentPathsTo(DataFlowNode destination) { - while (!parents.isEmpty()) { - DataFlowNode parent = parents.get(0); - parent.removePathToChild(this); - parent.addPathToChild(destination); - } - } - - @Override - public int getLine() { - return this.line; - } - - @Override - public void setType(int type) { - this.type.set(type); - } - - @Override - public boolean isType(int intype) { - try { - return type.get(intype); - } catch (IndexOutOfBoundsException e) { - e.printStackTrace(); - } - return false; - } - - @Override - public Node getNode() { - return this.node; - } - - @Override - public List getChildren() { - return this.children; - } - - @Override - public List getParents() { - return this.parents; - } - - @Override - public List getFlow() { - return this.dataFlow; - } - - @Override - public int getIndex() { - return this.dataFlow.indexOf(this); - } - - @Override - public void setVariableAccess(List variableAccess) { - if (this.variableAccess.isEmpty()) { - this.variableAccess = variableAccess; - } else { - this.variableAccess.addAll(variableAccess); - } - } - - @Override - public List getVariableAccess() { - return this.variableAccess; - } - - @Override - public String toString() { - String res = "DataFlowNode: line " + this.getLine() + ", "; - String tmp = type.toString(); - String newTmp = ""; - for (char c : tmp.toCharArray()) { - if (c != '{' && c != '}' && c != ' ') { - newTmp += c; - } - } - for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) { - int newTmpInt = Integer.parseInt(st.nextToken()); - res += "(" + stringFromType(newTmpInt) + ")"; - } - res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1); - res += node.getImage() == null ? "" : "(" + this.node.getImage() + ")"; - return res; - } - - private String stringFromType(int intype) { - return NodeType.stringFromType(intype); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.dfa; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; +import java.util.StringTokenizer; + +import net.sourceforge.pmd.lang.ast.Node; + +/** + * Each data flow contains a set of DataFlowNodes. + * + * @author raik + */ +public abstract class AbstractDataFlowNode implements DataFlowNode { + + protected Node node; + + protected List parents = new ArrayList<>(); + protected List children = new ArrayList<>(); + protected BitSet type = new BitSet(); + protected List variableAccess = new ArrayList<>(); + protected List dataFlow; + protected int line; + + public AbstractDataFlowNode(List dataFlow) { + this.dataFlow = dataFlow; + if (!this.dataFlow.isEmpty()) { + DataFlowNode parent = this.dataFlow.get(this.dataFlow.size() - 1); + parent.addPathToChild(this); + } + this.dataFlow.add(this); + } + + public AbstractDataFlowNode(List dataFlow, Node node) { + this(dataFlow); + + this.node = node; + node.setDataFlowNode(this); + this.line = node.getBeginLine(); + } + + @Override + public void addPathToChild(DataFlowNode child) { + DataFlowNode thisChild = child; + // TODO - throw an exception if already contained in children list? + if (!this.children.contains(thisChild) || this.equals(thisChild)) { + this.children.add(thisChild); + thisChild.getParents().add(this); + } + } + + @Override + public boolean removePathToChild(DataFlowNode child) { + DataFlowNode thisChild = child; + thisChild.getParents().remove(this); + return this.children.remove(thisChild); + } + + @Override + public void reverseParentPathsTo(DataFlowNode destination) { + while (!parents.isEmpty()) { + DataFlowNode parent = parents.get(0); + parent.removePathToChild(this); + parent.addPathToChild(destination); + } + } + + @Override + public int getLine() { + return this.line; + } + + @Override + public void setType(int type) { + this.type.set(type); + } + + @Override + public boolean isType(int intype) { + try { + return type.get(intype); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public Node getNode() { + return this.node; + } + + @Override + public List getChildren() { + return this.children; + } + + @Override + public List getParents() { + return this.parents; + } + + @Override + public List getFlow() { + return this.dataFlow; + } + + @Override + public int getIndex() { + return this.dataFlow.indexOf(this); + } + + @Override + public void setVariableAccess(List variableAccess) { + if (this.variableAccess.isEmpty()) { + this.variableAccess = variableAccess; + } else { + this.variableAccess.addAll(variableAccess); + } + } + + @Override + public List getVariableAccess() { + return this.variableAccess; + } + + @Override + public String toString() { + String res = "DataFlowNode: line " + this.getLine() + ", "; + String tmp = type.toString(); + String newTmp = ""; + for (char c : tmp.toCharArray()) { + if (c != '{' && c != '}' && c != ' ') { + newTmp += c; + } + } + for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) { + int newTmpInt = Integer.parseInt(st.nextToken()); + res += "(" + stringFromType(newTmpInt) + ")"; + } + res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1); + res += node.getImage() == null ? "" : "(" + this.node.getImage() + ")"; + return res; + } + + private String stringFromType(int intype) { + return NodeType.stringFromType(intype); + } + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java index a173fe43c5..331b23088f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java @@ -1,276 +1,276 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.PropertySource; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RulePriority; -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.ast.Node; - -/** - * Base class for Rule implementations which delegate to another Rule instance. - */ -public abstract class AbstractDelegateRule implements Rule { - - private Rule rule; - - public void setRule(Rule rule) { - this.rule = rule; - } - - public Rule getRule() { - return rule; - } - - @Override - public Language getLanguage() { - return rule.getLanguage(); - } - - @Override - public void setLanguage(Language language) { - rule.setLanguage(language); - } - - @Override - public LanguageVersion getMinimumLanguageVersion() { - return rule.getMinimumLanguageVersion(); - } - - @Override - public void setMinimumLanguageVersion(LanguageVersion minimumlanguageVersion) { - rule.setMinimumLanguageVersion(minimumlanguageVersion); - } - - @Override - public void setMaximumLanguageVersion(LanguageVersion maximumlanguageVersion) { - rule.setMaximumLanguageVersion(maximumlanguageVersion); - } - - @Override - public LanguageVersion getMaximumLanguageVersion() { - return rule.getMaximumLanguageVersion(); - } - - @Override - public boolean isDeprecated() { - return rule.isDeprecated(); - } - - /** - * @see PropertySource#dysfunctionReason() - */ - @Override - public String dysfunctionReason() { - return rule.dysfunctionReason(); - } - - @Override - public Set> ignoredProperties() { - return rule.ignoredProperties(); - } - - @Override - public void setDeprecated(boolean deprecated) { - rule.setDeprecated(deprecated); - } - - @Override - public String getName() { - return rule.getName(); - } - - @Override - public void setName(String name) { - rule.setName(name); - } - - @Override - public String getSince() { - return rule.getSince(); - } - - @Override - public void setSince(String since) { - rule.setSince(since); - } - - @Override - public String getRuleClass() { - return rule.getRuleClass(); - } - - @Override - public void setRuleClass(String ruleClass) { - rule.setRuleClass(ruleClass); - } - - @Override - public String getRuleSetName() { - return rule.getRuleSetName(); - } - - @Override - public void setRuleSetName(String name) { - rule.setRuleSetName(name); - } - - @Override - public String getMessage() { - return rule.getMessage(); - } - - @Override - public void setMessage(String message) { - rule.setMessage(message); - } - - @Override - public String getDescription() { - return rule.getDescription(); - } - - @Override - public void setDescription(String description) { - rule.setDescription(description); - } - - @Override - public List getExamples() { - return rule.getExamples(); - } - - @Override - public void addExample(String example) { - rule.addExample(example); - } - - @Override - public String getExternalInfoUrl() { - return rule.getExternalInfoUrl(); - } - - @Override - public void setExternalInfoUrl(String url) { - rule.setExternalInfoUrl(url); - } - - @Override - public RulePriority getPriority() { - return rule.getPriority(); - } - - @Override - public void setPriority(RulePriority priority) { - rule.setPriority(priority); - } - - @Override - public ParserOptions getParserOptions() { - return rule.getParserOptions(); - } - - @Override - public void definePropertyDescriptor(PropertyDescriptor propertyDescriptor) throws IllegalArgumentException { - rule.definePropertyDescriptor(propertyDescriptor); - } - - @Override - public PropertyDescriptor getPropertyDescriptor(String name) { - return rule.getPropertyDescriptor(name); - } - - @Override - public List> getPropertyDescriptors() { - return rule.getPropertyDescriptors(); - } - - @Override - public T getProperty(PropertyDescriptor propertyDescriptor) { - return rule.getProperty(propertyDescriptor); - } - - @Override - public void setProperty(PropertyDescriptor propertyDescriptor, T value) { - rule.setProperty(propertyDescriptor, value); - } - - @Override - public Map, Object> getPropertiesByPropertyDescriptor() { - return rule.getPropertiesByPropertyDescriptor(); - } - - @Override - public void setUsesDFA() { - rule.setUsesDFA(); - } - - @Override - public boolean usesDFA() { - return rule.usesDFA(); - } - - @Override - public void setUsesTypeResolution() { - rule.setUsesTypeResolution(); - } - - @Override - public boolean usesTypeResolution() { - return rule.usesTypeResolution(); - } - - @Override - public boolean usesRuleChain() { - return rule.usesRuleChain(); - } - - @Override - public List getRuleChainVisits() { - return rule.getRuleChainVisits(); - } - - @Override - public void addRuleChainVisit(Class nodeClass) { - rule.addRuleChainVisit(nodeClass); - } - - @Override - public void addRuleChainVisit(String astNodeName) { - rule.addRuleChainVisit(astNodeName); - } - - @Override - public void start(RuleContext ctx) { - rule.start(ctx); - } - - @Override - public void apply(List nodes, RuleContext ctx) { - rule.apply(nodes, ctx); - } - - @Override - public void end(RuleContext ctx) { - rule.end(ctx); - } - - /** - * @see Rule#hasDescriptor(PropertyDescriptor) - */ - @Override - public boolean hasDescriptor(PropertyDescriptor descriptor) { - return rule.hasDescriptor(descriptor); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.PropertySource; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RulePriority; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.ast.Node; + +/** + * Base class for Rule implementations which delegate to another Rule instance. + */ +public abstract class AbstractDelegateRule implements Rule { + + private Rule rule; + + public void setRule(Rule rule) { + this.rule = rule; + } + + public Rule getRule() { + return rule; + } + + @Override + public Language getLanguage() { + return rule.getLanguage(); + } + + @Override + public void setLanguage(Language language) { + rule.setLanguage(language); + } + + @Override + public LanguageVersion getMinimumLanguageVersion() { + return rule.getMinimumLanguageVersion(); + } + + @Override + public void setMinimumLanguageVersion(LanguageVersion minimumlanguageVersion) { + rule.setMinimumLanguageVersion(minimumlanguageVersion); + } + + @Override + public void setMaximumLanguageVersion(LanguageVersion maximumlanguageVersion) { + rule.setMaximumLanguageVersion(maximumlanguageVersion); + } + + @Override + public LanguageVersion getMaximumLanguageVersion() { + return rule.getMaximumLanguageVersion(); + } + + @Override + public boolean isDeprecated() { + return rule.isDeprecated(); + } + + /** + * @see PropertySource#dysfunctionReason() + */ + @Override + public String dysfunctionReason() { + return rule.dysfunctionReason(); + } + + @Override + public Set> ignoredProperties() { + return rule.ignoredProperties(); + } + + @Override + public void setDeprecated(boolean deprecated) { + rule.setDeprecated(deprecated); + } + + @Override + public String getName() { + return rule.getName(); + } + + @Override + public void setName(String name) { + rule.setName(name); + } + + @Override + public String getSince() { + return rule.getSince(); + } + + @Override + public void setSince(String since) { + rule.setSince(since); + } + + @Override + public String getRuleClass() { + return rule.getRuleClass(); + } + + @Override + public void setRuleClass(String ruleClass) { + rule.setRuleClass(ruleClass); + } + + @Override + public String getRuleSetName() { + return rule.getRuleSetName(); + } + + @Override + public void setRuleSetName(String name) { + rule.setRuleSetName(name); + } + + @Override + public String getMessage() { + return rule.getMessage(); + } + + @Override + public void setMessage(String message) { + rule.setMessage(message); + } + + @Override + public String getDescription() { + return rule.getDescription(); + } + + @Override + public void setDescription(String description) { + rule.setDescription(description); + } + + @Override + public List getExamples() { + return rule.getExamples(); + } + + @Override + public void addExample(String example) { + rule.addExample(example); + } + + @Override + public String getExternalInfoUrl() { + return rule.getExternalInfoUrl(); + } + + @Override + public void setExternalInfoUrl(String url) { + rule.setExternalInfoUrl(url); + } + + @Override + public RulePriority getPriority() { + return rule.getPriority(); + } + + @Override + public void setPriority(RulePriority priority) { + rule.setPriority(priority); + } + + @Override + public ParserOptions getParserOptions() { + return rule.getParserOptions(); + } + + @Override + public void definePropertyDescriptor(PropertyDescriptor propertyDescriptor) throws IllegalArgumentException { + rule.definePropertyDescriptor(propertyDescriptor); + } + + @Override + public PropertyDescriptor getPropertyDescriptor(String name) { + return rule.getPropertyDescriptor(name); + } + + @Override + public List> getPropertyDescriptors() { + return rule.getPropertyDescriptors(); + } + + @Override + public T getProperty(PropertyDescriptor propertyDescriptor) { + return rule.getProperty(propertyDescriptor); + } + + @Override + public void setProperty(PropertyDescriptor propertyDescriptor, T value) { + rule.setProperty(propertyDescriptor, value); + } + + @Override + public Map, Object> getPropertiesByPropertyDescriptor() { + return rule.getPropertiesByPropertyDescriptor(); + } + + @Override + public void setUsesDFA() { + rule.setUsesDFA(); + } + + @Override + public boolean usesDFA() { + return rule.usesDFA(); + } + + @Override + public void setUsesTypeResolution() { + rule.setUsesTypeResolution(); + } + + @Override + public boolean usesTypeResolution() { + return rule.usesTypeResolution(); + } + + @Override + public boolean usesRuleChain() { + return rule.usesRuleChain(); + } + + @Override + public List getRuleChainVisits() { + return rule.getRuleChainVisits(); + } + + @Override + public void addRuleChainVisit(Class nodeClass) { + rule.addRuleChainVisit(nodeClass); + } + + @Override + public void addRuleChainVisit(String astNodeName) { + rule.addRuleChainVisit(astNodeName); + } + + @Override + public void start(RuleContext ctx) { + rule.start(ctx); + } + + @Override + public void apply(List nodes, RuleContext ctx) { + rule.apply(nodes, ctx); + } + + @Override + public void end(RuleContext ctx) { + rule.end(ctx); + } + + /** + * @see Rule#hasDescriptor(PropertyDescriptor) + */ + @Override + public boolean hasDescriptor(PropertyDescriptor descriptor) { + return rule.hasDescriptor(descriptor); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRuleViolationFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRuleViolationFactory.java index 048304bb8b..1bce1e3456 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRuleViolationFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRuleViolationFactory.java @@ -1,53 +1,53 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -import java.text.MessageFormat; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.util.StringUtil; - -public abstract class AbstractRuleViolationFactory implements RuleViolationFactory { - - private static final Object[] NO_ARGS = new Object[0]; - - private String cleanup(String message, Object[] args) { - - if (message != null) { - // Escape PMD specific variable message format, specifically the { - // in the ${, so MessageFormat doesn't bitch. - final String escapedMessage = StringUtil.replaceString(message, "${", "$'{'"); - return MessageFormat.format(escapedMessage, args != null ? args : NO_ARGS); - } else { - return message; - } - } - - @Override - public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args) { - - String formattedMessage = cleanup(message, args); - - ruleContext.getReport().addRuleViolation(createRuleViolation(rule, ruleContext, node, formattedMessage)); - } - - @Override - public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine, - Object[] args) { - - String formattedMessage = cleanup(message, args); - - ruleContext.getReport() - .addRuleViolation(createRuleViolation(rule, ruleContext, node, formattedMessage, beginLine, endLine)); - } - - protected abstract RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message); - - protected abstract RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, - int beginLine, int endLine); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +import java.text.MessageFormat; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.util.StringUtil; + +public abstract class AbstractRuleViolationFactory implements RuleViolationFactory { + + private static final Object[] NO_ARGS = new Object[0]; + + private String cleanup(String message, Object[] args) { + + if (message != null) { + // Escape PMD specific variable message format, specifically the { + // in the ${, so MessageFormat doesn't bitch. + final String escapedMessage = StringUtil.replaceString(message, "${", "$'{'"); + return MessageFormat.format(escapedMessage, args != null ? args : NO_ARGS); + } else { + return message; + } + } + + @Override + public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args) { + + String formattedMessage = cleanup(message, args); + + ruleContext.getReport().addRuleViolation(createRuleViolation(rule, ruleContext, node, formattedMessage)); + } + + @Override + public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine, + Object[] args) { + + String formattedMessage = cleanup(message, args); + + ruleContext.getReport() + .addRuleViolation(createRuleViolation(rule, ruleContext, node, formattedMessage, beginLine, endLine)); + } + + protected abstract RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message); + + protected abstract RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, + int beginLine, int endLine); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ImmutableLanguage.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ImmutableLanguage.java index 8f708f7b8f..b71e01d24d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ImmutableLanguage.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ImmutableLanguage.java @@ -1,13 +1,13 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -/** - * This is a tag interface to indicate that a Rule implementation class does not - * support changes to it's Language. The Language is integral to the proper - * functioning of the Rule. - */ -public interface ImmutableLanguage { -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +/** + * This is a tag interface to indicate that a Rule implementation class does not + * support changes to it's Language. The Language is integral to the proper + * functioning of the Rule. + */ +public interface ImmutableLanguage { +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/MockRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/MockRule.java index 93c8239be9..8ba275f368 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/MockRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/MockRule.java @@ -1,45 +1,45 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -import java.util.List; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RulePriority; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -/** - * This is a Rule implementation which can be used in scenarios where an actual - * functional Rule is not needed. For example, during unit testing, or as an - * editable surrogate used by IDE plugins. The Language of this Rule defaults to - * Java. - */ -public class MockRule extends AbstractRule { - - public MockRule() { - super(); - setLanguage(LanguageRegistry.getLanguage("Dummy")); - definePropertyDescriptor(new IntegerProperty("testIntProperty", "testIntProperty", 0, 100, 1, 0)); - } - - public MockRule(String name, String description, String message, String ruleSetName, RulePriority priority) { - this(name, description, message, ruleSetName); - setPriority(priority); - } - - public MockRule(String name, String description, String message, String ruleSetName) { - this(); - setName(name); - setDescription(description); - setMessage(message); - setRuleSetName(ruleSetName); - } - - @Override - public void apply(List nodes, RuleContext ctx) { - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +import java.util.List; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RulePriority; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +/** + * This is a Rule implementation which can be used in scenarios where an actual + * functional Rule is not needed. For example, during unit testing, or as an + * editable surrogate used by IDE plugins. The Language of this Rule defaults to + * Java. + */ +public class MockRule extends AbstractRule { + + public MockRule() { + super(); + setLanguage(LanguageRegistry.getLanguage("Dummy")); + definePropertyDescriptor(new IntegerProperty("testIntProperty", "testIntProperty", 0, 100, 1, 0)); + } + + public MockRule(String name, String description, String message, String ruleSetName, RulePriority priority) { + this(name, description, message, ruleSetName); + setPriority(priority); + } + + public MockRule(String name, String description, String message, String ruleSetName) { + this(); + setName(name); + setDescription(description); + setMessage(message); + setRuleSetName(ruleSetName); + } + + @Override + public void apply(List nodes, RuleContext ctx) { + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java index 7c34e20f60..8e2a58a3ef 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java @@ -1,185 +1,185 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -import java.util.regex.Pattern; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.util.StringUtil; - -public class ParametricRuleViolation implements RuleViolation { - - protected final Rule rule; - protected final String description; - protected boolean suppressed; - protected String filename; - - protected int beginLine; - protected int beginColumn; - - protected int endLine; - protected int endColumn; - - protected String packageName = ""; - protected String className = ""; - protected String methodName = ""; - protected String variableName = ""; - - // FUTURE Fix to understand when a violation _must_ have a Node, and when it - // must not (to prevent erroneous Rules silently logging w/o a Node). Modify - // RuleViolationFactory to support identifying without a Node, and update - // Rule base classes too. - public ParametricRuleViolation(Rule theRule, RuleContext ctx, T node, String message) { - rule = theRule; - description = message; - filename = ctx.getSourceCodeFilename(); - if (filename == null) { - filename = ""; - } - if (node != null) { - beginLine = node.getBeginLine(); - beginColumn = node.getBeginColumn(); - endLine = node.getEndLine(); - endColumn = node.getEndColumn(); - } - - // Apply Rule specific suppressions - if (node != null && rule != null) { - setSuppression(rule, node); - } - - } - - private void setSuppression(Rule rule, T node) { - - String regex = rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR); // Regex - if (regex != null && description != null) { - if (Pattern.matches(regex, description)) { - suppressed = true; - } - } - - if (!suppressed) { // XPath - String xpath = rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR); - if (xpath != null) { - suppressed = node.hasDescendantMatchingXPath(xpath); - } - } - } - - protected String expandVariables(String message) { - - if (message.indexOf("${") < 0) { - return message; - } - - StringBuilder buf = new StringBuilder(message); - int startIndex = -1; - while ((startIndex = buf.indexOf("${", startIndex + 1)) >= 0) { - final int endIndex = buf.indexOf("}", startIndex); - if (endIndex >= 0) { - final String name = buf.substring(startIndex + 2, endIndex); - if (isVariable(name)) { - buf.replace(startIndex, endIndex + 1, getVariableValue(name)); - } - } - } - return buf.toString(); - } - - protected boolean isVariable(String name) { - return StringUtil.isAnyOf(name, "variableName", "methodName", "className", "packageName") - || rule.getPropertyDescriptor(name) != null; - } - - protected String getVariableValue(String name) { - if ("variableName".equals(name)) { - return variableName; - } else if ("methodName".equals(name)) { - return methodName; - } else if ("className".equals(name)) { - return className; - } else if ("packageName".equals(name)) { - return packageName; - } else { - final PropertyDescriptor propertyDescriptor = rule.getPropertyDescriptor(name); - return String.valueOf(rule.getProperty(propertyDescriptor)); - } - } - - @Override - public Rule getRule() { - return rule; - } - - @Override - public String getDescription() { - return expandVariables(description); - } - - @Override - public boolean isSuppressed() { - return suppressed; - } - - @Override - public String getFilename() { - return filename; - } - - @Override - public int getBeginLine() { - return beginLine; - } - - @Override - public int getBeginColumn() { - return beginColumn; - } - - @Override - public int getEndLine() { - return endLine; - } - - @Override - public int getEndColumn() { - return endColumn; - } - - @Override - public String getPackageName() { - return packageName; - } - - @Override - public String getClassName() { - return className; - } - - @Override - public String getMethodName() { - return methodName; - } - - @Override - public String getVariableName() { - return variableName; - } - - public void setLines(int theBeginLine, int theEndLine) { - beginLine = theBeginLine; - endLine = theEndLine; - } - - @Override - public String toString() { - return getFilename() + ':' + getRule() + ':' + getDescription() + ':' + beginLine; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +import java.util.regex.Pattern; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.util.StringUtil; + +public class ParametricRuleViolation implements RuleViolation { + + protected final Rule rule; + protected final String description; + protected boolean suppressed; + protected String filename; + + protected int beginLine; + protected int beginColumn; + + protected int endLine; + protected int endColumn; + + protected String packageName = ""; + protected String className = ""; + protected String methodName = ""; + protected String variableName = ""; + + // FUTURE Fix to understand when a violation _must_ have a Node, and when it + // must not (to prevent erroneous Rules silently logging w/o a Node). Modify + // RuleViolationFactory to support identifying without a Node, and update + // Rule base classes too. + public ParametricRuleViolation(Rule theRule, RuleContext ctx, T node, String message) { + rule = theRule; + description = message; + filename = ctx.getSourceCodeFilename(); + if (filename == null) { + filename = ""; + } + if (node != null) { + beginLine = node.getBeginLine(); + beginColumn = node.getBeginColumn(); + endLine = node.getEndLine(); + endColumn = node.getEndColumn(); + } + + // Apply Rule specific suppressions + if (node != null && rule != null) { + setSuppression(rule, node); + } + + } + + private void setSuppression(Rule rule, T node) { + + String regex = rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR); // Regex + if (regex != null && description != null) { + if (Pattern.matches(regex, description)) { + suppressed = true; + } + } + + if (!suppressed) { // XPath + String xpath = rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR); + if (xpath != null) { + suppressed = node.hasDescendantMatchingXPath(xpath); + } + } + } + + protected String expandVariables(String message) { + + if (message.indexOf("${") < 0) { + return message; + } + + StringBuilder buf = new StringBuilder(message); + int startIndex = -1; + while ((startIndex = buf.indexOf("${", startIndex + 1)) >= 0) { + final int endIndex = buf.indexOf("}", startIndex); + if (endIndex >= 0) { + final String name = buf.substring(startIndex + 2, endIndex); + if (isVariable(name)) { + buf.replace(startIndex, endIndex + 1, getVariableValue(name)); + } + } + } + return buf.toString(); + } + + protected boolean isVariable(String name) { + return StringUtil.isAnyOf(name, "variableName", "methodName", "className", "packageName") + || rule.getPropertyDescriptor(name) != null; + } + + protected String getVariableValue(String name) { + if ("variableName".equals(name)) { + return variableName; + } else if ("methodName".equals(name)) { + return methodName; + } else if ("className".equals(name)) { + return className; + } else if ("packageName".equals(name)) { + return packageName; + } else { + final PropertyDescriptor propertyDescriptor = rule.getPropertyDescriptor(name); + return String.valueOf(rule.getProperty(propertyDescriptor)); + } + } + + @Override + public Rule getRule() { + return rule; + } + + @Override + public String getDescription() { + return expandVariables(description); + } + + @Override + public boolean isSuppressed() { + return suppressed; + } + + @Override + public String getFilename() { + return filename; + } + + @Override + public int getBeginLine() { + return beginLine; + } + + @Override + public int getBeginColumn() { + return beginColumn; + } + + @Override + public int getEndLine() { + return endLine; + } + + @Override + public int getEndColumn() { + return endColumn; + } + + @Override + public String getPackageName() { + return packageName; + } + + @Override + public String getClassName() { + return className; + } + + @Override + public String getMethodName() { + return methodName; + } + + @Override + public String getVariableName() { + return variableName; + } + + public void setLines(int theBeginLine, int theEndLine) { + beginLine = theBeginLine; + endLine = theEndLine; + } + + @Override + public String toString() { + return getFilename() + ':' + getRule() + ':' + getDescription() + ':' + beginLine; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java index 39ceeb762d..c378022373 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java @@ -1,337 +1,337 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RulePriority; -import net.sourceforge.pmd.RuleSetReference; -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.util.StringUtil; - -/** - * This class represents a Rule which is a reference to Rule defined in another - * RuleSet. All details of the Rule are delegated to the underlying referenced - * Rule, but those operations which modify overridden aspects of the rule are - * explicitly tracked. Modification operations which set a value to the current - * underlying value do not override. - */ -public class RuleReference extends AbstractDelegateRule { - - private Language language; - private LanguageVersion minimumLanguageVersion; - private LanguageVersion maximumLanguageVersion; - private Boolean deprecated; - private String name; - private List> propertyDescriptors; - private Map, Object> propertyValues; - private String message; - private String description; - private List examples; - private String externalInfoUrl; - private RulePriority priority; - private RuleSetReference ruleSetReference; - - private static final List> EMPTY_DESCRIPTORS = new ArrayList<>(0); - - public RuleReference() { - } - - public RuleReference(Rule theRule, RuleSetReference theRuleSetReference) { - setRule(theRule); - ruleSetReference = theRuleSetReference; - } - - public Language getOverriddenLanguage() { - return language; - } - - @Override - public void setLanguage(Language language) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(language, super.getLanguage()) || this.language != null) { - this.language = language; - super.setLanguage(language); - } - } - - public LanguageVersion getOverriddenMinimumLanguageVersion() { - return minimumLanguageVersion; - } - - @Override - public void setMinimumLanguageVersion(LanguageVersion minimumLanguageVersion) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(minimumLanguageVersion, super.getMinimumLanguageVersion()) || this.minimumLanguageVersion != null) { - this.minimumLanguageVersion = minimumLanguageVersion; - super.setMinimumLanguageVersion(minimumLanguageVersion); - } - } - - public LanguageVersion getOverriddenMaximumLanguageVersion() { - return maximumLanguageVersion; - } - - @Override - public void setMaximumLanguageVersion(LanguageVersion maximumLanguageVersion) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(maximumLanguageVersion, super.getMaximumLanguageVersion()) || this.maximumLanguageVersion != null) { - this.maximumLanguageVersion = maximumLanguageVersion; - super.setMaximumLanguageVersion(maximumLanguageVersion); - } - } - - public Boolean isOverriddenDeprecated() { - return deprecated; - } - - @Override - public boolean isDeprecated() { - return deprecated != null && deprecated.booleanValue(); - } - - @Override - public void setDeprecated(boolean deprecated) { - // Deprecation does not propagate to the underlying Rule. It is the - // Rule reference itself which is being deprecated. - this.deprecated = deprecated ? deprecated : null; - } - - public String getOverriddenName() { - return name; - } - - public String getOriginalName() { - return super.getName(); - } - - @Override - public void setName(String name) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(name, super.getName()) || this.name != null) { - this.name = name; - } - } - - @Override - public String getName() { - if (this.name != null) { - return this.name; - } - return super.getName(); - } - - public String getOverriddenMessage() { - return message; - } - - @Override - public void setMessage(String message) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(message, super.getMessage()) || this.message != null) { - this.message = message; - super.setMessage(message); - } - } - - public String getOverriddenDescription() { - return description; - } - - @Override - public void setDescription(String description) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(description, super.getDescription()) || this.description != null) { - this.description = description; - super.setDescription(description); - } - } - - public List getOverriddenExamples() { - return examples; - } - - @Override - public void addExample(String example) { - // TODO Meaningful override of examples is hard, because they are merely - // a list of strings. How does one indicate override of a particular - // value? Via index? Rule.setExample(int, String)? But the XML format - // does not provide a means of overriding by index, not unless you took - // the position in the XML file to indicate corresponding index to - // override. But that means you have to override starting from index 0. - // This would be so much easier if examples had to have names, like - // properties. - - // Only override if different than current values. - if (!contains(super.getExamples(), example)) { - if (examples == null) { - examples = new ArrayList<>(1); - } - // TODO Fix later. To keep example overrides from being unbounded, - // we're only going to keep track of the last one. - examples.clear(); - examples.add(example); - super.addExample(example); - } - } - - public String getOverriddenExternalInfoUrl() { - return externalInfoUrl; - } - - @Override - public void setExternalInfoUrl(String externalInfoUrl) { - // Only override if different than current value, or if already - // overridden. - if (!isSame(externalInfoUrl, super.getExternalInfoUrl()) || this.externalInfoUrl != null) { - this.externalInfoUrl = externalInfoUrl; - super.setExternalInfoUrl(externalInfoUrl); - } - } - - public RulePriority getOverriddenPriority() { - return priority; - } - - @Override - public void setPriority(RulePriority priority) { - // Only override if different than current value, or if already - // overridden. - if (priority != super.getPriority() || this.priority != null) { - this.priority = priority; - super.setPriority(priority); - } - } - - public List> getOverriddenPropertyDescriptors() { - - return propertyDescriptors == null ? EMPTY_DESCRIPTORS : propertyDescriptors; - } - - @Override - public void definePropertyDescriptor(PropertyDescriptor propertyDescriptor) throws IllegalArgumentException { - // Define on the underlying Rule, where it is impossible to have two - // property descriptors with the same name. Therefore, there is no need - // to check if the property is already overridden at this level. - super.definePropertyDescriptor(propertyDescriptor); - if (propertyDescriptors == null) { - propertyDescriptors = new ArrayList<>(); - } - propertyDescriptors.add(propertyDescriptor); - } - - public Map, Object> getOverriddenPropertiesByPropertyDescriptor() { - return propertyValues; - } - - @Override - public void setProperty(PropertyDescriptor propertyDescriptor, T value) { - // Only override if different than current value. - if (!isSame(super.getProperty(propertyDescriptor), value)) { - if (propertyValues == null) { - propertyValues = new HashMap<>(); - } - propertyValues.put(propertyDescriptor, value); - super.setProperty(propertyDescriptor, value); - } - } - - public RuleSetReference getRuleSetReference() { - return ruleSetReference; - } - - public void setRuleSetReference(RuleSetReference ruleSetReference) { - this.ruleSetReference = ruleSetReference; - } - - private static boolean isSame(String s1, String s2) { - return StringUtil.isSame(s1, s2, true, false, true); - } - - @SuppressWarnings("PMD.CompareObjectsWithEquals") - private static boolean isSame(Object o1, Object o2) { - if (o1 instanceof Object[] && o2 instanceof Object[]) { - return isSame((Object[]) o1, (Object[]) o2); - } - return o1 == o2 || o1 != null && o2 != null && o1.equals(o2); - } - - @SuppressWarnings("PMD.UnusedNullCheckInEquals") - // TODO: fix UnusedNullCheckInEquals rule for Arrays - private static boolean isSame(Object[] a1, Object[] a2) { - return a1 == a2 || a1 != null && a2 != null && Arrays.equals(a1, a2); - } - - private static boolean contains(Collection collection, String s1) { - for (String s2 : collection) { - if (isSame(s1, s2)) { - return true; - } - } - return false; - } - - @Override - public boolean hasDescriptor(PropertyDescriptor descriptor) { - return propertyDescriptors != null && propertyDescriptors.contains(descriptor) - || super.hasDescriptor(descriptor); - } - - public boolean hasOverriddenProperty(PropertyDescriptor descriptor) { - return propertyValues != null && propertyValues.containsKey(descriptor); - } - - @Override - public boolean usesDefaultValues() { - - List> descriptors = getOverriddenPropertyDescriptors(); - if (!descriptors.isEmpty()) { - return false; - } - - for (PropertyDescriptor desc : descriptors) { - if (!isSame(desc.defaultValue(), getProperty(desc))) { - return false; - } - } - - if (!getRule().usesDefaultValues()) { - return false; - } - - return true; - } - - @Override - public void useDefaultValueFor(PropertyDescriptor desc) { - - // not sure if we should go all the way through to the real thing? - getRule().useDefaultValueFor(desc); - - if (propertyValues == null) { - return; - } - - propertyValues.remove(desc); - - if (propertyDescriptors != null) { - propertyDescriptors.remove(desc); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RulePriority; +import net.sourceforge.pmd.RuleSetReference; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.util.StringUtil; + +/** + * This class represents a Rule which is a reference to Rule defined in another + * RuleSet. All details of the Rule are delegated to the underlying referenced + * Rule, but those operations which modify overridden aspects of the rule are + * explicitly tracked. Modification operations which set a value to the current + * underlying value do not override. + */ +public class RuleReference extends AbstractDelegateRule { + + private Language language; + private LanguageVersion minimumLanguageVersion; + private LanguageVersion maximumLanguageVersion; + private Boolean deprecated; + private String name; + private List> propertyDescriptors; + private Map, Object> propertyValues; + private String message; + private String description; + private List examples; + private String externalInfoUrl; + private RulePriority priority; + private RuleSetReference ruleSetReference; + + private static final List> EMPTY_DESCRIPTORS = new ArrayList<>(0); + + public RuleReference() { + } + + public RuleReference(Rule theRule, RuleSetReference theRuleSetReference) { + setRule(theRule); + ruleSetReference = theRuleSetReference; + } + + public Language getOverriddenLanguage() { + return language; + } + + @Override + public void setLanguage(Language language) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(language, super.getLanguage()) || this.language != null) { + this.language = language; + super.setLanguage(language); + } + } + + public LanguageVersion getOverriddenMinimumLanguageVersion() { + return minimumLanguageVersion; + } + + @Override + public void setMinimumLanguageVersion(LanguageVersion minimumLanguageVersion) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(minimumLanguageVersion, super.getMinimumLanguageVersion()) || this.minimumLanguageVersion != null) { + this.minimumLanguageVersion = minimumLanguageVersion; + super.setMinimumLanguageVersion(minimumLanguageVersion); + } + } + + public LanguageVersion getOverriddenMaximumLanguageVersion() { + return maximumLanguageVersion; + } + + @Override + public void setMaximumLanguageVersion(LanguageVersion maximumLanguageVersion) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(maximumLanguageVersion, super.getMaximumLanguageVersion()) || this.maximumLanguageVersion != null) { + this.maximumLanguageVersion = maximumLanguageVersion; + super.setMaximumLanguageVersion(maximumLanguageVersion); + } + } + + public Boolean isOverriddenDeprecated() { + return deprecated; + } + + @Override + public boolean isDeprecated() { + return deprecated != null && deprecated.booleanValue(); + } + + @Override + public void setDeprecated(boolean deprecated) { + // Deprecation does not propagate to the underlying Rule. It is the + // Rule reference itself which is being deprecated. + this.deprecated = deprecated ? deprecated : null; + } + + public String getOverriddenName() { + return name; + } + + public String getOriginalName() { + return super.getName(); + } + + @Override + public void setName(String name) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(name, super.getName()) || this.name != null) { + this.name = name; + } + } + + @Override + public String getName() { + if (this.name != null) { + return this.name; + } + return super.getName(); + } + + public String getOverriddenMessage() { + return message; + } + + @Override + public void setMessage(String message) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(message, super.getMessage()) || this.message != null) { + this.message = message; + super.setMessage(message); + } + } + + public String getOverriddenDescription() { + return description; + } + + @Override + public void setDescription(String description) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(description, super.getDescription()) || this.description != null) { + this.description = description; + super.setDescription(description); + } + } + + public List getOverriddenExamples() { + return examples; + } + + @Override + public void addExample(String example) { + // TODO Meaningful override of examples is hard, because they are merely + // a list of strings. How does one indicate override of a particular + // value? Via index? Rule.setExample(int, String)? But the XML format + // does not provide a means of overriding by index, not unless you took + // the position in the XML file to indicate corresponding index to + // override. But that means you have to override starting from index 0. + // This would be so much easier if examples had to have names, like + // properties. + + // Only override if different than current values. + if (!contains(super.getExamples(), example)) { + if (examples == null) { + examples = new ArrayList<>(1); + } + // TODO Fix later. To keep example overrides from being unbounded, + // we're only going to keep track of the last one. + examples.clear(); + examples.add(example); + super.addExample(example); + } + } + + public String getOverriddenExternalInfoUrl() { + return externalInfoUrl; + } + + @Override + public void setExternalInfoUrl(String externalInfoUrl) { + // Only override if different than current value, or if already + // overridden. + if (!isSame(externalInfoUrl, super.getExternalInfoUrl()) || this.externalInfoUrl != null) { + this.externalInfoUrl = externalInfoUrl; + super.setExternalInfoUrl(externalInfoUrl); + } + } + + public RulePriority getOverriddenPriority() { + return priority; + } + + @Override + public void setPriority(RulePriority priority) { + // Only override if different than current value, or if already + // overridden. + if (priority != super.getPriority() || this.priority != null) { + this.priority = priority; + super.setPriority(priority); + } + } + + public List> getOverriddenPropertyDescriptors() { + + return propertyDescriptors == null ? EMPTY_DESCRIPTORS : propertyDescriptors; + } + + @Override + public void definePropertyDescriptor(PropertyDescriptor propertyDescriptor) throws IllegalArgumentException { + // Define on the underlying Rule, where it is impossible to have two + // property descriptors with the same name. Therefore, there is no need + // to check if the property is already overridden at this level. + super.definePropertyDescriptor(propertyDescriptor); + if (propertyDescriptors == null) { + propertyDescriptors = new ArrayList<>(); + } + propertyDescriptors.add(propertyDescriptor); + } + + public Map, Object> getOverriddenPropertiesByPropertyDescriptor() { + return propertyValues; + } + + @Override + public void setProperty(PropertyDescriptor propertyDescriptor, T value) { + // Only override if different than current value. + if (!isSame(super.getProperty(propertyDescriptor), value)) { + if (propertyValues == null) { + propertyValues = new HashMap<>(); + } + propertyValues.put(propertyDescriptor, value); + super.setProperty(propertyDescriptor, value); + } + } + + public RuleSetReference getRuleSetReference() { + return ruleSetReference; + } + + public void setRuleSetReference(RuleSetReference ruleSetReference) { + this.ruleSetReference = ruleSetReference; + } + + private static boolean isSame(String s1, String s2) { + return StringUtil.isSame(s1, s2, true, false, true); + } + + @SuppressWarnings("PMD.CompareObjectsWithEquals") + private static boolean isSame(Object o1, Object o2) { + if (o1 instanceof Object[] && o2 instanceof Object[]) { + return isSame((Object[]) o1, (Object[]) o2); + } + return o1 == o2 || o1 != null && o2 != null && o1.equals(o2); + } + + @SuppressWarnings("PMD.UnusedNullCheckInEquals") + // TODO: fix UnusedNullCheckInEquals rule for Arrays + private static boolean isSame(Object[] a1, Object[] a2) { + return a1 == a2 || a1 != null && a2 != null && Arrays.equals(a1, a2); + } + + private static boolean contains(Collection collection, String s1) { + for (String s2 : collection) { + if (isSame(s1, s2)) { + return true; + } + } + return false; + } + + @Override + public boolean hasDescriptor(PropertyDescriptor descriptor) { + return propertyDescriptors != null && propertyDescriptors.contains(descriptor) + || super.hasDescriptor(descriptor); + } + + public boolean hasOverriddenProperty(PropertyDescriptor descriptor) { + return propertyValues != null && propertyValues.containsKey(descriptor); + } + + @Override + public boolean usesDefaultValues() { + + List> descriptors = getOverriddenPropertyDescriptors(); + if (!descriptors.isEmpty()) { + return false; + } + + for (PropertyDescriptor desc : descriptors) { + if (!isSame(desc.defaultValue(), getProperty(desc))) { + return false; + } + } + + if (!getRule().usesDefaultValues()) { + return false; + } + + return true; + } + + @Override + public void useDefaultValueFor(PropertyDescriptor desc) { + + // not sure if we should go all the way through to the real thing? + getRule().useDefaultValueFor(desc); + + if (propertyValues == null) { + return; + } + + propertyValues.remove(desc); + + if (propertyDescriptors != null) { + propertyDescriptors.remove(desc); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleViolationFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleViolationFactory.java index fb95d15ee0..68959d1df0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleViolationFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleViolationFactory.java @@ -1,34 +1,34 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; - -/** - * This class handles of producing a Language specific RuleViolation and adding - * to a Report. - */ -public interface RuleViolationFactory { - /** - * Adds a violation to the report. - * - * @param ruleContext - * the RuleContext - * @param rule - * the rule - * @param node - * the node that produces the violation - * @param message - * specific message to put in the report - * @param args - * arguments to embed in the rule violation message - */ - void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args); - - void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine, - Object[] args); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; + +/** + * This class handles of producing a Language specific RuleViolation and adding + * to a Report. + */ +public interface RuleViolationFactory { + /** + * Adds a violation to the report. + * + * @param ruleContext + * the RuleContext + * @param rule + * the rule + * @param node + * the node that produces the violation + * @param message + * specific message to put in the report + * @param args + * arguments to embed in the rule violation message + */ + void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args); + + void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine, + Object[] args); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractEnumeratedProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractEnumeratedProperty.java index 2754396cf1..d241ae564b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractEnumeratedProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractEnumeratedProperty.java @@ -1,120 +1,120 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.util.CollectionUtil; - -/** - * @author Brian Remedios - * @param - */ -public abstract class AbstractEnumeratedProperty extends AbstractProperty { - - protected Map choicesByLabel; - protected Map labelsByChoice; - - private String[] orderedLabels; - protected Object[][] choices; - - /** - * @param theName - * @param theDescription - * @param theLabels - * @param theChoices - * @param choiceIndices - * @param theUIOrder - * @param isMulti - * @throws IllegalArgumentException - */ - @SuppressWarnings("unchecked") - public AbstractEnumeratedProperty(String theName, String theDescription, String[] theLabels, E[] theChoices, - int[] choiceIndices, float theUIOrder, boolean isMulti) { - super(theName, theDescription, (T) selectionsIn(theLabels, choiceIndices, isMulti), theUIOrder); - - choicesByLabel = CollectionUtil.mapFrom(theLabels, theChoices); - labelsByChoice = CollectionUtil.invertedMapFrom(choicesByLabel); - orderedLabels = theLabels; - } - - /** - * Method selectionsIn. - * - * @param items - * String[] - * @param selectionIndices - * int[] - * @param isMulti - * boolean - * @return Object - */ - private static Object selectionsIn(String[] items, int[] selectionIndices, boolean isMulti) { - String[] selections = new String[selectionIndices.length]; - final int maxIdx = items.length - 1; - for (int i = 0; i < selections.length; i++) { - if (i < 0 || i > maxIdx) { - throw new IllegalArgumentException("Invalid item index: " + i); - } - selections[i] = items[selectionIndices[i]]; - } - return isMulti ? selections : selections[0]; - } - - /** - * @return String - */ - @Override - protected String defaultAsString() { - - return isMultiValue() ? (String) defaultValue() : asDelimitedString(defaultValue(), '|'); - } - - /** - * Method nonLegalValueMsgFor. - * - * @param value - * Object - * @return String - */ - protected String nonLegalValueMsgFor(Object value) { - return value + " is not a legal value"; - } - - /** - * Method choiceFrom. - * - * @param label - * String - * @return E - */ - protected E choiceFrom(String label) { - E result = choicesByLabel.get(label); - if (result != null) { - return result; - } - throw new IllegalArgumentException(label); - } - - /** - * @see net.sourceforge.pmd.PropertyDescriptor#choices() - */ - @Override - public Object[][] choices() { - - if (choices != null) { - return choices; - } - - choices = new Object[orderedLabels.length][2]; - - for (int i = 0; i < choices.length; i++) { - choices[i][0] = orderedLabels[i]; - choices[i][1] = choicesByLabel.get(orderedLabels[i]); - } - orderedLabels = null; // no longer needed - return choices; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.util.CollectionUtil; + +/** + * @author Brian Remedios + * @param + */ +public abstract class AbstractEnumeratedProperty extends AbstractProperty { + + protected Map choicesByLabel; + protected Map labelsByChoice; + + private String[] orderedLabels; + protected Object[][] choices; + + /** + * @param theName + * @param theDescription + * @param theLabels + * @param theChoices + * @param choiceIndices + * @param theUIOrder + * @param isMulti + * @throws IllegalArgumentException + */ + @SuppressWarnings("unchecked") + public AbstractEnumeratedProperty(String theName, String theDescription, String[] theLabels, E[] theChoices, + int[] choiceIndices, float theUIOrder, boolean isMulti) { + super(theName, theDescription, (T) selectionsIn(theLabels, choiceIndices, isMulti), theUIOrder); + + choicesByLabel = CollectionUtil.mapFrom(theLabels, theChoices); + labelsByChoice = CollectionUtil.invertedMapFrom(choicesByLabel); + orderedLabels = theLabels; + } + + /** + * Method selectionsIn. + * + * @param items + * String[] + * @param selectionIndices + * int[] + * @param isMulti + * boolean + * @return Object + */ + private static Object selectionsIn(String[] items, int[] selectionIndices, boolean isMulti) { + String[] selections = new String[selectionIndices.length]; + final int maxIdx = items.length - 1; + for (int i = 0; i < selections.length; i++) { + if (i < 0 || i > maxIdx) { + throw new IllegalArgumentException("Invalid item index: " + i); + } + selections[i] = items[selectionIndices[i]]; + } + return isMulti ? selections : selections[0]; + } + + /** + * @return String + */ + @Override + protected String defaultAsString() { + + return isMultiValue() ? (String) defaultValue() : asDelimitedString(defaultValue(), '|'); + } + + /** + * Method nonLegalValueMsgFor. + * + * @param value + * Object + * @return String + */ + protected String nonLegalValueMsgFor(Object value) { + return value + " is not a legal value"; + } + + /** + * Method choiceFrom. + * + * @param label + * String + * @return E + */ + protected E choiceFrom(String label) { + E result = choicesByLabel.get(label); + if (result != null) { + return result; + } + throw new IllegalArgumentException(label); + } + + /** + * @see net.sourceforge.pmd.PropertyDescriptor#choices() + */ + @Override + public Object[][] choices() { + + if (choices != null) { + return choices; + } + + choices = new Object[orderedLabels.length][2]; + + for (int i = 0; i < choices.length; i++) { + choices[i][0] = orderedLabels[i]; + choices[i][1] = choicesByLabel.get(orderedLabels[i]); + } + orderedLabels = null; // no longer needed + return choices; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java index 27a71b6f7f..b742e4cc4b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java @@ -1,92 +1,92 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; - -/** - * Defines a property type that supports multiple Boolean values. - * - * @author Brian Remedios - */ -public class BooleanMultiProperty extends AbstractScalarProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - String[].class) { - @Override - public BooleanMultiProperty createWith(Map valuesById) { - char delimiter = delimiterIn(valuesById); - return new BooleanMultiProperty(nameIn(valuesById), descriptionIn(valuesById), - booleanValuesIn(defaultValueIn(valuesById), delimiter), 0f); - } - }; - - /** - * Constructor for BooleanMultiProperty that allows for multiple values. - * - * @param theName - * String - * @param theDescription - * String - * @param defaultValues - * Boolean[] - * @param theUIOrder - * float - */ - public BooleanMultiProperty(String theName, String theDescription, Boolean[] defaultValues, float theUIOrder) { - super(theName, theDescription, defaultValues, theUIOrder); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Boolean[].class; - } - - /** - * @return boolean - * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() - */ - @Override - public boolean isMultiValue() { - return true; - } - - /** - * Creates and returns a Boolean instance from a raw string - * - * @param value - * String - * @return Object - */ - @Override - protected Object createFrom(String value) { - return Boolean.valueOf(value); - } - - /** - * @param size - * int - * @return Object[] - */ - @Override - protected Boolean[] arrayFor(int size) { - return new Boolean[size]; - } - - /** - * @return String - */ - @Override - protected String defaultAsString() { - return asDelimitedString(defaultValue()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; + +/** + * Defines a property type that supports multiple Boolean values. + * + * @author Brian Remedios + */ +public class BooleanMultiProperty extends AbstractScalarProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + String[].class) { + @Override + public BooleanMultiProperty createWith(Map valuesById) { + char delimiter = delimiterIn(valuesById); + return new BooleanMultiProperty(nameIn(valuesById), descriptionIn(valuesById), + booleanValuesIn(defaultValueIn(valuesById), delimiter), 0f); + } + }; + + /** + * Constructor for BooleanMultiProperty that allows for multiple values. + * + * @param theName + * String + * @param theDescription + * String + * @param defaultValues + * Boolean[] + * @param theUIOrder + * float + */ + public BooleanMultiProperty(String theName, String theDescription, Boolean[] defaultValues, float theUIOrder) { + super(theName, theDescription, defaultValues, theUIOrder); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Boolean[].class; + } + + /** + * @return boolean + * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() + */ + @Override + public boolean isMultiValue() { + return true; + } + + /** + * Creates and returns a Boolean instance from a raw string + * + * @param value + * String + * @return Object + */ + @Override + protected Object createFrom(String value) { + return Boolean.valueOf(value); + } + + /** + * @param size + * int + * @return Object[] + */ + @Override + protected Boolean[] arrayFor(int size) { + return new Boolean[size]; + } + + /** + * @return String + */ + @Override + protected String defaultAsString() { + return asDelimitedString(defaultValue()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java index cf89bffb85..af3044f0c9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java @@ -1,94 +1,94 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; -import net.sourceforge.pmd.util.StringUtil; - -/** - * Defines a property type that supports multiple Character values. - * - * @author Brian Remedios - */ -public class CharacterMultiProperty extends AbstractProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Character[].class) { - - @Override - public CharacterMultiProperty createWith(Map valuesById) { - char delimiter = delimiterIn(valuesById); - return new CharacterMultiProperty(nameIn(valuesById), descriptionIn(valuesById), - charsIn(defaultValueIn(valuesById), delimiter), 0.0f, delimiter); - } - }; - - /** - * Constructor for CharacterProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param theDefaults - * char[] - * @param theUIOrder - * float - * @param delimiter - * char - * @throws IllegalArgumentException - */ - public CharacterMultiProperty(String theName, String theDescription, Character[] theDefaults, float theUIOrder, - char delimiter) { - super(theName, theDescription, theDefaults, theUIOrder, delimiter); - - if (theDefaults != null) { - for (int i = 0; i < theDefaults.length; i++) { - if (theDefaults[i].charValue() == delimiter) { - throw new IllegalArgumentException("Cannot include the delimiter in the set of defaults"); - } - } - } - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Character[].class; - } - - /** - * @param valueString - * String - * @return Object - * @throws IllegalArgumentException - * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) - */ - @Override - public Character[] valueFrom(String valueString) throws IllegalArgumentException { - String[] values = StringUtil.substringsOf(valueString, multiValueDelimiter()); - - Character[] chars = new Character[values.length]; - for (int i = 0; i < values.length; i++) { - chars[i] = Character.valueOf(values[i].charAt(0)); - } - return chars; - } - - /** - * @return boolean - * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() - */ - @Override - public boolean isMultiValue() { - return true; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; +import net.sourceforge.pmd.util.StringUtil; + +/** + * Defines a property type that supports multiple Character values. + * + * @author Brian Remedios + */ +public class CharacterMultiProperty extends AbstractProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Character[].class) { + + @Override + public CharacterMultiProperty createWith(Map valuesById) { + char delimiter = delimiterIn(valuesById); + return new CharacterMultiProperty(nameIn(valuesById), descriptionIn(valuesById), + charsIn(defaultValueIn(valuesById), delimiter), 0.0f, delimiter); + } + }; + + /** + * Constructor for CharacterProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param theDefaults + * char[] + * @param theUIOrder + * float + * @param delimiter + * char + * @throws IllegalArgumentException + */ + public CharacterMultiProperty(String theName, String theDescription, Character[] theDefaults, float theUIOrder, + char delimiter) { + super(theName, theDescription, theDefaults, theUIOrder, delimiter); + + if (theDefaults != null) { + for (int i = 0; i < theDefaults.length; i++) { + if (theDefaults[i].charValue() == delimiter) { + throw new IllegalArgumentException("Cannot include the delimiter in the set of defaults"); + } + } + } + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Character[].class; + } + + /** + * @param valueString + * String + * @return Object + * @throws IllegalArgumentException + * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) + */ + @Override + public Character[] valueFrom(String valueString) throws IllegalArgumentException { + String[] values = StringUtil.substringsOf(valueString, multiValueDelimiter()); + + Character[] chars = new Character[values.length]; + for (int i = 0; i < values.length; i++) { + chars[i] = Character.valueOf(values[i].charAt(0)); + } + return chars; + } + + /** + * @return boolean + * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() + */ + @Override + public boolean isMultiValue() { + return true; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java index 44766f877f..00c9da0966 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java @@ -1,82 +1,82 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; - -/** - * Defines a property type that supports multiple double-type property values - * within an upper and lower boundary. - * - * @author Brian Remedios - */ -public class DoubleMultiProperty extends AbstractMultiNumericProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Double[].class, NUMBER_FIELD_TYPES_BY_KEY) { - - @Override - public DoubleMultiProperty createWith(Map valuesById) { - String[] minMax = minMaxFrom(valuesById); - char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); - Double[] defaultValues = doublesIn(numericDefaultValueIn(valuesById), delimiter); - return new DoubleMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Double.parseDouble(minMax[0]), - Double.parseDouble(minMax[1]), defaultValues, 0f); - } - }; - - /** - * Constructor for DoubleProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param min - * Double - * @param max - * Double - * @param defaultValues - * Double[] - * @param theUIOrder - * float - */ - public DoubleMultiProperty(String theName, String theDescription, Double min, Double max, Double[] defaultValues, - float theUIOrder) { - super(theName, theDescription, min, max, defaultValues, theUIOrder); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Double[].class; - } - - /** - * @param value - * String - * @return Object - */ - @Override - protected Object createFrom(String value) { - return Double.valueOf(value); - } - - /** - * @param size - * int - * @return Object[] - */ - @Override - protected Object[] arrayFor(int size) { - return new Double[size]; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; + +/** + * Defines a property type that supports multiple double-type property values + * within an upper and lower boundary. + * + * @author Brian Remedios + */ +public class DoubleMultiProperty extends AbstractMultiNumericProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Double[].class, NUMBER_FIELD_TYPES_BY_KEY) { + + @Override + public DoubleMultiProperty createWith(Map valuesById) { + String[] minMax = minMaxFrom(valuesById); + char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); + Double[] defaultValues = doublesIn(numericDefaultValueIn(valuesById), delimiter); + return new DoubleMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Double.parseDouble(minMax[0]), + Double.parseDouble(minMax[1]), defaultValues, 0f); + } + }; + + /** + * Constructor for DoubleProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param min + * Double + * @param max + * Double + * @param defaultValues + * Double[] + * @param theUIOrder + * float + */ + public DoubleMultiProperty(String theName, String theDescription, Double min, Double max, Double[] defaultValues, + float theUIOrder) { + super(theName, theDescription, min, max, defaultValues, theUIOrder); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Double[].class; + } + + /** + * @param value + * String + * @return Object + */ + @Override + protected Object createFrom(String value) { + return Double.valueOf(value); + } + + /** + * @param size + * int + * @return Object[] + */ + @Override + protected Object[] arrayFor(int size) { + return new Double[size]; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java index fd2e02f665..a3dc611ea1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java @@ -1,134 +1,134 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Enumeration; -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; -import net.sourceforge.pmd.util.StringUtil; - -/** - * Defines a datatype with a set of preset values of any type as held within a - * pair of maps. While the values are not serialized out, the labels are and - * serve as keys to obtain the values. The choices() method provides the ordered - * selections to be used in an editor widget. - * - * @author Brian Remedios - * @param - */ -public class EnumeratedMultiProperty extends AbstractEnumeratedProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Enumeration[].class) { - - @Override - public EnumeratedMultiProperty createWith(Map valuesById) { - - return new EnumeratedMultiProperty(nameIn(valuesById), descriptionIn(valuesById), labelsIn(valuesById), - choicesIn(valuesById), indiciesIn(valuesById), 0f); - } - }; - - /** - * Constructor for EnumeratedProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param theLabels - * String[] - * @param theChoices - * E[] - * @param choiceIndices - * int[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public EnumeratedMultiProperty(String theName, String theDescription, String[] theLabels, E[] theChoices, - int[] choiceIndices, float theUIOrder) { - super(theName, theDescription, theLabels, theChoices, choiceIndices, theUIOrder, true); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Object[].class; - } - - /** - * @return boolean - * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() - */ - @Override - public boolean isMultiValue() { - return true; - } - - /** - * @param value - * Object - * @return String - * @see net.sourceforge.pmd.PropertyDescriptor#errorFor(Object) - */ - @Override - public String errorFor(Object value) { - Object[] values = (Object[]) value; - for (int i = 0; i < values.length; i++) { - if (!labelsByChoice.containsKey(values[i])) { - return nonLegalValueMsgFor(values[i]); - } - } - return null; - } - - /** - * - * @param value - * String - * @return Object - * @throws IllegalArgumentException - * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) - */ - @Override - public Object[] valueFrom(String value) throws IllegalArgumentException { - String[] strValues = StringUtil.substringsOf(value, multiValueDelimiter()); - - Object[] values = new Object[strValues.length]; - for (int i = 0; i < values.length; i++) { - values[i] = choiceFrom(strValues[i]); - } - return values; - } - - /** - * - * @param value - * Object - * @return String - * @see net.sourceforge.pmd.PropertyDescriptor#asDelimitedString(Object) - */ - @Override - public String asDelimitedString(Object[] value) { - Object[] choices = value; - - StringBuilder sb = new StringBuilder(); - - sb.append(labelsByChoice.get(choices[0])); - - for (int i = 1; i < choices.length; i++) { - sb.append(multiValueDelimiter()); - sb.append(labelsByChoice.get(choices[i])); - } - - return sb.toString(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Enumeration; +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; +import net.sourceforge.pmd.util.StringUtil; + +/** + * Defines a datatype with a set of preset values of any type as held within a + * pair of maps. While the values are not serialized out, the labels are and + * serve as keys to obtain the values. The choices() method provides the ordered + * selections to be used in an editor widget. + * + * @author Brian Remedios + * @param + */ +public class EnumeratedMultiProperty extends AbstractEnumeratedProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Enumeration[].class) { + + @Override + public EnumeratedMultiProperty createWith(Map valuesById) { + + return new EnumeratedMultiProperty(nameIn(valuesById), descriptionIn(valuesById), labelsIn(valuesById), + choicesIn(valuesById), indiciesIn(valuesById), 0f); + } + }; + + /** + * Constructor for EnumeratedProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param theLabels + * String[] + * @param theChoices + * E[] + * @param choiceIndices + * int[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public EnumeratedMultiProperty(String theName, String theDescription, String[] theLabels, E[] theChoices, + int[] choiceIndices, float theUIOrder) { + super(theName, theDescription, theLabels, theChoices, choiceIndices, theUIOrder, true); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Object[].class; + } + + /** + * @return boolean + * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() + */ + @Override + public boolean isMultiValue() { + return true; + } + + /** + * @param value + * Object + * @return String + * @see net.sourceforge.pmd.PropertyDescriptor#errorFor(Object) + */ + @Override + public String errorFor(Object value) { + Object[] values = (Object[]) value; + for (int i = 0; i < values.length; i++) { + if (!labelsByChoice.containsKey(values[i])) { + return nonLegalValueMsgFor(values[i]); + } + } + return null; + } + + /** + * + * @param value + * String + * @return Object + * @throws IllegalArgumentException + * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) + */ + @Override + public Object[] valueFrom(String value) throws IllegalArgumentException { + String[] strValues = StringUtil.substringsOf(value, multiValueDelimiter()); + + Object[] values = new Object[strValues.length]; + for (int i = 0; i < values.length; i++) { + values[i] = choiceFrom(strValues[i]); + } + return values; + } + + /** + * + * @param value + * Object + * @return String + * @see net.sourceforge.pmd.PropertyDescriptor#asDelimitedString(Object) + */ + @Override + public String asDelimitedString(Object[] value) { + Object[] choices = value; + + StringBuilder sb = new StringBuilder(); + + sb.append(labelsByChoice.get(choices[0])); + + for (int i = 1; i < choices.length; i++) { + sb.append(multiValueDelimiter()); + sb.append(labelsByChoice.get(choices[i])); + } + + return sb.toString(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java index 537ff25633..fa19b7231a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java @@ -1,88 +1,88 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; - -/** - * Defines a property type that support float property values within an upper - * and lower boundary. - * - * @author Brian Remedios - */ -public class FloatMultiProperty extends AbstractMultiNumericProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Float[].class, NUMBER_FIELD_TYPES_BY_KEY) { - - @Override - public FloatMultiProperty createWith(Map valuesById) { - String[] minMax = minMaxFrom(valuesById); - char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); - Float[] defaultValues = floatsIn(numericDefaultValueIn(valuesById), delimiter); - return new FloatMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Float.parseFloat(minMax[0]), - Float.parseFloat(minMax[1]), defaultValues, 0f); - } - }; - - /** - * Constructor for FloatProperty that configures it to accept multiple - * values and any number of defaults. - * - * @param theName - * String - * @param theDescription - * String - * @param min - * Float - * @param max - * Float - * @param defaultValues - * Float[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public FloatMultiProperty(String theName, String theDescription, Float min, Float max, Float[] defaultValues, - float theUIOrder) { - super(theName, theDescription, min, max, defaultValues, theUIOrder); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Float[].class; - } - - /** - * Creates an property value of the right type from a raw string. - * - * @param value - * String - * @return Object - */ - @Override - protected Object createFrom(String value) { - return Float.valueOf(value); - } - - /** - * Returns an array of the correct type for the receiver. - * - * @param size - * int - * @return Object[] - */ - @Override - protected Object[] arrayFor(int size) { - return new Float[size]; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; + +/** + * Defines a property type that support float property values within an upper + * and lower boundary. + * + * @author Brian Remedios + */ +public class FloatMultiProperty extends AbstractMultiNumericProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Float[].class, NUMBER_FIELD_TYPES_BY_KEY) { + + @Override + public FloatMultiProperty createWith(Map valuesById) { + String[] minMax = minMaxFrom(valuesById); + char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); + Float[] defaultValues = floatsIn(numericDefaultValueIn(valuesById), delimiter); + return new FloatMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Float.parseFloat(minMax[0]), + Float.parseFloat(minMax[1]), defaultValues, 0f); + } + }; + + /** + * Constructor for FloatProperty that configures it to accept multiple + * values and any number of defaults. + * + * @param theName + * String + * @param theDescription + * String + * @param min + * Float + * @param max + * Float + * @param defaultValues + * Float[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public FloatMultiProperty(String theName, String theDescription, Float min, Float max, Float[] defaultValues, + float theUIOrder) { + super(theName, theDescription, min, max, defaultValues, theUIOrder); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Float[].class; + } + + /** + * Creates an property value of the right type from a raw string. + * + * @param value + * String + * @return Object + */ + @Override + protected Object createFrom(String value) { + return Float.valueOf(value); + } + + /** + * Returns an array of the correct type for the receiver. + * + * @param size + * int + * @return Object[] + */ + @Override + protected Object[] arrayFor(int size) { + return new Float[size]; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java index 09bbe0b9a4..b437b12000 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java @@ -1,83 +1,83 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; - -/** - * Defines a datatype that supports multiple Integer property values within an - * upper and lower boundary. - * - * @author Brian Remedios - */ -public class IntegerMultiProperty extends AbstractMultiNumericProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Integer[].class, NUMBER_FIELD_TYPES_BY_KEY) { - - @Override - public IntegerMultiProperty createWith(Map valuesById) { - String[] minMax = minMaxFrom(valuesById); - char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); - Integer[] defaultValues = integersIn(numericDefaultValueIn(valuesById), delimiter); - return new IntegerMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Integer.parseInt(minMax[0]), - Integer.parseInt(minMax[1]), defaultValues, 0f); - } - }; - - /** - * Constructor for IntegerProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param min - * Integer - * @param max - * Integer - * @param theDefaults - * Integer[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public IntegerMultiProperty(String theName, String theDescription, Integer min, Integer max, Integer[] theDefaults, - float theUIOrder) { - super(theName, theDescription, min, max, theDefaults, theUIOrder); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Integer[].class; - } - - /** - * @param value - * String - * @return Object - */ - @Override - protected Object createFrom(String value) { - return Integer.valueOf(value); - } - - /** - * @param size - * int - * @return Object[] - */ - @Override - protected Object[] arrayFor(int size) { - return new Integer[size]; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; + +/** + * Defines a datatype that supports multiple Integer property values within an + * upper and lower boundary. + * + * @author Brian Remedios + */ +public class IntegerMultiProperty extends AbstractMultiNumericProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Integer[].class, NUMBER_FIELD_TYPES_BY_KEY) { + + @Override + public IntegerMultiProperty createWith(Map valuesById) { + String[] minMax = minMaxFrom(valuesById); + char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); + Integer[] defaultValues = integersIn(numericDefaultValueIn(valuesById), delimiter); + return new IntegerMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Integer.parseInt(minMax[0]), + Integer.parseInt(minMax[1]), defaultValues, 0f); + } + }; + + /** + * Constructor for IntegerProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param min + * Integer + * @param max + * Integer + * @param theDefaults + * Integer[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public IntegerMultiProperty(String theName, String theDescription, Integer min, Integer max, Integer[] theDefaults, + float theUIOrder) { + super(theName, theDescription, min, max, theDefaults, theUIOrder); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Integer[].class; + } + + /** + * @param value + * String + * @return Object + */ + @Override + protected Object createFrom(String value) { + return Integer.valueOf(value); + } + + /** + * @param size + * int + * @return Object[] + */ + @Override + protected Object[] arrayFor(int size) { + return new Integer[size]; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java index 879f0d83f5..e83e58cfaa 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java @@ -1,85 +1,85 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; - -/** - * Defines a datatype that supports multiple Long property values within an - * upper and lower boundary. - * - * @author Brian Remedios - */ -public class LongMultiProperty extends AbstractMultiNumericProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Long[].class, NUMBER_FIELD_TYPES_BY_KEY) { - - @Override - public LongMultiProperty createWith(Map valuesById) { - String[] minMax = minMaxFrom(valuesById); - char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); - Long[] defaultValues = longsIn(defaultValueIn(valuesById), delimiter); - return new LongMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Long.parseLong(minMax[0]), - Long.parseLong(minMax[1]), defaultValues, 0f); - } - }; - - /** - * Constructor for LongProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param min - * Long - * @param max - * Long - * @param theDefaults - * Long[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public LongMultiProperty(String theName, String theDescription, Long min, Long max, Long[] theDefaults, - float theUIOrder) { - super(theName, theDescription, min, max, theDefaults, theUIOrder); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Long[].class; - } - - /** - * @param value - * String - * @return Object - */ - @Override - protected Object createFrom(String value) { - return Long.valueOf(value); - } - - /** - * Returns an array of the correct type for the receiver. - * - * @param size - * int - * @return Object[] - */ - @Override - protected Object[] arrayFor(int size) { - return new Long[size]; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; + +/** + * Defines a datatype that supports multiple Long property values within an + * upper and lower boundary. + * + * @author Brian Remedios + */ +public class LongMultiProperty extends AbstractMultiNumericProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Long[].class, NUMBER_FIELD_TYPES_BY_KEY) { + + @Override + public LongMultiProperty createWith(Map valuesById) { + String[] minMax = minMaxFrom(valuesById); + char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); + Long[] defaultValues = longsIn(defaultValueIn(valuesById), delimiter); + return new LongMultiProperty(nameIn(valuesById), descriptionIn(valuesById), Long.parseLong(minMax[0]), + Long.parseLong(minMax[1]), defaultValues, 0f); + } + }; + + /** + * Constructor for LongProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param min + * Long + * @param max + * Long + * @param theDefaults + * Long[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public LongMultiProperty(String theName, String theDescription, Long min, Long max, Long[] theDefaults, + float theUIOrder) { + super(theName, theDescription, min, max, theDefaults, theUIOrder); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Long[].class; + } + + /** + * @param value + * String + * @return Object + */ + @Override + protected Object createFrom(String value) { + return Long.valueOf(value); + } + + /** + * Returns an array of the correct type for the receiver. + * + * @param size + * int + * @return Object[] + */ + @Override + protected Object[] arrayFor(int size) { + return new Long[size]; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java index 7f8a75f724..ea0476b38d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java @@ -1,102 +1,102 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; - -/** - * Defines a datatype that supports the single Long property values within an - * upper and lower boundary. - * - * @author Brian Remedios - */ -public class LongProperty extends AbstractNumericProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory(Long.class, - NUMBER_FIELD_TYPES_BY_KEY) { - - @Override - public LongProperty createWith(Map valuesById) { - final String[] minMax = minMaxFrom(valuesById); - return new LongProperty(nameIn(valuesById), descriptionIn(valuesById), Long.valueOf(minMax[0]), - Long.valueOf(minMax[1]), Long.valueOf(numericDefaultValueIn(valuesById)), 0f); - } - }; - - /** - * Constructor for LongProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param min - * Long - * @param max - * Long - * @param theDefault - * Long - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public LongProperty(String theName, String theDescription, Long min, Long max, Long theDefault, float theUIOrder) { - super(theName, theDescription, min, max, theDefault, theUIOrder); - } - - /** - * Constructor for LongProperty that limits itself to a single value within - * the specified limits. Converts string arguments into the Long values. - * - * @param theName - * String - * @param theDescription - * String - * @param minStr - * String - * @param maxStr - * String - * @param defaultStr - * String - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public LongProperty(String theName, String theDescription, String minStr, String maxStr, String defaultStr, - float theUIOrder) { - this(theName, theDescription, longFrom(minStr), longFrom(maxStr), longFrom(defaultStr), theUIOrder); - } - - /** - * @param numberString - * String - * @return Long - */ - public static Long longFrom(String numberString) { - return Long.valueOf(numberString); - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Long.class; - } - - /** - * @param value - * String - * @return Object - */ - @Override - protected Object createFrom(String value) { - return longFrom(value); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; + +/** + * Defines a datatype that supports the single Long property values within an + * upper and lower boundary. + * + * @author Brian Remedios + */ +public class LongProperty extends AbstractNumericProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory(Long.class, + NUMBER_FIELD_TYPES_BY_KEY) { + + @Override + public LongProperty createWith(Map valuesById) { + final String[] minMax = minMaxFrom(valuesById); + return new LongProperty(nameIn(valuesById), descriptionIn(valuesById), Long.valueOf(minMax[0]), + Long.valueOf(minMax[1]), Long.valueOf(numericDefaultValueIn(valuesById)), 0f); + } + }; + + /** + * Constructor for LongProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param min + * Long + * @param max + * Long + * @param theDefault + * Long + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public LongProperty(String theName, String theDescription, Long min, Long max, Long theDefault, float theUIOrder) { + super(theName, theDescription, min, max, theDefault, theUIOrder); + } + + /** + * Constructor for LongProperty that limits itself to a single value within + * the specified limits. Converts string arguments into the Long values. + * + * @param theName + * String + * @param theDescription + * String + * @param minStr + * String + * @param maxStr + * String + * @param defaultStr + * String + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public LongProperty(String theName, String theDescription, String minStr, String maxStr, String defaultStr, + float theUIOrder) { + this(theName, theDescription, longFrom(minStr), longFrom(maxStr), longFrom(defaultStr), theUIOrder); + } + + /** + * @param numberString + * String + * @return Long + */ + public static Long longFrom(String numberString) { + return Long.valueOf(numberString); + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Long.class; + } + + /** + * @param value + * String + * @return Object + */ + @Override + protected Object createFrom(String value) { + return longFrom(value); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java index d8177dd7b7..13baad7d1c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java @@ -1,153 +1,153 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.lang.reflect.Method; -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; -import net.sourceforge.pmd.util.StringUtil; - -/** - * Defines a property type that can specify multiple methods to use as part of a - * rule. - * - * Rule developers can limit the rules to those within designated packages per - * the 'legalPackages' argument in the constructor which can be an array of - * partial package names, i.e., ["java.lang", "com.mycompany" ]. - * - * @author Brian Remedios - */ -public class MethodMultiProperty extends AbstractMultiPackagedProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Method[].class, PACKAGED_FIELD_TYPES_BY_KEY) { - - @Override - public MethodMultiProperty createWith(Map valuesById) { - char delimiter = delimiterIn(valuesById); - return new MethodMultiProperty(nameIn(valuesById), descriptionIn(valuesById), defaultValueIn(valuesById), - legalPackageNamesIn(valuesById, delimiter), 0f); - } - }; - - /** - * Constructor for MethodProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param theDefaults - * Method[] - * @param legalPackageNames - * String[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public MethodMultiProperty(String theName, String theDescription, Method[] theDefaults, String[] legalPackageNames, - float theUIOrder) { - super(theName, theDescription, theDefaults, legalPackageNames, theUIOrder); - } - - /** - * Constructor for MethodProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param methodDefaults - * String - * @param legalPackageNames - * String[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public MethodMultiProperty(String theName, String theDescription, String methodDefaults, String[] legalPackageNames, - float theUIOrder) { - super(theName, theDescription, methodsFrom(methodDefaults), legalPackageNames, theUIOrder); - } - - public MethodMultiProperty(String theName, String theDescription, String methodDefaults, - Map otherParams, float theUIOrder) { - this(theName, theDescription, methodsFrom(methodDefaults), packageNamesIn(otherParams), theUIOrder); - } - - /** - * @param methodsStr - * String - * @return Method[] - */ - public static Method[] methodsFrom(String methodsStr) { - - String[] values = StringUtil.substringsOf(methodsStr, DELIMITER); - - Method[] methods = new Method[values.length]; - for (int i = 0; i < methods.length; i++) { - methods[i] = MethodProperty.methodFrom(values[i], MethodProperty.CLASS_METHOD_DELIMITER, - MethodProperty.METHOD_ARG_DELIMITER); - } - return methods; - } - - /** - * Return the value as a string that can be easily recognized and parsed - * when we see it again. - * - * @param value - * Object - * @return String - */ - @Override - protected String asString(Object value) { - return value == null ? "" : MethodProperty.asStringFor((Method) value); - } - - /** - * @param item - * Object - * @return String - */ - @Override - protected String packageNameOf(Object item) { - - final Method method = (Method) item; - return method.getDeclaringClass().getName() + '.' + method.getName(); - } - - /** - * @return String - */ - @Override - protected String itemTypeName() { - return "method"; - } - - /** - * - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return Method[].class; - } - - /** - * @param valueString - * String - * @return Object - * @throws IllegalArgumentException - * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) - */ - @Override - public Method[] valueFrom(String valueString) throws IllegalArgumentException { - return methodsFrom(valueString); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.lang.reflect.Method; +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; +import net.sourceforge.pmd.util.StringUtil; + +/** + * Defines a property type that can specify multiple methods to use as part of a + * rule. + * + * Rule developers can limit the rules to those within designated packages per + * the 'legalPackages' argument in the constructor which can be an array of + * partial package names, i.e., ["java.lang", "com.mycompany" ]. + * + * @author Brian Remedios + */ +public class MethodMultiProperty extends AbstractMultiPackagedProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Method[].class, PACKAGED_FIELD_TYPES_BY_KEY) { + + @Override + public MethodMultiProperty createWith(Map valuesById) { + char delimiter = delimiterIn(valuesById); + return new MethodMultiProperty(nameIn(valuesById), descriptionIn(valuesById), defaultValueIn(valuesById), + legalPackageNamesIn(valuesById, delimiter), 0f); + } + }; + + /** + * Constructor for MethodProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param theDefaults + * Method[] + * @param legalPackageNames + * String[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public MethodMultiProperty(String theName, String theDescription, Method[] theDefaults, String[] legalPackageNames, + float theUIOrder) { + super(theName, theDescription, theDefaults, legalPackageNames, theUIOrder); + } + + /** + * Constructor for MethodProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param methodDefaults + * String + * @param legalPackageNames + * String[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public MethodMultiProperty(String theName, String theDescription, String methodDefaults, String[] legalPackageNames, + float theUIOrder) { + super(theName, theDescription, methodsFrom(methodDefaults), legalPackageNames, theUIOrder); + } + + public MethodMultiProperty(String theName, String theDescription, String methodDefaults, + Map otherParams, float theUIOrder) { + this(theName, theDescription, methodsFrom(methodDefaults), packageNamesIn(otherParams), theUIOrder); + } + + /** + * @param methodsStr + * String + * @return Method[] + */ + public static Method[] methodsFrom(String methodsStr) { + + String[] values = StringUtil.substringsOf(methodsStr, DELIMITER); + + Method[] methods = new Method[values.length]; + for (int i = 0; i < methods.length; i++) { + methods[i] = MethodProperty.methodFrom(values[i], MethodProperty.CLASS_METHOD_DELIMITER, + MethodProperty.METHOD_ARG_DELIMITER); + } + return methods; + } + + /** + * Return the value as a string that can be easily recognized and parsed + * when we see it again. + * + * @param value + * Object + * @return String + */ + @Override + protected String asString(Object value) { + return value == null ? "" : MethodProperty.asStringFor((Method) value); + } + + /** + * @param item + * Object + * @return String + */ + @Override + protected String packageNameOf(Object item) { + + final Method method = (Method) item; + return method.getDeclaringClass().getName() + '.' + method.getName(); + } + + /** + * @return String + */ + @Override + protected String itemTypeName() { + return "method"; + } + + /** + * + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return Method[].class; + } + + /** + * @param valueString + * String + * @return Object + * @throws IllegalArgumentException + * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) + */ + @Override + public Method[] valueFrom(String valueString) throws IllegalArgumentException { + return methodsFrom(valueString); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorFactory.java index 8da91f9b28..23116766ce 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorFactory.java @@ -1,127 +1,127 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.util.StringUtil; - -public class PropertyDescriptorFactory { - - private PropertyDescriptorFactory() { } - - /** - * Returns the String type of the PropertyDescriptor for use in XML - * serialization. If the value is null the type cannot be - * serialized. - */ - public static String getPropertyDescriptorType(PropertyDescriptor propertyDescriptor) { - Class type = propertyDescriptor.type(); - String typeName = null; - // TODO - yes we can, investigate - if (propertyDescriptor instanceof EnumeratedProperty || propertyDescriptor instanceof MethodProperty - || propertyDescriptor instanceof TypeProperty) { - // Cannot serialize these kinds of PropertyDescriptors - } else if ("java.lang".equals(type.getPackage().getName())) { - typeName = type.getSimpleName(); - } - if (typeName == null) { - throw new IllegalArgumentException("Cannot encode type for PropertyDescriptor class: " + type.getName()); - } - return typeName; - } - - public static PropertyDescriptor createPropertyDescriptor(String name, String description, String type, - String delimiter, String min, String max, String value) { - return new PropertyDescriptorWrapper( - createRawPropertyDescriptor(name, description, type, delimiter, min, max, value)); - } - - private static PropertyDescriptor createRawPropertyDescriptor(String name, String description, String type, - String delimiter, String min, String max, String value) { - if ("Boolean".equals(type)) { - return new BooleanProperty(name, description, value, 0.0f); - } else if ("Boolean[]".equals(type)) { - BooleanMultiProperty property = new BooleanMultiProperty(name, description, null, 0.0f); - return new BooleanMultiProperty(name, description, property.valueFrom(value), 0.0f); - } else if ("Character".equals(type)) { - return new CharacterProperty(name, description, CharacterProperty.charFrom(value), 0.0f); - } else if ("Character[]".equals(type)) { - checkDelimiter(name, type, delimiter); - char delim = delimiter.charAt(0); - CharacterMultiProperty property = new CharacterMultiProperty(name, description, null, 0.0f, delim); - return new CharacterMultiProperty(name, description, property.valueFrom(value), 0.0f, delim); - } else if ("Double".equals(type)) { - checkMinMax(name, type, min, max); - return new DoubleProperty(name, description, min, max, value, 0.0f); - } else if ("Double[]".equals(type)) { - checkMinMax(name, type, min, max); - DoubleMultiProperty property = new DoubleMultiProperty(name, description, 0d, 0d, null, 0.0f); - return new DoubleMultiProperty(name, description, DoubleProperty.doubleFrom(min), - DoubleProperty.doubleFrom(max), property.valueFrom(value), 0.0f); - } else if ("Float".equals(type)) { - checkMinMax(name, type, min, max); - return new FloatProperty(name, description, min, max, value, 0.0f); - } else if ("Float[]".equals(type)) { - checkMinMax(name, type, min, max); - FloatMultiProperty property = new FloatMultiProperty(name, description, 0f, 0f, null, 0.0f); - return new FloatMultiProperty(name, description, FloatProperty.floatFrom(min), FloatProperty.floatFrom(max), - property.valueFrom(value), 0.0f); - } else if ("Integer".equals(type)) { - checkMinMax(name, type, min, max); - return new IntegerProperty(name, description, min, max, value, 0.0f); - } else if ("Integer[]".equals(type)) { - checkMinMax(name, type, min, max); - IntegerMultiProperty property = new IntegerMultiProperty(name, description, 0, 0, null, 0.0f); - return new IntegerMultiProperty(name, description, IntegerProperty.intFrom(min), - IntegerProperty.intFrom(max), property.valueFrom(value), 0.0f); - } else if ("Long".equals(type)) { - checkMinMax(name, type, min, max); - return new LongProperty(name, description, min, max, value, 0.0f); - } else if ("Long[]".equals(type)) { - checkMinMax(name, type, min, max); - LongMultiProperty property = new LongMultiProperty(name, description, 0L, 0L, null, 0.0f); - return new LongMultiProperty(name, description, LongProperty.longFrom(min), LongProperty.longFrom(max), - property.valueFrom(value), 0.0f); - - // TODO - include legal package names for next four types - } else if ("Type".equals(type)) { - return new TypeProperty(name, description, value, (String[]) null, 0.0f); - } else if ("Type[]".equals(type)) { - return new TypeMultiProperty(name, description, value, (String[]) null, 0.0f); - } else if ("Method".equals(type)) { - return new MethodProperty(name, description, value, (String[]) null, 0.0f); - } else if ("Method[]".equals(type)) { - return new MethodMultiProperty(name, description, value, (String[]) null, 0.0f); - - } else if ("String".equals(type)) { - return new StringProperty(name, description, value, 0.0f); - } else if ("String[]".equals(type)) { - checkDelimiter(name, type, delimiter); - char delim = delimiter.charAt(0); - StringMultiProperty property = new StringMultiProperty(name, description, null, 0.0f, delim); - return new StringMultiProperty(name, description, property.valueFrom(value), 0.0f, delim); - } else { - throw new IllegalArgumentException("Cannot define property type '" + type + "'."); - } - } - - private static void checkDelimiter(String name, String type, String delimiter) { - if (delimiter == null || delimiter.length() == 0) { - throw new IllegalArgumentException( - "Delimiter must be provided to create PropertyDescriptor for " + name + " of type " + type + "."); - } - } - - private static void checkMinMax(String name, String type, String min, String max) { - if (StringUtil.isEmpty(min)) { - throw new IllegalArgumentException( - "Min must be provided to create PropertyDescriptor for " + name + " of type " + type + "."); - } - if (StringUtil.isEmpty(max)) { - throw new IllegalArgumentException( - "Max must be provided to create PropertyDescriptor for " + name + " of type " + type + "."); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.util.StringUtil; + +public class PropertyDescriptorFactory { + + private PropertyDescriptorFactory() { } + + /** + * Returns the String type of the PropertyDescriptor for use in XML + * serialization. If the value is null the type cannot be + * serialized. + */ + public static String getPropertyDescriptorType(PropertyDescriptor propertyDescriptor) { + Class type = propertyDescriptor.type(); + String typeName = null; + // TODO - yes we can, investigate + if (propertyDescriptor instanceof EnumeratedProperty || propertyDescriptor instanceof MethodProperty + || propertyDescriptor instanceof TypeProperty) { + // Cannot serialize these kinds of PropertyDescriptors + } else if ("java.lang".equals(type.getPackage().getName())) { + typeName = type.getSimpleName(); + } + if (typeName == null) { + throw new IllegalArgumentException("Cannot encode type for PropertyDescriptor class: " + type.getName()); + } + return typeName; + } + + public static PropertyDescriptor createPropertyDescriptor(String name, String description, String type, + String delimiter, String min, String max, String value) { + return new PropertyDescriptorWrapper( + createRawPropertyDescriptor(name, description, type, delimiter, min, max, value)); + } + + private static PropertyDescriptor createRawPropertyDescriptor(String name, String description, String type, + String delimiter, String min, String max, String value) { + if ("Boolean".equals(type)) { + return new BooleanProperty(name, description, value, 0.0f); + } else if ("Boolean[]".equals(type)) { + BooleanMultiProperty property = new BooleanMultiProperty(name, description, null, 0.0f); + return new BooleanMultiProperty(name, description, property.valueFrom(value), 0.0f); + } else if ("Character".equals(type)) { + return new CharacterProperty(name, description, CharacterProperty.charFrom(value), 0.0f); + } else if ("Character[]".equals(type)) { + checkDelimiter(name, type, delimiter); + char delim = delimiter.charAt(0); + CharacterMultiProperty property = new CharacterMultiProperty(name, description, null, 0.0f, delim); + return new CharacterMultiProperty(name, description, property.valueFrom(value), 0.0f, delim); + } else if ("Double".equals(type)) { + checkMinMax(name, type, min, max); + return new DoubleProperty(name, description, min, max, value, 0.0f); + } else if ("Double[]".equals(type)) { + checkMinMax(name, type, min, max); + DoubleMultiProperty property = new DoubleMultiProperty(name, description, 0d, 0d, null, 0.0f); + return new DoubleMultiProperty(name, description, DoubleProperty.doubleFrom(min), + DoubleProperty.doubleFrom(max), property.valueFrom(value), 0.0f); + } else if ("Float".equals(type)) { + checkMinMax(name, type, min, max); + return new FloatProperty(name, description, min, max, value, 0.0f); + } else if ("Float[]".equals(type)) { + checkMinMax(name, type, min, max); + FloatMultiProperty property = new FloatMultiProperty(name, description, 0f, 0f, null, 0.0f); + return new FloatMultiProperty(name, description, FloatProperty.floatFrom(min), FloatProperty.floatFrom(max), + property.valueFrom(value), 0.0f); + } else if ("Integer".equals(type)) { + checkMinMax(name, type, min, max); + return new IntegerProperty(name, description, min, max, value, 0.0f); + } else if ("Integer[]".equals(type)) { + checkMinMax(name, type, min, max); + IntegerMultiProperty property = new IntegerMultiProperty(name, description, 0, 0, null, 0.0f); + return new IntegerMultiProperty(name, description, IntegerProperty.intFrom(min), + IntegerProperty.intFrom(max), property.valueFrom(value), 0.0f); + } else if ("Long".equals(type)) { + checkMinMax(name, type, min, max); + return new LongProperty(name, description, min, max, value, 0.0f); + } else if ("Long[]".equals(type)) { + checkMinMax(name, type, min, max); + LongMultiProperty property = new LongMultiProperty(name, description, 0L, 0L, null, 0.0f); + return new LongMultiProperty(name, description, LongProperty.longFrom(min), LongProperty.longFrom(max), + property.valueFrom(value), 0.0f); + + // TODO - include legal package names for next four types + } else if ("Type".equals(type)) { + return new TypeProperty(name, description, value, (String[]) null, 0.0f); + } else if ("Type[]".equals(type)) { + return new TypeMultiProperty(name, description, value, (String[]) null, 0.0f); + } else if ("Method".equals(type)) { + return new MethodProperty(name, description, value, (String[]) null, 0.0f); + } else if ("Method[]".equals(type)) { + return new MethodMultiProperty(name, description, value, (String[]) null, 0.0f); + + } else if ("String".equals(type)) { + return new StringProperty(name, description, value, 0.0f); + } else if ("String[]".equals(type)) { + checkDelimiter(name, type, delimiter); + char delim = delimiter.charAt(0); + StringMultiProperty property = new StringMultiProperty(name, description, null, 0.0f, delim); + return new StringMultiProperty(name, description, property.valueFrom(value), 0.0f, delim); + } else { + throw new IllegalArgumentException("Cannot define property type '" + type + "'."); + } + } + + private static void checkDelimiter(String name, String type, String delimiter) { + if (delimiter == null || delimiter.length() == 0) { + throw new IllegalArgumentException( + "Delimiter must be provided to create PropertyDescriptor for " + name + " of type " + type + "."); + } + } + + private static void checkMinMax(String name, String type, String min, String max) { + if (StringUtil.isEmpty(min)) { + throw new IllegalArgumentException( + "Min must be provided to create PropertyDescriptor for " + name + " of type " + type + "."); + } + if (StringUtil.isEmpty(max)) { + throw new IllegalArgumentException( + "Max must be provided to create PropertyDescriptor for " + name + " of type " + type + "."); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorWrapper.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorWrapper.java index 0f34d0bca7..5e0eab37d9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorWrapper.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorWrapper.java @@ -1,133 +1,133 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.Rule; - -/** - * This class serves as a wrapper class for a PropertyDescriptor instance. It - * exists to allowing the {@link PropertyDescriptorFactory} to readily flag - * properties it has created, versus those created by Rule classes. This is used - * in the encoding of a Rule to XML format to distinguish Rule defined - * PropertyDescriptors and those which were originally defined in XML. - * - * @param - * The type of the underlying PropertyDescriptor. - */ -public class PropertyDescriptorWrapper implements PropertyDescriptor { - private final PropertyDescriptor propertyDescriptor; - - public PropertyDescriptorWrapper(PropertyDescriptor propertyDescriptor) { - if (propertyDescriptor == null) { - throw new IllegalArgumentException("PropertyDescriptor cannot be null."); - } - this.propertyDescriptor = propertyDescriptor; - } - - public PropertyDescriptor getPropertyDescriptor() { - return propertyDescriptor; - } - - @Override - public String asDelimitedString(T value) { - return propertyDescriptor.asDelimitedString(value); - } - - @Override - public Object[][] choices() { - return propertyDescriptor.choices(); - } - - @Override - public int compareTo(PropertyDescriptor o) { - return propertyDescriptor.compareTo(o); - } - - @Override - public T defaultValue() { - return propertyDescriptor.defaultValue(); - } - - @Override - public String description() { - return propertyDescriptor.description(); - } - - @Override - public String errorFor(Object value) { - return propertyDescriptor.errorFor(value); - } - - @Override - public boolean isMultiValue() { - return propertyDescriptor.isMultiValue(); - } - - @Override - public boolean isRequired() { - return propertyDescriptor.isRequired(); - } - - @Override - public char multiValueDelimiter() { - return propertyDescriptor.multiValueDelimiter(); - } - - @Override - public String name() { - return propertyDescriptor.name(); - } - - @Override - public int preferredRowCount() { - return propertyDescriptor.preferredRowCount(); - } - - @Override - public String propertyErrorFor(Rule rule) { - return propertyDescriptor.propertyErrorFor(rule); - } - - @Override - public Class type() { - return propertyDescriptor.type(); - } - - @Override - public float uiOrder() { - return propertyDescriptor.uiOrder(); - } - - @Override - public T valueFrom(String propertyString) throws IllegalArgumentException { - return propertyDescriptor.valueFrom(propertyString); - } - - @Override - public Map attributeValuesById() { - return propertyDescriptor.attributeValuesById(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PropertyDescriptorWrapper) { - return this.getPropertyDescriptor().equals(((PropertyDescriptorWrapper) obj).getPropertyDescriptor()); - } - return this.getPropertyDescriptor().equals(obj); - } - - @Override - public int hashCode() { - return this.getPropertyDescriptor().hashCode(); - } - - @Override - public String toString() { - return "wrapped:" + propertyDescriptor.toString(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; + +/** + * This class serves as a wrapper class for a PropertyDescriptor instance. It + * exists to allowing the {@link PropertyDescriptorFactory} to readily flag + * properties it has created, versus those created by Rule classes. This is used + * in the encoding of a Rule to XML format to distinguish Rule defined + * PropertyDescriptors and those which were originally defined in XML. + * + * @param + * The type of the underlying PropertyDescriptor. + */ +public class PropertyDescriptorWrapper implements PropertyDescriptor { + private final PropertyDescriptor propertyDescriptor; + + public PropertyDescriptorWrapper(PropertyDescriptor propertyDescriptor) { + if (propertyDescriptor == null) { + throw new IllegalArgumentException("PropertyDescriptor cannot be null."); + } + this.propertyDescriptor = propertyDescriptor; + } + + public PropertyDescriptor getPropertyDescriptor() { + return propertyDescriptor; + } + + @Override + public String asDelimitedString(T value) { + return propertyDescriptor.asDelimitedString(value); + } + + @Override + public Object[][] choices() { + return propertyDescriptor.choices(); + } + + @Override + public int compareTo(PropertyDescriptor o) { + return propertyDescriptor.compareTo(o); + } + + @Override + public T defaultValue() { + return propertyDescriptor.defaultValue(); + } + + @Override + public String description() { + return propertyDescriptor.description(); + } + + @Override + public String errorFor(Object value) { + return propertyDescriptor.errorFor(value); + } + + @Override + public boolean isMultiValue() { + return propertyDescriptor.isMultiValue(); + } + + @Override + public boolean isRequired() { + return propertyDescriptor.isRequired(); + } + + @Override + public char multiValueDelimiter() { + return propertyDescriptor.multiValueDelimiter(); + } + + @Override + public String name() { + return propertyDescriptor.name(); + } + + @Override + public int preferredRowCount() { + return propertyDescriptor.preferredRowCount(); + } + + @Override + public String propertyErrorFor(Rule rule) { + return propertyDescriptor.propertyErrorFor(rule); + } + + @Override + public Class type() { + return propertyDescriptor.type(); + } + + @Override + public float uiOrder() { + return propertyDescriptor.uiOrder(); + } + + @Override + public T valueFrom(String propertyString) throws IllegalArgumentException { + return propertyDescriptor.valueFrom(propertyString); + } + + @Override + public Map attributeValuesById() { + return propertyDescriptor.attributeValuesById(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PropertyDescriptorWrapper) { + return this.getPropertyDescriptor().equals(((PropertyDescriptorWrapper) obj).getPropertyDescriptor()); + } + return this.getPropertyDescriptor().equals(obj); + } + + @Override + public int hashCode() { + return this.getPropertyDescriptor().hashCode(); + } + + @Override + public String toString() { + return "wrapped:" + propertyDescriptor.toString(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java index 49920fe574..76948becde 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java @@ -1,139 +1,139 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; -import net.sourceforge.pmd.util.StringUtil; - -/** - * Defines a datatype that supports multiple String values. Note that all - * strings must be filtered by the delimiter character. - * - * @author Brian Remedios - */ -public class StringMultiProperty extends AbstractProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - String[].class) { - - @Override - public StringMultiProperty createWith(Map valuesById) { - char delimiter = delimiterIn(valuesById); - return new StringMultiProperty(nameIn(valuesById), descriptionIn(valuesById), - StringUtil.substringsOf(defaultValueIn(valuesById), delimiter), 0.0f, delimiter); - } - }; - - /** - * Constructor for StringProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param theDefaults - * String[] - * @param theUIOrder - * float - * @param delimiter - * String - * @throws IllegalArgumentException - */ - public StringMultiProperty(String theName, String theDescription, String[] theDefaults, float theUIOrder, - char delimiter) { - super(theName, theDescription, theDefaults, theUIOrder, delimiter); - - checkDefaults(theDefaults, delimiter); - } - - /** - * @param defaultValue - * @param delim - * @throws IllegalArgumentException - */ - private static void checkDefaults(String[] defaultValue, char delim) { - - if (defaultValue == null) { - return; - } - - for (int i = 0; i < defaultValue.length; i++) { - if (defaultValue[i].indexOf(delim) >= 0) { - throw new IllegalArgumentException("Cannot include the delimiter in the set of defaults"); - } - } - } - - /** - * @return Class - * @see net.sourceforge.pmd.PropertyDescriptor#type() - */ - @Override - public Class type() { - return String[].class; - } - - /** - * @param valueString - * String - * @return Object - * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) - */ - @Override - public String[] valueFrom(String valueString) { - return StringUtil.substringsOf(valueString, multiValueDelimiter()); - } - - /** - * @param value - * String - * @return boolean - */ - private boolean containsDelimiter(String value) { - return value.indexOf(multiValueDelimiter()) >= 0; - } - - /** - * @return String - */ - private String illegalCharMsg() { - return "Value cannot contain the '" + multiValueDelimiter() + "' character"; - } - - /** - * - * @param value - * Object - * @return String - */ - @Override - protected String valueErrorFor(Object value) { - - if (value == null) { - return "missing value"; - } - - String testValue = (String) value; - if (containsDelimiter(testValue)) { - return illegalCharMsg(); - } - - // TODO - eval against regex checkers - - return null; - } - - /** - * @return boolean - * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() - */ - @Override - public boolean isMultiValue() { - return true; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; +import net.sourceforge.pmd.util.StringUtil; + +/** + * Defines a datatype that supports multiple String values. Note that all + * strings must be filtered by the delimiter character. + * + * @author Brian Remedios + */ +public class StringMultiProperty extends AbstractProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + String[].class) { + + @Override + public StringMultiProperty createWith(Map valuesById) { + char delimiter = delimiterIn(valuesById); + return new StringMultiProperty(nameIn(valuesById), descriptionIn(valuesById), + StringUtil.substringsOf(defaultValueIn(valuesById), delimiter), 0.0f, delimiter); + } + }; + + /** + * Constructor for StringProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param theDefaults + * String[] + * @param theUIOrder + * float + * @param delimiter + * String + * @throws IllegalArgumentException + */ + public StringMultiProperty(String theName, String theDescription, String[] theDefaults, float theUIOrder, + char delimiter) { + super(theName, theDescription, theDefaults, theUIOrder, delimiter); + + checkDefaults(theDefaults, delimiter); + } + + /** + * @param defaultValue + * @param delim + * @throws IllegalArgumentException + */ + private static void checkDefaults(String[] defaultValue, char delim) { + + if (defaultValue == null) { + return; + } + + for (int i = 0; i < defaultValue.length; i++) { + if (defaultValue[i].indexOf(delim) >= 0) { + throw new IllegalArgumentException("Cannot include the delimiter in the set of defaults"); + } + } + } + + /** + * @return Class + * @see net.sourceforge.pmd.PropertyDescriptor#type() + */ + @Override + public Class type() { + return String[].class; + } + + /** + * @param valueString + * String + * @return Object + * @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String) + */ + @Override + public String[] valueFrom(String valueString) { + return StringUtil.substringsOf(valueString, multiValueDelimiter()); + } + + /** + * @param value + * String + * @return boolean + */ + private boolean containsDelimiter(String value) { + return value.indexOf(multiValueDelimiter()) >= 0; + } + + /** + * @return String + */ + private String illegalCharMsg() { + return "Value cannot contain the '" + multiValueDelimiter() + "' character"; + } + + /** + * + * @param value + * Object + * @return String + */ + @Override + protected String valueErrorFor(Object value) { + + if (value == null) { + return "missing value"; + } + + String testValue = (String) value; + if (containsDelimiter(testValue)) { + return illegalCharMsg(); + } + + // TODO - eval against regex checkers + + return null; + } + + /** + * @return boolean + * @see net.sourceforge.pmd.PropertyDescriptor#isMultiValue() + */ + @Override + public boolean isMultiValue() { + return true; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java index fc747dc0b7..55817523b7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java @@ -1,144 +1,144 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.properties; - -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.PropertyDescriptorFactory; -import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; -import net.sourceforge.pmd.util.StringUtil; - -/** - * Defines a property that supports multiple class types, even for primitive - * values! - * - * TODO - untested for array types - * - * @author Brian Remedios - */ -public class TypeMultiProperty extends AbstractMultiPackagedProperty { - - public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( - Class[].class, PACKAGED_FIELD_TYPES_BY_KEY) { - - @Override - public TypeMultiProperty createWith(Map valuesById) { - char delimiter = delimiterIn(valuesById); - return new TypeMultiProperty(nameIn(valuesById), descriptionIn(valuesById), defaultValueIn(valuesById), - legalPackageNamesIn(valuesById, delimiter), 0f); - } - }; - - /** - * Constructor for TypeProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param theDefaults - * Class[] - * @param legalPackageNames - * String[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public TypeMultiProperty(String theName, String theDescription, Class[] theDefaults, String[] legalPackageNames, - float theUIOrder) { - super(theName, theDescription, theDefaults, legalPackageNames, theUIOrder); - - } - - /** - * Constructor for TypeProperty. - * - * @param theName - * String - * @param theDescription - * String - * @param theTypeDefaults - * String - * @param legalPackageNames - * String[] - * @param theUIOrder - * float - * @throws IllegalArgumentException - */ - public TypeMultiProperty(String theName, String theDescription, String theTypeDefaults, String[] legalPackageNames, - float theUIOrder) { - this(theName, theDescription, typesFrom(theTypeDefaults), legalPackageNames, theUIOrder); - - } - - public TypeMultiProperty(String theName, String theDescription, String theTypeDefaults, - Map otherParams, float theUIOrder) { - this(theName, theDescription, typesFrom(theTypeDefaults), packageNamesIn(otherParams), theUIOrder); - } - - /** - * @param classesStr - * String - * @return Class[] - */ - public static Class[] typesFrom(String classesStr) { - String[] values = StringUtil.substringsOf(classesStr, DELIMITER); - - Class[] classes = new Class[values.length]; - for (int i = 0; i < values.length; i++) { - classes[i] = TypeProperty.classFrom(values[i]); - } - return classes; - } - - /** - * @param item - * Object - * @return String - */ - @Override - protected String packageNameOf(Object item) { - return ((Class) item).getName(); - } - - /** - * @return Class - * @see PropertyDescriptor#type() - */ - @Override - public Class type() { - return Class[].class; - } - - /** - * @return String - */ - @Override - protected String itemTypeName() { - return "type"; - } - - /** - * @param value - * Object - * @return String - */ - @Override - protected String asString(Object value) { - return value == null ? "" : ((Class) value).getName(); - } - - /** - * @param valueString - * String - * @return Object - * @see PropertyDescriptor#valueFrom(String) - */ - @Override - public Class[] valueFrom(String valueString) { - return typesFrom(valueString); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.PropertyDescriptorFactory; +import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory; +import net.sourceforge.pmd.util.StringUtil; + +/** + * Defines a property that supports multiple class types, even for primitive + * values! + * + * TODO - untested for array types + * + * @author Brian Remedios + */ +public class TypeMultiProperty extends AbstractMultiPackagedProperty { + + public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory( + Class[].class, PACKAGED_FIELD_TYPES_BY_KEY) { + + @Override + public TypeMultiProperty createWith(Map valuesById) { + char delimiter = delimiterIn(valuesById); + return new TypeMultiProperty(nameIn(valuesById), descriptionIn(valuesById), defaultValueIn(valuesById), + legalPackageNamesIn(valuesById, delimiter), 0f); + } + }; + + /** + * Constructor for TypeProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param theDefaults + * Class[] + * @param legalPackageNames + * String[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public TypeMultiProperty(String theName, String theDescription, Class[] theDefaults, String[] legalPackageNames, + float theUIOrder) { + super(theName, theDescription, theDefaults, legalPackageNames, theUIOrder); + + } + + /** + * Constructor for TypeProperty. + * + * @param theName + * String + * @param theDescription + * String + * @param theTypeDefaults + * String + * @param legalPackageNames + * String[] + * @param theUIOrder + * float + * @throws IllegalArgumentException + */ + public TypeMultiProperty(String theName, String theDescription, String theTypeDefaults, String[] legalPackageNames, + float theUIOrder) { + this(theName, theDescription, typesFrom(theTypeDefaults), legalPackageNames, theUIOrder); + + } + + public TypeMultiProperty(String theName, String theDescription, String theTypeDefaults, + Map otherParams, float theUIOrder) { + this(theName, theDescription, typesFrom(theTypeDefaults), packageNamesIn(otherParams), theUIOrder); + } + + /** + * @param classesStr + * String + * @return Class[] + */ + public static Class[] typesFrom(String classesStr) { + String[] values = StringUtil.substringsOf(classesStr, DELIMITER); + + Class[] classes = new Class[values.length]; + for (int i = 0; i < values.length; i++) { + classes[i] = TypeProperty.classFrom(values[i]); + } + return classes; + } + + /** + * @param item + * Object + * @return String + */ + @Override + protected String packageNameOf(Object item) { + return ((Class) item).getName(); + } + + /** + * @return Class + * @see PropertyDescriptor#type() + */ + @Override + public Class type() { + return Class[].class; + } + + /** + * @return String + */ + @Override + protected String itemTypeName() { + return "type"; + } + + /** + * @param value + * Object + * @return String + */ + @Override + protected String asString(Object value) { + return value == null ? "" : ((Class) value).getName(); + } + + /** + * @param valueString + * String + * @return Object + * @see PropertyDescriptor#valueFrom(String) + */ + @Override + public Class[] valueFrom(String valueString) { + return typesFrom(valueString); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java index 7eaad0ce74..d86f451bf8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java @@ -1,31 +1,31 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.stat; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.rule.properties.DoubleProperty; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; -import net.sourceforge.pmd.stat.DataPoint; -import net.sourceforge.pmd.stat.Metric; - -/** - * This interface tags a Rule as being a Statistical rule, producing various - * metrics from data points. - * - * @see DataPoint - * @see Metric - * @see StatisticalRuleHelper - */ -public interface StatisticalRule extends Rule { - - DoubleProperty SIGMA_DESCRIPTOR = new DoubleProperty("sigma", "Sigma value", 0d, 100d, null, 1.0f); - DoubleProperty MINIMUM_DESCRIPTOR = new DoubleProperty("minimum", "Minimum reporting threshold", 0d, 100d, null, - 2.0f); - IntegerProperty TOP_SCORE_DESCRIPTOR = new IntegerProperty("topscore", "Top score value", 1, 100, null, 3.0f); - - void addDataPoint(DataPoint point); - - Object[] getViolationParameters(DataPoint point); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.stat; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.DoubleProperty; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; +import net.sourceforge.pmd.stat.DataPoint; +import net.sourceforge.pmd.stat.Metric; + +/** + * This interface tags a Rule as being a Statistical rule, producing various + * metrics from data points. + * + * @see DataPoint + * @see Metric + * @see StatisticalRuleHelper + */ +public interface StatisticalRule extends Rule { + + DoubleProperty SIGMA_DESCRIPTOR = new DoubleProperty("sigma", "Sigma value", 0d, 100d, null, 1.0f); + DoubleProperty MINIMUM_DESCRIPTOR = new DoubleProperty("minimum", "Minimum reporting threshold", 0d, 100d, null, + 2.0f); + IntegerProperty TOP_SCORE_DESCRIPTOR = new IntegerProperty("topscore", "Top score value", 1, 100, null, 3.0f); + + void addDataPoint(DataPoint point); + + Object[] getViolationParameters(DataPoint point); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRuleHelper.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRuleHelper.java index 3df136061e..4f89a3565c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRuleHelper.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRuleHelper.java @@ -1,147 +1,147 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.stat; - -import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.MINIMUM_DESCRIPTOR; -import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.SIGMA_DESCRIPTOR; -import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.TOP_SCORE_DESCRIPTOR; - -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.rule.AbstractRule; -import net.sourceforge.pmd.stat.DataPoint; -import net.sourceforge.pmd.stat.Metric; - -/** - * This class is used to implement the core logic of a StatisticalRule. Concrete - * Rule implementations should delegate to an instance of this class. - * - * @author David Dixon-Peugh Aug 8, 2002 StatisticalRule.java - */ -public class StatisticalRuleHelper { - - public static final double DELTA = 0.000005; // Within this range. . . - - private AbstractRule rule; - - private SortedSet dataPoints = new TreeSet<>(); - - private int count = 0; - private double total = 0.0; - - public StatisticalRuleHelper(AbstractRule rule) { - this.rule = rule; - rule.definePropertyDescriptor(SIGMA_DESCRIPTOR); - rule.definePropertyDescriptor(MINIMUM_DESCRIPTOR); - rule.definePropertyDescriptor(TOP_SCORE_DESCRIPTOR); - } - - public void addDataPoint(DataPoint point) { - count++; - total += point.getScore(); - dataPoints.add(point); - } - - public void apply(RuleContext ctx) { - - double deviation; - double minimum = 0.0; - - if (rule.getProperty(SIGMA_DESCRIPTOR) != null) { // TODO - need to come - // up with a good - // default value - deviation = getStdDev(); - double sigma = rule.getProperty(SIGMA_DESCRIPTOR); - minimum = getMean() + (sigma * deviation); - } - - if (rule.getProperty(MINIMUM_DESCRIPTOR) != null) { // TODO - need to - // come up with a - // good default - // value - double mMin = rule.getProperty(MINIMUM_DESCRIPTOR); - if (mMin > minimum) { - minimum = mMin; - } - } - - SortedSet newPoints = applyMinimumValue(dataPoints, minimum); - - if (rule.getProperty(TOP_SCORE_DESCRIPTOR) != null) { // TODO - need to - // come up with a - // good default - // value - int topScore = rule.getProperty(TOP_SCORE_DESCRIPTOR); - if (newPoints.size() >= topScore) { - newPoints = applyTopScore(newPoints, topScore); - } - } - - makeViolations(ctx, newPoints); - - double low = 0.0d; - double high = 0.0d; - if (!dataPoints.isEmpty()) { - low = dataPoints.first().getScore(); - high = dataPoints.last().getScore(); - } - - ctx.getReport().addMetric(new Metric(rule.getName(), count, total, low, high, getMean(), getStdDev())); - - dataPoints.clear(); - } - - private double getMean() { - return total / count; - } - - private double getStdDev() { - if (dataPoints.size() < 2) { - return Double.NaN; - } - - double mean = getMean(); - double deltaSq = 0.0; - double scoreMinusMean; - - for (DataPoint point : dataPoints) { - scoreMinusMean = point.getScore() - mean; - deltaSq += scoreMinusMean * scoreMinusMean; - } - - return Math.sqrt(deltaSq / (dataPoints.size() - 1)); - } - - private SortedSet applyMinimumValue(SortedSet pointSet, double minValue) { - SortedSet rc = new TreeSet<>(); - double threshold = minValue - DELTA; - - for (DataPoint point : pointSet) { - if (point.getScore() > threshold) { - rc.add(point); - } - } - return rc; - } - - private SortedSet applyTopScore(SortedSet points, int topScore) { - SortedSet s = new TreeSet<>(); - DataPoint[] arr = points.toArray(new DataPoint[] {}); - for (int i = arr.length - 1; i >= (arr.length - topScore); i--) { - s.add(arr[i]); - } - return s; - } - - private void makeViolations(RuleContext ctx, Set p) { - for (DataPoint point : p) { - rule.addViolationWithMessage(ctx, point.getNode(), point.getMessage(), - ((StatisticalRule) rule).getViolationParameters(point)); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.stat; + +import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.MINIMUM_DESCRIPTOR; +import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.SIGMA_DESCRIPTOR; +import static net.sourceforge.pmd.lang.rule.stat.StatisticalRule.TOP_SCORE_DESCRIPTOR; + +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.rule.AbstractRule; +import net.sourceforge.pmd.stat.DataPoint; +import net.sourceforge.pmd.stat.Metric; + +/** + * This class is used to implement the core logic of a StatisticalRule. Concrete + * Rule implementations should delegate to an instance of this class. + * + * @author David Dixon-Peugh Aug 8, 2002 StatisticalRule.java + */ +public class StatisticalRuleHelper { + + public static final double DELTA = 0.000005; // Within this range. . . + + private AbstractRule rule; + + private SortedSet dataPoints = new TreeSet<>(); + + private int count = 0; + private double total = 0.0; + + public StatisticalRuleHelper(AbstractRule rule) { + this.rule = rule; + rule.definePropertyDescriptor(SIGMA_DESCRIPTOR); + rule.definePropertyDescriptor(MINIMUM_DESCRIPTOR); + rule.definePropertyDescriptor(TOP_SCORE_DESCRIPTOR); + } + + public void addDataPoint(DataPoint point) { + count++; + total += point.getScore(); + dataPoints.add(point); + } + + public void apply(RuleContext ctx) { + + double deviation; + double minimum = 0.0; + + if (rule.getProperty(SIGMA_DESCRIPTOR) != null) { // TODO - need to come + // up with a good + // default value + deviation = getStdDev(); + double sigma = rule.getProperty(SIGMA_DESCRIPTOR); + minimum = getMean() + (sigma * deviation); + } + + if (rule.getProperty(MINIMUM_DESCRIPTOR) != null) { // TODO - need to + // come up with a + // good default + // value + double mMin = rule.getProperty(MINIMUM_DESCRIPTOR); + if (mMin > minimum) { + minimum = mMin; + } + } + + SortedSet newPoints = applyMinimumValue(dataPoints, minimum); + + if (rule.getProperty(TOP_SCORE_DESCRIPTOR) != null) { // TODO - need to + // come up with a + // good default + // value + int topScore = rule.getProperty(TOP_SCORE_DESCRIPTOR); + if (newPoints.size() >= topScore) { + newPoints = applyTopScore(newPoints, topScore); + } + } + + makeViolations(ctx, newPoints); + + double low = 0.0d; + double high = 0.0d; + if (!dataPoints.isEmpty()) { + low = dataPoints.first().getScore(); + high = dataPoints.last().getScore(); + } + + ctx.getReport().addMetric(new Metric(rule.getName(), count, total, low, high, getMean(), getStdDev())); + + dataPoints.clear(); + } + + private double getMean() { + return total / count; + } + + private double getStdDev() { + if (dataPoints.size() < 2) { + return Double.NaN; + } + + double mean = getMean(); + double deltaSq = 0.0; + double scoreMinusMean; + + for (DataPoint point : dataPoints) { + scoreMinusMean = point.getScore() - mean; + deltaSq += scoreMinusMean * scoreMinusMean; + } + + return Math.sqrt(deltaSq / (dataPoints.size() - 1)); + } + + private SortedSet applyMinimumValue(SortedSet pointSet, double minValue) { + SortedSet rc = new TreeSet<>(); + double threshold = minValue - DELTA; + + for (DataPoint point : pointSet) { + if (point.getScore() > threshold) { + rc.add(point); + } + } + return rc; + } + + private SortedSet applyTopScore(SortedSet points, int topScore) { + SortedSet s = new TreeSet<>(); + DataPoint[] arr = points.toArray(new DataPoint[] {}); + for (int i = arr.length - 1; i >= (arr.length - topScore); i--) { + s.add(arr[i]); + } + return s; + } + + private void makeViolations(RuleContext ctx, Set p) { + for (DataPoint point : p) { + rule.addViolationWithMessage(ctx, point.getNode(), point.getMessage(), + ((StatisticalRule) rule).getViolationParameters(point)); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java index 27c78bb5b6..05cb8b3c63 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java @@ -1,92 +1,92 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; - -/** - * This implementation of XPathRuleQuery provides support for RuleChain visits. - */ -public abstract class AbstractXPathRuleQuery implements XPathRuleQuery { - - /** - * The XPath query string. - */ - protected String xpath; - - /** - * The XPath version; - */ - protected String version; - - /** - * The properties. - */ - protected Map, Object> properties; - - /** - * Subclasses can manage RuleChain visits via this list. - */ - protected final List ruleChainVisits = new ArrayList<>(); - - /** - * {@inheritDoc} - */ - @Override - public void setXPath(String xpath) { - this.xpath = xpath; - } - - /** - * {@inheritDoc} - */ - @Override - public void setVersion(String version) throws UnsupportedOperationException { - if (!isSupportedVersion(version)) { - throw new UnsupportedOperationException( - this.getClass().getSimpleName() + " does not support XPath version: " + version); - } - this.version = version; - } - - /** - * Subclasses should implement to indicate whether an XPath version is - * supported. - * - * @param version - * The XPath version. - * @return true if the XPath version is supported, - * false otherwise. - */ - protected abstract boolean isSupportedVersion(String version); - - /** - * {@inheritDoc} - */ - @Override - public void setProperties(Map, Object> properties) { - this.properties = properties; - } - - /** - * {@inheritDoc} - */ - @Override - public List getRuleChainVisits() { - return ruleChainVisits; - } - - /** - * {@inheritDoc} - */ - @Override - public abstract List evaluate(Node node, RuleContext data); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; + +/** + * This implementation of XPathRuleQuery provides support for RuleChain visits. + */ +public abstract class AbstractXPathRuleQuery implements XPathRuleQuery { + + /** + * The XPath query string. + */ + protected String xpath; + + /** + * The XPath version; + */ + protected String version; + + /** + * The properties. + */ + protected Map, Object> properties; + + /** + * Subclasses can manage RuleChain visits via this list. + */ + protected final List ruleChainVisits = new ArrayList<>(); + + /** + * {@inheritDoc} + */ + @Override + public void setXPath(String xpath) { + this.xpath = xpath; + } + + /** + * {@inheritDoc} + */ + @Override + public void setVersion(String version) throws UnsupportedOperationException { + if (!isSupportedVersion(version)) { + throw new UnsupportedOperationException( + this.getClass().getSimpleName() + " does not support XPath version: " + version); + } + this.version = version; + } + + /** + * Subclasses should implement to indicate whether an XPath version is + * supported. + * + * @param version + * The XPath version. + * @return true if the XPath version is supported, + * false otherwise. + */ + protected abstract boolean isSupportedVersion(String version); + + /** + * {@inheritDoc} + */ + @Override + public void setProperties(Map, Object> properties) { + this.properties = properties; + } + + /** + * {@inheritDoc} + */ + @Override + public List getRuleChainVisits() { + return ruleChainVisits; + } + + /** + * {@inheritDoc} + */ + @Override + public abstract List evaluate(Node node, RuleContext data); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java index 546a613ef5..802055a1d1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java @@ -1,244 +1,244 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.jaxen.BaseXPath; -import org.jaxen.JaxenException; -import org.jaxen.Navigator; -import org.jaxen.SimpleVariableContext; -import org.jaxen.XPath; -import org.jaxen.expr.AllNodeStep; -import org.jaxen.expr.DefaultXPathFactory; -import org.jaxen.expr.Expr; -import org.jaxen.expr.LocationPath; -import org.jaxen.expr.NameStep; -import org.jaxen.expr.Predicate; -import org.jaxen.expr.Step; -import org.jaxen.expr.UnionExpr; -import org.jaxen.expr.XPathFactory; -import org.jaxen.saxpath.Axis; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; - -/** - * This is a Jaxen based XPathRule query. - */ -public class JaxenXPathRuleQuery extends AbstractXPathRuleQuery { - - private static final Logger LOG = Logger.getLogger(JaxenXPathRuleQuery.class.getName()); - - private enum InitializationStatus { - NONE, PARTIAL, FULL - } - - // Mapping from Node name to applicable XPath queries - private InitializationStatus initializationStatus = InitializationStatus.NONE; - private Map> nodeNameToXPaths; - - private static final String AST_ROOT = "_AST_ROOT_"; - - /** - * {@inheritDoc} - */ - @Override - public boolean isSupportedVersion(String version) { - return XPATH_1_0.equals(version); - } - - /** - * {@inheritDoc} - */ - @Override - @SuppressWarnings("unchecked") - public List evaluate(Node node, RuleContext data) { - List results = new ArrayList<>(); - try { - initializeXPathExpression( - data.getLanguageVersion().getLanguageVersionHandler().getXPathHandler().getNavigator()); - List xpaths = nodeNameToXPaths.get(node.toString()); - if (xpaths == null) { - xpaths = nodeNameToXPaths.get(AST_ROOT); - } - for (XPath xpath : xpaths) { - List nodes = xpath.selectNodes(node); - results.addAll(nodes); - } - } catch (JaxenException ex) { - throw new RuntimeException(ex); - } - return results; - } - - /** - * {@inheritDoc} - */ - @Override - public List getRuleChainVisits() { - try { - // No Navigator available in this context - initializeXPathExpression(null); - return super.getRuleChainVisits(); - } catch (JaxenException ex) { - throw new RuntimeException(ex); - } - } - - @SuppressWarnings("unchecked") - private void initializeXPathExpression(Navigator navigator) throws JaxenException { - if (initializationStatus == InitializationStatus.FULL) { - return; - } else if (initializationStatus == InitializationStatus.PARTIAL && navigator == null) { - if (LOG.isLoggable(Level.SEVERE)) { - LOG.severe("XPathRule is not initialized because no navigator was provided. " - + "Please make sure to implement getXPathHandler in the handler of the language. " - + "See also AbstractLanguageVersionHandler."); - } - return; - } - - // - // Attempt to use the RuleChain with this XPath query. To do so, the - // queries - // should generally look like //TypeA or //TypeA | //TypeB. We will look - // at the - // parsed XPath AST using the Jaxen APIs to make this determination. - // If the query is not exactly what we are looking for, do not use the - // RuleChain. - // - nodeNameToXPaths = new HashMap<>(); - - BaseXPath originalXPath = createXPath(xpath, navigator); - indexXPath(originalXPath, AST_ROOT); - - boolean useRuleChain = true; - Deque pending = new ArrayDeque<>(); - pending.push(originalXPath.getRootExpr()); - while (!pending.isEmpty()) { - Expr node = pending.pop(); - - // Need to prove we can handle this part of the query - boolean valid = false; - - // Must be a LocationPath... that is something like //Type - if (node instanceof LocationPath) { - LocationPath locationPath = (LocationPath) node; - if (locationPath.isAbsolute()) { - // Should be at least two steps - List steps = locationPath.getSteps(); - if (steps.size() >= 2) { - Step step1 = steps.get(0); - Step step2 = steps.get(1); - // First step should be an AllNodeStep using the - // descendant or self axis - if (step1 instanceof AllNodeStep - && ((AllNodeStep) step1).getAxis() == Axis.DESCENDANT_OR_SELF) { - // Second step should be a NameStep using the child - // axis. - if (step2 instanceof NameStep && ((NameStep) step2).getAxis() == Axis.CHILD) { - // Construct a new expression that is - // appropriate for RuleChain use - XPathFactory xpathFactory = new DefaultXPathFactory(); - - // Instead of an absolute location path, we'll - // be using a relative path - LocationPath relativeLocationPath = xpathFactory.createRelativeLocationPath(); - // The first step will be along the self axis - Step allNodeStep = xpathFactory.createAllNodeStep(Axis.SELF); - // Retain all predicates from the original name - // step - for (Iterator i = step2.getPredicates().iterator(); i.hasNext();) { - allNodeStep.addPredicate(i.next()); - } - relativeLocationPath.addStep(allNodeStep); - - // Retain the remaining steps from the original - // location path - for (int i = 2; i < steps.size(); i++) { - relativeLocationPath.addStep(steps.get(i)); - } - - BaseXPath xpath = createXPath(relativeLocationPath.getText(), navigator); - indexXPath(xpath, ((NameStep) step2).getLocalName()); - valid = true; - } - } - } - } - } else if (node instanceof UnionExpr) { // Or a UnionExpr, that is - // something like //TypeA | - // //TypeB - UnionExpr unionExpr = (UnionExpr) node; - pending.push(unionExpr.getLHS()); - pending.push(unionExpr.getRHS()); - valid = true; - } - if (!valid) { - useRuleChain = false; - break; - } - } - - if (useRuleChain) { - // Use the RuleChain for all the nodes extracted from the xpath - // queries - super.ruleChainVisits.addAll(nodeNameToXPaths.keySet()); - } else { - // Use original XPath if we cannot use the RuleChain - nodeNameToXPaths.clear(); - indexXPath(originalXPath, AST_ROOT); - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Unable to use RuleChain for for XPath: " + xpath); - } - } - - if (navigator == null) { - this.initializationStatus = InitializationStatus.PARTIAL; - // Clear the node data, because we did not have a Navigator - nodeNameToXPaths = null; - } else { - this.initializationStatus = InitializationStatus.FULL; - } - - } - - private void indexXPath(XPath xpath, String nodeName) { - List xpaths = nodeNameToXPaths.get(nodeName); - if (xpaths == null) { - xpaths = new ArrayList<>(); - nodeNameToXPaths.put(nodeName, xpaths); - } - xpaths.add(xpath); - } - - private BaseXPath createXPath(String xpathQueryString, Navigator navigator) throws JaxenException { - - BaseXPath xpath = new BaseXPath(xpathQueryString, navigator); - if (properties.size() > 1) { - SimpleVariableContext vc = new SimpleVariableContext(); - for (Entry, Object> e : properties.entrySet()) { - String propName = e.getKey().name(); - if (!"xpath".equals(propName)) { - Object value = e.getValue(); - vc.setVariableValue(propName, value != null ? value.toString() : null); - } - } - xpath.setVariableContext(vc); - } - return xpath; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jaxen.BaseXPath; +import org.jaxen.JaxenException; +import org.jaxen.Navigator; +import org.jaxen.SimpleVariableContext; +import org.jaxen.XPath; +import org.jaxen.expr.AllNodeStep; +import org.jaxen.expr.DefaultXPathFactory; +import org.jaxen.expr.Expr; +import org.jaxen.expr.LocationPath; +import org.jaxen.expr.NameStep; +import org.jaxen.expr.Predicate; +import org.jaxen.expr.Step; +import org.jaxen.expr.UnionExpr; +import org.jaxen.expr.XPathFactory; +import org.jaxen.saxpath.Axis; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; + +/** + * This is a Jaxen based XPathRule query. + */ +public class JaxenXPathRuleQuery extends AbstractXPathRuleQuery { + + private static final Logger LOG = Logger.getLogger(JaxenXPathRuleQuery.class.getName()); + + private enum InitializationStatus { + NONE, PARTIAL, FULL + } + + // Mapping from Node name to applicable XPath queries + private InitializationStatus initializationStatus = InitializationStatus.NONE; + private Map> nodeNameToXPaths; + + private static final String AST_ROOT = "_AST_ROOT_"; + + /** + * {@inheritDoc} + */ + @Override + public boolean isSupportedVersion(String version) { + return XPATH_1_0.equals(version); + } + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public List evaluate(Node node, RuleContext data) { + List results = new ArrayList<>(); + try { + initializeXPathExpression( + data.getLanguageVersion().getLanguageVersionHandler().getXPathHandler().getNavigator()); + List xpaths = nodeNameToXPaths.get(node.toString()); + if (xpaths == null) { + xpaths = nodeNameToXPaths.get(AST_ROOT); + } + for (XPath xpath : xpaths) { + List nodes = xpath.selectNodes(node); + results.addAll(nodes); + } + } catch (JaxenException ex) { + throw new RuntimeException(ex); + } + return results; + } + + /** + * {@inheritDoc} + */ + @Override + public List getRuleChainVisits() { + try { + // No Navigator available in this context + initializeXPathExpression(null); + return super.getRuleChainVisits(); + } catch (JaxenException ex) { + throw new RuntimeException(ex); + } + } + + @SuppressWarnings("unchecked") + private void initializeXPathExpression(Navigator navigator) throws JaxenException { + if (initializationStatus == InitializationStatus.FULL) { + return; + } else if (initializationStatus == InitializationStatus.PARTIAL && navigator == null) { + if (LOG.isLoggable(Level.SEVERE)) { + LOG.severe("XPathRule is not initialized because no navigator was provided. " + + "Please make sure to implement getXPathHandler in the handler of the language. " + + "See also AbstractLanguageVersionHandler."); + } + return; + } + + // + // Attempt to use the RuleChain with this XPath query. To do so, the + // queries + // should generally look like //TypeA or //TypeA | //TypeB. We will look + // at the + // parsed XPath AST using the Jaxen APIs to make this determination. + // If the query is not exactly what we are looking for, do not use the + // RuleChain. + // + nodeNameToXPaths = new HashMap<>(); + + BaseXPath originalXPath = createXPath(xpath, navigator); + indexXPath(originalXPath, AST_ROOT); + + boolean useRuleChain = true; + Deque pending = new ArrayDeque<>(); + pending.push(originalXPath.getRootExpr()); + while (!pending.isEmpty()) { + Expr node = pending.pop(); + + // Need to prove we can handle this part of the query + boolean valid = false; + + // Must be a LocationPath... that is something like //Type + if (node instanceof LocationPath) { + LocationPath locationPath = (LocationPath) node; + if (locationPath.isAbsolute()) { + // Should be at least two steps + List steps = locationPath.getSteps(); + if (steps.size() >= 2) { + Step step1 = steps.get(0); + Step step2 = steps.get(1); + // First step should be an AllNodeStep using the + // descendant or self axis + if (step1 instanceof AllNodeStep + && ((AllNodeStep) step1).getAxis() == Axis.DESCENDANT_OR_SELF) { + // Second step should be a NameStep using the child + // axis. + if (step2 instanceof NameStep && ((NameStep) step2).getAxis() == Axis.CHILD) { + // Construct a new expression that is + // appropriate for RuleChain use + XPathFactory xpathFactory = new DefaultXPathFactory(); + + // Instead of an absolute location path, we'll + // be using a relative path + LocationPath relativeLocationPath = xpathFactory.createRelativeLocationPath(); + // The first step will be along the self axis + Step allNodeStep = xpathFactory.createAllNodeStep(Axis.SELF); + // Retain all predicates from the original name + // step + for (Iterator i = step2.getPredicates().iterator(); i.hasNext();) { + allNodeStep.addPredicate(i.next()); + } + relativeLocationPath.addStep(allNodeStep); + + // Retain the remaining steps from the original + // location path + for (int i = 2; i < steps.size(); i++) { + relativeLocationPath.addStep(steps.get(i)); + } + + BaseXPath xpath = createXPath(relativeLocationPath.getText(), navigator); + indexXPath(xpath, ((NameStep) step2).getLocalName()); + valid = true; + } + } + } + } + } else if (node instanceof UnionExpr) { // Or a UnionExpr, that is + // something like //TypeA | + // //TypeB + UnionExpr unionExpr = (UnionExpr) node; + pending.push(unionExpr.getLHS()); + pending.push(unionExpr.getRHS()); + valid = true; + } + if (!valid) { + useRuleChain = false; + break; + } + } + + if (useRuleChain) { + // Use the RuleChain for all the nodes extracted from the xpath + // queries + super.ruleChainVisits.addAll(nodeNameToXPaths.keySet()); + } else { + // Use original XPath if we cannot use the RuleChain + nodeNameToXPaths.clear(); + indexXPath(originalXPath, AST_ROOT); + if (LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Unable to use RuleChain for for XPath: " + xpath); + } + } + + if (navigator == null) { + this.initializationStatus = InitializationStatus.PARTIAL; + // Clear the node data, because we did not have a Navigator + nodeNameToXPaths = null; + } else { + this.initializationStatus = InitializationStatus.FULL; + } + + } + + private void indexXPath(XPath xpath, String nodeName) { + List xpaths = nodeNameToXPaths.get(nodeName); + if (xpaths == null) { + xpaths = new ArrayList<>(); + nodeNameToXPaths.put(nodeName, xpaths); + } + xpaths.add(xpath); + } + + private BaseXPath createXPath(String xpathQueryString, Navigator navigator) throws JaxenException { + + BaseXPath xpath = new BaseXPath(xpathQueryString, navigator); + if (properties.size() > 1) { + SimpleVariableContext vc = new SimpleVariableContext(); + for (Entry, Object> e : properties.entrySet()) { + String propName = e.getKey().name(); + if (!"xpath".equals(propName)) { + Object value = e.getValue(); + vc.setVariableValue(propName, value != null ? value.toString() : null); + } + } + xpath.setVariableContext(vc); + } + return xpath; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java index 54a1b173f0..7eb6deae8f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java @@ -1,186 +1,186 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.saxon.DocumentNode; -import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; -import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; -import net.sourceforge.pmd.lang.rule.properties.StringProperty; -import net.sourceforge.pmd.lang.xpath.Initializer; - -import net.sf.saxon.om.ValueRepresentation; -import net.sf.saxon.sxpath.AbstractStaticContext; -import net.sf.saxon.sxpath.IndependentContext; -import net.sf.saxon.sxpath.XPathDynamicContext; -import net.sf.saxon.sxpath.XPathEvaluator; -import net.sf.saxon.sxpath.XPathExpression; -import net.sf.saxon.sxpath.XPathStaticContext; -import net.sf.saxon.sxpath.XPathVariable; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.value.BooleanValue; -import net.sf.saxon.value.Int64Value; -import net.sf.saxon.value.StringValue; - -/** - * This is a Saxon based XPathRule query. - */ -public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery { - - // Mapping from Node name to applicable XPath queries - private XPathExpression xpathExpression; - private List xpathVariables; - - private static final int MAX_CACHE_SIZE = 20; - private static final Map CACHE = new LinkedHashMap(MAX_CACHE_SIZE) { - private static final long serialVersionUID = -7653916493967142443L; - - protected boolean removeEldestEntry(final Map.Entry eldest) { - return size() > MAX_CACHE_SIZE; - } - }; - - /** - * {@inheritDoc} - */ - @Override - public boolean isSupportedVersion(String version) { - return XPATH_1_0_COMPATIBILITY.equals(version) || XPATH_2_0.equals(version); - } - - /** - * {@inheritDoc} - */ - @Override - @SuppressWarnings("unchecked") - public List evaluate(Node node, RuleContext data) { - initializeXPathExpression(); - - List results = new ArrayList<>(); - try { - // Get the DocumentNode for the AST - DocumentNode documentNode = getDocumentNode(node); - - // Get the corresponding ElementNode for this node. - ElementNode rootElementNode = documentNode.nodeToElementNode.get(node); - - // Create a dynamic context for this node - XPathDynamicContext xpathDynamicContext = xpathExpression.createDynamicContext(rootElementNode); - - // Set variable values on the dynamic context - for (XPathVariable xpathVariable : xpathVariables) { - String name = xpathVariable.getVariableQName().getLocalName(); - for (Map.Entry, Object> entry : super.properties.entrySet()) { - if (name.equals(entry.getKey().name())) { - PropertyDescriptor propertyDescriptor = entry.getKey(); - if (propertyDescriptor instanceof PropertyDescriptorWrapper) { - propertyDescriptor = ((PropertyDescriptorWrapper) propertyDescriptor) - .getPropertyDescriptor(); - } - Object value = entry.getValue(); - ValueRepresentation valueRepresentation; - - // TODO Need to handle null values? - // TODO Need to handle more PropertyDescriptors, is - // there an easy factory in Saxon we can use for this? - if (propertyDescriptor instanceof StringProperty) { - valueRepresentation = new StringValue((String) value); - } else if (propertyDescriptor instanceof BooleanProperty) { - valueRepresentation = BooleanValue.get(((Boolean) value).booleanValue()); - } else if (propertyDescriptor instanceof IntegerProperty) { - valueRepresentation = Int64Value.makeIntegerValue((Integer) value); - } else if (propertyDescriptor instanceof EnumeratedProperty) { - if (value instanceof String) { - valueRepresentation = new StringValue((String) value); - } else { - throw new RuntimeException( - "Unable to create ValueRepresentaton for non-String EnumeratedProperty value: " - + value); - } - } else { - throw new RuntimeException("Unable to create ValueRepresentaton for PropertyDescriptor: " - + propertyDescriptor); - } - xpathDynamicContext.setVariable(xpathVariable, valueRepresentation); - } - } - } - - List nodes = xpathExpression.evaluate(xpathDynamicContext); - for (ElementNode elementNode : nodes) { - results.add((Node) elementNode.getUnderlyingNode()); - } - } catch (XPathException e) { - throw new RuntimeException(super.xpath + " had problem: " + e.getMessage(), e); - } - return results; - } - - private DocumentNode getDocumentNode(Node node) { - // Get the root AST node - Node root = node; - while (root.jjtGetParent() != null) { - root = root.jjtGetParent(); - } - - // Cache DocumentNode trees, so that different XPath queries can re-use them. - DocumentNode documentNode; - synchronized (CACHE) { - documentNode = CACHE.get(root); - if (documentNode == null) { - documentNode = new DocumentNode(root); - CACHE.put(root, documentNode); - } - } - return documentNode; - } - - private void initializeXPathExpression() { - if (xpathExpression != null) { - return; - } - try { - XPathEvaluator xpathEvaluator = new XPathEvaluator(); - XPathStaticContext xpathStaticContext = xpathEvaluator.getStaticContext(); - - // Enable XPath 1.0 compatibility - if (XPATH_1_0_COMPATIBILITY.equals(version)) { - ((AbstractStaticContext) xpathStaticContext).setBackwardsCompatibilityMode(true); - } - - // Register PMD functions - Initializer.initialize((IndependentContext) xpathStaticContext); - - // Create XPathVariables for later use. It is a Saxon quirk that - // XPathVariables must be defined on the static context, and - // reused later to associate an actual value on the dynamic context. - xpathVariables = new ArrayList<>(); - for (PropertyDescriptor propertyDescriptor : super.properties.keySet()) { - String name = propertyDescriptor.name(); - if (!"xpath".equals(name)) { - XPathVariable xpathVariable = xpathStaticContext.declareVariable(null, name); - xpathVariables.add(xpathVariable); - } - } - - // TODO Come up with a way to make use of RuleChain. I had hacked up - // an approach which used Jaxen's stuff, but that only works for - // 1.0 compatibility mode. Rather do it right instead of kludging. - xpathExpression = xpathEvaluator.createExpression(super.xpath); - } catch (XPathException e) { - throw new RuntimeException(e); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.saxon.DocumentNode; +import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; +import net.sourceforge.pmd.lang.rule.properties.StringProperty; +import net.sourceforge.pmd.lang.xpath.Initializer; + +import net.sf.saxon.om.ValueRepresentation; +import net.sf.saxon.sxpath.AbstractStaticContext; +import net.sf.saxon.sxpath.IndependentContext; +import net.sf.saxon.sxpath.XPathDynamicContext; +import net.sf.saxon.sxpath.XPathEvaluator; +import net.sf.saxon.sxpath.XPathExpression; +import net.sf.saxon.sxpath.XPathStaticContext; +import net.sf.saxon.sxpath.XPathVariable; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.BooleanValue; +import net.sf.saxon.value.Int64Value; +import net.sf.saxon.value.StringValue; + +/** + * This is a Saxon based XPathRule query. + */ +public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery { + + // Mapping from Node name to applicable XPath queries + private XPathExpression xpathExpression; + private List xpathVariables; + + private static final int MAX_CACHE_SIZE = 20; + private static final Map CACHE = new LinkedHashMap(MAX_CACHE_SIZE) { + private static final long serialVersionUID = -7653916493967142443L; + + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > MAX_CACHE_SIZE; + } + }; + + /** + * {@inheritDoc} + */ + @Override + public boolean isSupportedVersion(String version) { + return XPATH_1_0_COMPATIBILITY.equals(version) || XPATH_2_0.equals(version); + } + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public List evaluate(Node node, RuleContext data) { + initializeXPathExpression(); + + List results = new ArrayList<>(); + try { + // Get the DocumentNode for the AST + DocumentNode documentNode = getDocumentNode(node); + + // Get the corresponding ElementNode for this node. + ElementNode rootElementNode = documentNode.nodeToElementNode.get(node); + + // Create a dynamic context for this node + XPathDynamicContext xpathDynamicContext = xpathExpression.createDynamicContext(rootElementNode); + + // Set variable values on the dynamic context + for (XPathVariable xpathVariable : xpathVariables) { + String name = xpathVariable.getVariableQName().getLocalName(); + for (Map.Entry, Object> entry : super.properties.entrySet()) { + if (name.equals(entry.getKey().name())) { + PropertyDescriptor propertyDescriptor = entry.getKey(); + if (propertyDescriptor instanceof PropertyDescriptorWrapper) { + propertyDescriptor = ((PropertyDescriptorWrapper) propertyDescriptor) + .getPropertyDescriptor(); + } + Object value = entry.getValue(); + ValueRepresentation valueRepresentation; + + // TODO Need to handle null values? + // TODO Need to handle more PropertyDescriptors, is + // there an easy factory in Saxon we can use for this? + if (propertyDescriptor instanceof StringProperty) { + valueRepresentation = new StringValue((String) value); + } else if (propertyDescriptor instanceof BooleanProperty) { + valueRepresentation = BooleanValue.get(((Boolean) value).booleanValue()); + } else if (propertyDescriptor instanceof IntegerProperty) { + valueRepresentation = Int64Value.makeIntegerValue((Integer) value); + } else if (propertyDescriptor instanceof EnumeratedProperty) { + if (value instanceof String) { + valueRepresentation = new StringValue((String) value); + } else { + throw new RuntimeException( + "Unable to create ValueRepresentaton for non-String EnumeratedProperty value: " + + value); + } + } else { + throw new RuntimeException("Unable to create ValueRepresentaton for PropertyDescriptor: " + + propertyDescriptor); + } + xpathDynamicContext.setVariable(xpathVariable, valueRepresentation); + } + } + } + + List nodes = xpathExpression.evaluate(xpathDynamicContext); + for (ElementNode elementNode : nodes) { + results.add((Node) elementNode.getUnderlyingNode()); + } + } catch (XPathException e) { + throw new RuntimeException(super.xpath + " had problem: " + e.getMessage(), e); + } + return results; + } + + private DocumentNode getDocumentNode(Node node) { + // Get the root AST node + Node root = node; + while (root.jjtGetParent() != null) { + root = root.jjtGetParent(); + } + + // Cache DocumentNode trees, so that different XPath queries can re-use them. + DocumentNode documentNode; + synchronized (CACHE) { + documentNode = CACHE.get(root); + if (documentNode == null) { + documentNode = new DocumentNode(root); + CACHE.put(root, documentNode); + } + } + return documentNode; + } + + private void initializeXPathExpression() { + if (xpathExpression != null) { + return; + } + try { + XPathEvaluator xpathEvaluator = new XPathEvaluator(); + XPathStaticContext xpathStaticContext = xpathEvaluator.getStaticContext(); + + // Enable XPath 1.0 compatibility + if (XPATH_1_0_COMPATIBILITY.equals(version)) { + ((AbstractStaticContext) xpathStaticContext).setBackwardsCompatibilityMode(true); + } + + // Register PMD functions + Initializer.initialize((IndependentContext) xpathStaticContext); + + // Create XPathVariables for later use. It is a Saxon quirk that + // XPathVariables must be defined on the static context, and + // reused later to associate an actual value on the dynamic context. + xpathVariables = new ArrayList<>(); + for (PropertyDescriptor propertyDescriptor : super.properties.keySet()) { + String name = propertyDescriptor.name(); + if (!"xpath".equals(name)) { + XPathVariable xpathVariable = xpathStaticContext.declareVariable(null, name); + xpathVariables.add(xpathVariable); + } + } + + // TODO Come up with a way to make use of RuleChain. I had hacked up + // an approach which used Jaxen's stuff, but that only works for + // 1.0 compatibility mode. Rather do it right instead of kludging. + xpathExpression = xpathEvaluator.createExpression(super.xpath); + } catch (XPathException e) { + throw new RuntimeException(e); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java index c665d3764b..1c8a87463a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java @@ -1,82 +1,82 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; - -/** - * This interface captures the logic needed by XPathRule to implement an XPath - * based query on an AST Node. - *

- * Implementations of this class do not need to be thread-safe, but they will be - * reused to query against different AST Nodes. Therefore, internal state should - * be maintained in a fashion consistent with reuse. Further, implementations - * are recommended to manage internal state that is invariant over AST Nodes in - * a fashion which facilities high performance (e.g. caching). - */ -public interface XPathRuleQuery { - - /** - * XPath 1.0 version. - */ - String XPATH_1_0 = "1.0"; - - /** - * XPath 1.0 compatibility version. - */ - String XPATH_1_0_COMPATIBILITY = "1.0 compatibility"; - - /** - * XPath 2.0 version. - */ - String XPATH_2_0 = "2.0"; - - /** - * Set the XPath query string to be used. - * - * @param xpath - * The XPath query string. - */ - void setXPath(String xpath); - - /** - * Set the XPath version to be used. - * - * @param version - * The XPath version. - * @throws UnsupportedOperationException - * if the version cannot be handled. - */ - void setVersion(String version) throws UnsupportedOperationException; - - /** - * Set the properties to use during the XPath query. - */ - void setProperties(Map, Object> properties); - - /** - * Indicates which AST Nodes (if any) should be used with the RuleChain. Use - * of the RuleChain will allow the query execute on a targed sub-tree of the - * AST, instead of the entire AST from the root. This can result in great - * performance benefits. - */ - List getRuleChainVisits(); - - /** - * Evaluate the XPath query against the given Node. - * - * @param node - * The Node. - * @param data - * The RuleContext. - * @return The matching Nodes. - */ - List evaluate(Node node, RuleContext data); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; + +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; + +/** + * This interface captures the logic needed by XPathRule to implement an XPath + * based query on an AST Node. + *

+ * Implementations of this class do not need to be thread-safe, but they will be + * reused to query against different AST Nodes. Therefore, internal state should + * be maintained in a fashion consistent with reuse. Further, implementations + * are recommended to manage internal state that is invariant over AST Nodes in + * a fashion which facilities high performance (e.g. caching). + */ +public interface XPathRuleQuery { + + /** + * XPath 1.0 version. + */ + String XPATH_1_0 = "1.0"; + + /** + * XPath 1.0 compatibility version. + */ + String XPATH_1_0_COMPATIBILITY = "1.0 compatibility"; + + /** + * XPath 2.0 version. + */ + String XPATH_2_0 = "2.0"; + + /** + * Set the XPath query string to be used. + * + * @param xpath + * The XPath query string. + */ + void setXPath(String xpath); + + /** + * Set the XPath version to be used. + * + * @param version + * The XPath version. + * @throws UnsupportedOperationException + * if the version cannot be handled. + */ + void setVersion(String version) throws UnsupportedOperationException; + + /** + * Set the properties to use during the XPath query. + */ + void setProperties(Map, Object> properties); + + /** + * Indicates which AST Nodes (if any) should be used with the RuleChain. Use + * of the RuleChain will allow the query execute on a targed sub-tree of the + * AST, instead of the entire AST from the root. This can result in great + * performance benefits. + */ + List getRuleChainVisits(); + + /** + * Evaluate the XPath query against the given Node. + * + * @param node + * The Node. + * @param data + * The RuleContext. + * @return The matching Nodes. + */ + List evaluate(Node node, RuleContext data); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java index 365de39f68..bb69fd43f8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java @@ -1,65 +1,65 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.xpath; - -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.LanguageVersionHandler; - -import net.sf.saxon.sxpath.IndependentContext; - -/** - * This class serves as the means to perform XPath related static - * initialization. For example, initializing custom Jaxen Functions. - * Initialization should be performed before any XPath related operations are - * performed. - */ -public class Initializer { - - private Initializer() { } - - /** - * Perform all initialization. - */ - public static void initialize() { - // noop as initialization is done in static block below - } - - /** - * Perform all initialization. - */ - public static void initialize(IndependentContext context) { - context.declareNamespace("pmd", "java:" + PMDFunctions.class.getName()); - for (Language language : LanguageRegistry.getLanguages()) { - for (LanguageVersion languageVersion : language.getVersions()) { - LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); - if (languageVersionHandler != null) { - languageVersionHandler.getXPathHandler().initialize(context); - } - } - } - } - - static { - initializeGlobal(); - initializeLanguages(); - } - - private static void initializeGlobal() { - MatchesFunction.registerSelfInSimpleContext(); - } - - private static void initializeLanguages() { - for (Language language : LanguageRegistry.getLanguages()) { - for (LanguageVersion languageVersion : language.getVersions()) { - LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); - if (languageVersionHandler != null) { - languageVersionHandler.getXPathHandler().initialize(); - } - } - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.xpath; + +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.LanguageVersionHandler; + +import net.sf.saxon.sxpath.IndependentContext; + +/** + * This class serves as the means to perform XPath related static + * initialization. For example, initializing custom Jaxen Functions. + * Initialization should be performed before any XPath related operations are + * performed. + */ +public class Initializer { + + private Initializer() { } + + /** + * Perform all initialization. + */ + public static void initialize() { + // noop as initialization is done in static block below + } + + /** + * Perform all initialization. + */ + public static void initialize(IndependentContext context) { + context.declareNamespace("pmd", "java:" + PMDFunctions.class.getName()); + for (Language language : LanguageRegistry.getLanguages()) { + for (LanguageVersion languageVersion : language.getVersions()) { + LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); + if (languageVersionHandler != null) { + languageVersionHandler.getXPathHandler().initialize(context); + } + } + } + } + + static { + initializeGlobal(); + initializeLanguages(); + } + + private static void initializeGlobal() { + MatchesFunction.registerSelfInSimpleContext(); + } + + private static void initializeLanguages() { + for (Language language : LanguageRegistry.getLanguages()) { + for (LanguageVersion languageVersion : language.getVersions()) { + LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); + if (languageVersionHandler != null) { + languageVersionHandler.getXPathHandler().initialize(); + } + } + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java index e2fdb3dbd8..2619c3e1e5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java @@ -1,35 +1,35 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.xpath; - -public class PMDFunctions { - private PMDFunctions() { } - - public static boolean matches(String s, String pattern1) { - return MatchesFunction.matches(s, pattern1); - } - - public static boolean matches(String s, String pattern1, String pattern2) { - return MatchesFunction.matches(s, pattern1, pattern2); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4, - String pattern5) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4, pattern5); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4, - String pattern5, String pattern6) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4, pattern5, pattern6); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.xpath; + +public class PMDFunctions { + private PMDFunctions() { } + + public static boolean matches(String s, String pattern1) { + return MatchesFunction.matches(s, pattern1); + } + + public static boolean matches(String s, String pattern1, String pattern2) { + return MatchesFunction.matches(s, pattern1, pattern2); + } + + public static boolean matches(String s, String pattern1, String pattern2, String pattern3) { + return MatchesFunction.matches(s, pattern1, pattern2, pattern3); + } + + public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4) { + return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4); + } + + public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4, + String pattern5) { + return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4, pattern5); + } + + public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4, + String pattern5, String pattern6) { + return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4, pattern5, pattern6); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractAccumulatingRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractAccumulatingRenderer.java index 71072b7390..b12e0803b4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractAccumulatingRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractAccumulatingRenderer.java @@ -1,65 +1,65 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.renderers; - -import java.io.IOException; - -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.util.datasource.DataSource; - -/** - * Abstract base class for {@link Renderer} implementations which only produce - * output once all source files are processed. Such {@link Renderer}s use - * working memory proportional to the number of violations found, which can be - * quite large in some scenarios. Consider using - * {@link AbstractIncrementingRenderer} which can use significantly less memory. - * - * Subclasses should implement the {@link #end()} method to output the - * {@link #report}. - * - * @see AbstractIncrementingRenderer - */ -public abstract class AbstractAccumulatingRenderer extends AbstractRenderer { - - /** - * The accumulated Report. - */ - protected Report report; - - public AbstractAccumulatingRenderer(String name, String description) { - super(name, description); - } - - /** - * {@inheritDoc} - */ - @Override - public void start() throws IOException { - report = new Report(); - } - - /** - * {@inheritDoc} - */ - @Override - public void startFileAnalysis(DataSource dataSource) { - } - - /** - * {@inheritDoc} - */ - @Override - public void renderFileReport(Report report) throws IOException { - this.report.merge(report); - } - - /** - * Subclasses should output the {@link #report}. - * - * {@inheritDoc} - */ - @Override - public abstract void end() throws IOException; -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.renderers; + +import java.io.IOException; + +import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.util.datasource.DataSource; + +/** + * Abstract base class for {@link Renderer} implementations which only produce + * output once all source files are processed. Such {@link Renderer}s use + * working memory proportional to the number of violations found, which can be + * quite large in some scenarios. Consider using + * {@link AbstractIncrementingRenderer} which can use significantly less memory. + * + * Subclasses should implement the {@link #end()} method to output the + * {@link #report}. + * + * @see AbstractIncrementingRenderer + */ +public abstract class AbstractAccumulatingRenderer extends AbstractRenderer { + + /** + * The accumulated Report. + */ + protected Report report; + + public AbstractAccumulatingRenderer(String name, String description) { + super(name, description); + } + + /** + * {@inheritDoc} + */ + @Override + public void start() throws IOException { + report = new Report(); + } + + /** + * {@inheritDoc} + */ + @Override + public void startFileAnalysis(DataSource dataSource) { + } + + /** + * {@inheritDoc} + */ + @Override + public void renderFileReport(Report report) throws IOException { + this.report.merge(report); + } + + /** + * Subclasses should output the {@link #report}. + * + * {@inheritDoc} + */ + @Override + public abstract void end() throws IOException; +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java index 1e528ebbf2..2aa064a321 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java @@ -1,152 +1,152 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.renderers; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.util.Collections; -import java.util.Map; -import java.util.Properties; -import java.util.TreeMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -import net.sourceforge.pmd.PropertyDescriptor; - -/** - * This class handles the creation of Renderers. - * - * @see Renderer - */ -public class RendererFactory { - - private static final Logger LOG = Logger.getLogger(RendererFactory.class.getName()); - - public static final Map> REPORT_FORMAT_TO_RENDERER; - - static { - Map> map = new TreeMap<>(); - map.put(CodeClimateRenderer.NAME, CodeClimateRenderer.class); - map.put(XMLRenderer.NAME, XMLRenderer.class); - map.put(IDEAJRenderer.NAME, IDEAJRenderer.class); - map.put(TextColorRenderer.NAME, TextColorRenderer.class); - map.put(TextRenderer.NAME, TextRenderer.class); - map.put(TextPadRenderer.NAME, TextPadRenderer.class); - map.put(EmacsRenderer.NAME, EmacsRenderer.class); - map.put(CSVRenderer.NAME, CSVRenderer.class); - map.put(HTMLRenderer.NAME, HTMLRenderer.class); - map.put(XSLTRenderer.NAME, XSLTRenderer.class); - map.put(YAHTMLRenderer.NAME, YAHTMLRenderer.class); - map.put(SummaryHTMLRenderer.NAME, SummaryHTMLRenderer.class); - map.put(VBHTMLRenderer.NAME, VBHTMLRenderer.class); - REPORT_FORMAT_TO_RENDERER = Collections.unmodifiableMap(map); - } - - private RendererFactory() { } - - /** - * Construct an instance of a Renderer based on report format name. - * - * @param reportFormat - * The report format name. - * @param properties - * Initialization properties for the corresponding Renderer. - * @return A Renderer instance. - */ - public static Renderer createRenderer(String reportFormat, Properties properties) { - Class rendererClass = getRendererClass(reportFormat); - Constructor constructor = getRendererConstructor(rendererClass); - - Renderer renderer; - try { - if (constructor.getParameterTypes().length > 0) { - LOG.warning( - "The renderer uses a deprecated mechanism to use the properties. Please define the needed properties with this.definePropertyDescriptor(..)."); - renderer = constructor.newInstance(properties); - } else { - renderer = constructor.newInstance(); - - for (PropertyDescriptor prop : renderer.getPropertyDescriptors()) { - String value = properties.getProperty(prop.name()); - if (value != null) { - @SuppressWarnings("unchecked") - PropertyDescriptor prop2 = (PropertyDescriptor) prop; - Object valueFrom = prop2.valueFrom(value); - renderer.setProperty(prop2, valueFrom); - } - } - } - } catch (InstantiationException e) { - throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage()); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage()); - } catch (InvocationTargetException e) { - throw new IllegalArgumentException( - "Unable to construct report renderer class: " + e.getTargetException().getLocalizedMessage()); - } - // Warn about legacy report format usages - if (REPORT_FORMAT_TO_RENDERER.containsKey(reportFormat) && !reportFormat.equals(renderer.getName())) { - if (LOG.isLoggable(Level.WARNING)) { - LOG.warning("Report format '" + reportFormat + "' is deprecated, and has been replaced with '" - + renderer.getName() - + "'. Future versions of PMD will remove support for this deprecated Report format usage."); - } - } - return renderer; - } - - @SuppressWarnings("unchecked") - private static Class getRendererClass(String reportFormat) { - Class rendererClass = REPORT_FORMAT_TO_RENDERER.get(reportFormat); - - // Look up a custom renderer class - if (rendererClass == null && !"".equals(reportFormat)) { - try { - Class clazz = Class.forName(reportFormat); - if (!Renderer.class.isAssignableFrom(clazz)) { - throw new IllegalArgumentException("Custom report renderer class does not implement the " - + Renderer.class.getName() + " interface."); - } else { - rendererClass = (Class) clazz; - } - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Can't find the custom format " + reportFormat + ": " + e); - } - } - return rendererClass; - } - - private static Constructor getRendererConstructor(Class rendererClass) { - Constructor constructor = null; - - // 1) Properties constructor? - deprecated - try { - constructor = rendererClass.getConstructor(Properties.class); - if (!Modifier.isPublic(constructor.getModifiers())) { - constructor = null; - } - } catch (NoSuchMethodException e) { - // Ok - } - - // 2) No-arg constructor? - try { - constructor = rendererClass.getConstructor(); - if (!Modifier.isPublic(constructor.getModifiers())) { - constructor = null; - } - } catch (NoSuchMethodException e2) { - // Ok - } - - if (constructor == null) { - throw new IllegalArgumentException( - "Unable to find either a public java.util.Properties or no-arg constructors for Renderer class: " - + rendererClass.getName()); - } - return constructor; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.renderers; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.sourceforge.pmd.PropertyDescriptor; + +/** + * This class handles the creation of Renderers. + * + * @see Renderer + */ +public class RendererFactory { + + private static final Logger LOG = Logger.getLogger(RendererFactory.class.getName()); + + public static final Map> REPORT_FORMAT_TO_RENDERER; + + static { + Map> map = new TreeMap<>(); + map.put(CodeClimateRenderer.NAME, CodeClimateRenderer.class); + map.put(XMLRenderer.NAME, XMLRenderer.class); + map.put(IDEAJRenderer.NAME, IDEAJRenderer.class); + map.put(TextColorRenderer.NAME, TextColorRenderer.class); + map.put(TextRenderer.NAME, TextRenderer.class); + map.put(TextPadRenderer.NAME, TextPadRenderer.class); + map.put(EmacsRenderer.NAME, EmacsRenderer.class); + map.put(CSVRenderer.NAME, CSVRenderer.class); + map.put(HTMLRenderer.NAME, HTMLRenderer.class); + map.put(XSLTRenderer.NAME, XSLTRenderer.class); + map.put(YAHTMLRenderer.NAME, YAHTMLRenderer.class); + map.put(SummaryHTMLRenderer.NAME, SummaryHTMLRenderer.class); + map.put(VBHTMLRenderer.NAME, VBHTMLRenderer.class); + REPORT_FORMAT_TO_RENDERER = Collections.unmodifiableMap(map); + } + + private RendererFactory() { } + + /** + * Construct an instance of a Renderer based on report format name. + * + * @param reportFormat + * The report format name. + * @param properties + * Initialization properties for the corresponding Renderer. + * @return A Renderer instance. + */ + public static Renderer createRenderer(String reportFormat, Properties properties) { + Class rendererClass = getRendererClass(reportFormat); + Constructor constructor = getRendererConstructor(rendererClass); + + Renderer renderer; + try { + if (constructor.getParameterTypes().length > 0) { + LOG.warning( + "The renderer uses a deprecated mechanism to use the properties. Please define the needed properties with this.definePropertyDescriptor(..)."); + renderer = constructor.newInstance(properties); + } else { + renderer = constructor.newInstance(); + + for (PropertyDescriptor prop : renderer.getPropertyDescriptors()) { + String value = properties.getProperty(prop.name()); + if (value != null) { + @SuppressWarnings("unchecked") + PropertyDescriptor prop2 = (PropertyDescriptor) prop; + Object valueFrom = prop2.valueFrom(value); + renderer.setProperty(prop2, valueFrom); + } + } + } + } catch (InstantiationException e) { + throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage()); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage()); + } catch (InvocationTargetException e) { + throw new IllegalArgumentException( + "Unable to construct report renderer class: " + e.getTargetException().getLocalizedMessage()); + } + // Warn about legacy report format usages + if (REPORT_FORMAT_TO_RENDERER.containsKey(reportFormat) && !reportFormat.equals(renderer.getName())) { + if (LOG.isLoggable(Level.WARNING)) { + LOG.warning("Report format '" + reportFormat + "' is deprecated, and has been replaced with '" + + renderer.getName() + + "'. Future versions of PMD will remove support for this deprecated Report format usage."); + } + } + return renderer; + } + + @SuppressWarnings("unchecked") + private static Class getRendererClass(String reportFormat) { + Class rendererClass = REPORT_FORMAT_TO_RENDERER.get(reportFormat); + + // Look up a custom renderer class + if (rendererClass == null && !"".equals(reportFormat)) { + try { + Class clazz = Class.forName(reportFormat); + if (!Renderer.class.isAssignableFrom(clazz)) { + throw new IllegalArgumentException("Custom report renderer class does not implement the " + + Renderer.class.getName() + " interface."); + } else { + rendererClass = (Class) clazz; + } + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Can't find the custom format " + reportFormat + ": " + e); + } + } + return rendererClass; + } + + private static Constructor getRendererConstructor(Class rendererClass) { + Constructor constructor = null; + + // 1) Properties constructor? - deprecated + try { + constructor = rendererClass.getConstructor(Properties.class); + if (!Modifier.isPublic(constructor.getModifiers())) { + constructor = null; + } + } catch (NoSuchMethodException e) { + // Ok + } + + // 2) No-arg constructor? + try { + constructor = rendererClass.getConstructor(); + if (!Modifier.isPublic(constructor.getModifiers())) { + constructor = null; + } + } catch (NoSuchMethodException e2) { + // Ok + } + + if (constructor == null) { + throw new IllegalArgumentException( + "Unable to find either a public java.util.Properties or no-arg constructors for Renderer class: " + + rendererClass.getName()); + } + return constructor; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/CompoundIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/CompoundIterator.java index c12d8f9b8d..543d6c3fcc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/CompoundIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/CompoundIterator.java @@ -1,78 +1,78 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Creates a single compound Iterator from an array of Iterators. - * - * @param - * The type returned by the Iterator. - * - * @see Iterator - */ -public class CompoundIterator implements Iterator { - private final Iterator[] iterators; - private int index; - - /** - * - * @param iterators - * The iterators use. - */ - public CompoundIterator(Iterator... iterators) { - this.iterators = iterators; - this.index = 0; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNext() { - return getNextIterator() != null; - } - - /** - * {@inheritDoc} - */ - @Override - public T next() { - Iterator iterator = getNextIterator(); - if (iterator != null) { - return iterator.next(); - } else { - throw new NoSuchElementException(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void remove() { - Iterator iterator = getNextIterator(); - if (iterator != null) { - iterator.remove(); - } else { - throw new IllegalStateException(); - } - } - - // Get the next iterator with values, returns null if there is no such - // iterator - private Iterator getNextIterator() { - while (index < iterators.length) { - if (iterators[index].hasNext()) { - return iterators[index]; - } else { - index++; - } - } - return null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Creates a single compound Iterator from an array of Iterators. + * + * @param + * The type returned by the Iterator. + * + * @see Iterator + */ +public class CompoundIterator implements Iterator { + private final Iterator[] iterators; + private int index; + + /** + * + * @param iterators + * The iterators use. + */ + public CompoundIterator(Iterator... iterators) { + this.iterators = iterators; + this.index = 0; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasNext() { + return getNextIterator() != null; + } + + /** + * {@inheritDoc} + */ + @Override + public T next() { + Iterator iterator = getNextIterator(); + if (iterator != null) { + return iterator.next(); + } else { + throw new NoSuchElementException(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void remove() { + Iterator iterator = getNextIterator(); + if (iterator != null) { + iterator.remove(); + } else { + throw new IllegalStateException(); + } + } + + // Get the next iterator with values, returns null if there is no such + // iterator + private Iterator getNextIterator() { + while (index < iterators.length) { + if (iterators[index].hasNext()) { + return iterators[index]; + } else { + index++; + } + } + return null; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java index d075b8c297..544e10dad6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java @@ -1,46 +1,46 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import java.io.File; -import java.io.FilenameFilter; -import java.util.ArrayList; -import java.util.List; - -/** - * A utility class for finding files within a directory. - */ -public class FileFinder { - - private FilenameFilter filter; - private static final String FILE_SEP = System.getProperty("file.separator"); - - public List findFilesFrom(File dir, FilenameFilter filter, boolean recurse) { - this.filter = filter; - List files = new ArrayList<>(); - scanDirectory(dir, files, recurse); - return files; - } - - /** - * Implements a tail recursive file scanner - */ - private void scanDirectory(File dir, List list, boolean recurse) { - String[] candidates = dir.list(filter); - if (candidates == null) { - return; - } - for (int i = 0; i < candidates.length; i++) { - File tmp = new File(dir + FILE_SEP + candidates[i]); - if (tmp.isDirectory()) { - if (recurse) { - scanDirectory(tmp, list, true); - } - } else { - list.add(new File(dir + FILE_SEP + candidates[i])); - } - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.List; + +/** + * A utility class for finding files within a directory. + */ +public class FileFinder { + + private FilenameFilter filter; + private static final String FILE_SEP = System.getProperty("file.separator"); + + public List findFilesFrom(File dir, FilenameFilter filter, boolean recurse) { + this.filter = filter; + List files = new ArrayList<>(); + scanDirectory(dir, files, recurse); + return files; + } + + /** + * Implements a tail recursive file scanner + */ + private void scanDirectory(File dir, List list, boolean recurse) { + String[] candidates = dir.list(filter); + if (candidates == null) { + return; + } + for (int i = 0; i < candidates.length; i++) { + File tmp = new File(dir + FILE_SEP + candidates[i]); + if (tmp.isDirectory()) { + if (recurse) { + scanDirectory(tmp, list, true); + } + } else { + list.add(new File(dir + FILE_SEP + candidates[i])); + } + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/database/DBMSMetadata.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/database/DBMSMetadata.java index 85375e45e3..634c3154f9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/database/DBMSMetadata.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/database/DBMSMetadata.java @@ -1,535 +1,535 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.database; - -import java.net.MalformedURLException; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Wrap JDBC connection for use by PMD: {@link DBURI} parameters specify the - * source code to be passed to PMD. - * - * @author sturton - */ -public class DBMSMetadata { - - /** - * Classname utility string for use in logging. - */ - private static final String CLASS_NAME = DBMSMetadata.class.getCanonicalName(); - - /** - * Local logger. - */ - private static final Logger LOGGER = Logger.getLogger(CLASS_NAME); - - /** - * Optional DBType property specifying a query to fetch the Source Objects - * from the database. - * - *

- * If the DBType lacks this property, then the standard - * DatabaseMetaData.getProcedures method is used. - *

- */ - private static final String GET_SOURCE_OBJECTS_STATEMENT = "getSourceObjectsStatement"; - - /** - * Essential DBType property specifying a CallableStatement to retrieve the - * Source Object's code from the database. - * - *

- * If the DBType lacks this property, there is no DatabaseMetaData method - * to fallback to. - *

- */ - private static final String GET_SOURCE_CODE_STATEMENT = "getSourceCodeStatement"; - - /** - * DBURI - */ - protected DBURI dburi = null; - - /** - * Connection management - */ - protected Connection connection = null; - - /** - * Procedural statement to return list of source code objects. - */ - protected String returnSourceCodeObjectsStatement = null; - - /** - * Procedural statement to return source code. - */ - protected String returnSourceCodeStatement = null; - - /** - * CallableStatement to return source code. - */ - protected CallableStatement callableStatement = null; - - /** - * {@link java.sql.Types} value representing the type returned by - * {@link callableStatement} - * - * Currently only java.sql.Types.String and java.sql.Types.Clob are - * supported - */ - protected int returnType = java.sql.Types.CLOB; - - /* constructors */ - /** - * Minimal constructor - * - * @param c - * JDBC Connection - * @throws SQLException - */ - public DBMSMetadata(Connection c) throws SQLException { - connection = c; - } - - /** - * Define database connection and source code to retrieve with explicit - * database username and password. - * - * @param user - * Database username - * @param password - * Database password - * @param dbURI - * {@link DBURI } containing JDBC connection plus parameters to - * specify source code. - * @throws SQLException - * on failing to create JDBC connection - * @throws MalformedURLException - * on attempting to connect with malformed JDBC URL - * @throws ClassNotFoundException - * on failing to locate the JDBC driver class. - */ - public DBMSMetadata(String user, String password, DBURI dbURI) - throws SQLException, MalformedURLException, ClassNotFoundException { - String urlString = init(dbURI); - - Properties mergedProperties = dbURI.getDbType().getProperties(); - Map dbURIParameters = dbURI.getParameters(); - mergedProperties.putAll(dbURIParameters); - mergedProperties.put("user", user); - mergedProperties.put("password", password); - - connection = DriverManager.getConnection(urlString, mergedProperties); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("we have a connection=" + connection); - } - } - - /** - * Define database connection and source code to retrieve with database - * properties. - * - * @param properties - * database settings such as database username, password - * @param dbURI - * {@link DBURI } containing JDBC connection plus parameters to - * specify source code. - * @throws SQLException - * on failing to create JDBC connection - * @throws MalformedURLException - * on attempting to connect with malformed JDBC URL - * @throws ClassNotFoundException - * on failing to locate the JDBC driver class. - */ - public DBMSMetadata(Properties properties, DBURI dbURI) - throws SQLException, MalformedURLException, ClassNotFoundException { - String urlString = init(dbURI); - - Properties mergedProperties = dbURI.getDbType().getProperties(); - Map dbURIParameters = dbURI.getParameters(); - mergedProperties.putAll(dbURIParameters); - mergedProperties.putAll(properties); - - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("Retrieving connection for urlString" + urlString); - } - connection = DriverManager.getConnection(urlString, mergedProperties); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("Secured Connection for DBURI" + dbURI); - } - } - - /** - * Define database connection and source code to retrieve. - * - *

- * This constructor is reliant on database username and password embedded in - * the JDBC URL or defaulted from the {@link DBURI}'s DriverType. - *

- * - * @param dbURI - * {@link DBURI } containing JDBC connection plus parameters to - * specify source code. - * @throws SQLException - * on failing to create JDBC connection - * @throws ClassNotFoundException - * on failing to locate the JDBC driver class. - */ - public DBMSMetadata(DBURI dbURI) throws SQLException, ClassNotFoundException { - String urlString = init(dbURI); - - Properties dbURIProperties = dbURI.getDbType().getProperties(); - Map dbURIParameters = dbURI.getParameters(); - - /* - * Overwrite any DBType properties with DBURI parameters allowing JDBC - * connection properties to be inherited from DBType or passed as DBURI - * parameters - */ - dbURIProperties.putAll(dbURIParameters); - - connection = DriverManager.getConnection(urlString, dbURIProperties); - } - - /** - * Return JDBC Connection for direct JDBC access to the specified database. - * - * @return I=JDBC Connection - * @throws SQLException - */ - public Connection getConnection() throws SQLException { - return connection; - } - - private String init(DBURI dbURI) throws ClassNotFoundException { - this.dburi = dbURI; - this.returnSourceCodeObjectsStatement = dbURI.getDbType().getProperties() - .getProperty(GET_SOURCE_OBJECTS_STATEMENT); - this.returnSourceCodeStatement = dbURI.getDbType().getProperties().getProperty(GET_SOURCE_CODE_STATEMENT); - this.returnType = dbURI.getSourceCodeType(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("returnSourceCodeStatement=" + returnSourceCodeStatement + ", returnType=" + returnType); - } - - String driverClass = dbURI.getDriverClass(); - String urlString = dbURI.getURL().toString(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("driverClass=" + driverClass + ", urlString=" + urlString); - } - Class.forName(driverClass); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("Located class for driverClass=" + driverClass); - } - return urlString; - } - - /** - * Return source code text from the database. - * - * @param sourceObject object - * @return source code - * @throws SQLException - */ - public java.io.Reader getSourceCode(SourceObject sourceObject) throws SQLException { - return getSourceCode(sourceObject.getType(), sourceObject.getName(), sourceObject.getSchema()); - - } - - /** - * return source code text - * - * @param objectType - * @param name - * Source Code name - * @param schema - * Owner of the code - * @return Source code text. - * @throws SQLException - * on failing to retrieve the source Code text - */ - public java.io.Reader getSourceCode(String objectType, String name, String schema) throws SQLException { - Object result; - - /* - * Only define callableStatement once and reuse it for subsequent calls - * to getSourceCode() - */ - if (null == callableStatement) { - if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.finest("getSourceCode: returnSourceCodeStatement=\"" + returnSourceCodeStatement + "\""); - LOGGER.finest("getSourceCode: returnType=\"" + returnType + "\""); - } - callableStatement = getConnection().prepareCall(returnSourceCodeStatement); - callableStatement.registerOutParameter(1, returnType); - } - - // set IN parameters - callableStatement.setString(2, objectType); - callableStatement.setString(3, name); - callableStatement.setString(4, schema); - // - // execute statement - callableStatement.executeUpdate(); - // retrieve OUT parameters - result = callableStatement.getObject(1); - - return (java.sql.Types.CLOB == returnType) ? ((Clob) result).getCharacterStream() - : new java.io.StringReader(result.toString()); - } - - /** - * Return all source code objects associated with any associated DBURI. - * - * @return - */ - public List getSourceObjectList() { - - if (null == dburi) { - LOGGER.warning("No dbUri defined - no further action possible"); - return null; - } else { - return getSourceObjectList(dburi.getLanguagesList(), dburi.getSchemasList(), dburi.getSourceCodeTypesList(), - dburi.getSourceCodeNamesList()); - } - - } - - /** - * Return all source code objects associated with the specified languages, - * schemas, source code types and source code names. - * - *

- * Each parameter may be null and the appropriate field from any related - * DBURI is assigned, defaulting to the normal SQL wildcard expression - * ("%"). - *

- * - * @param languages - * Optional list of languages to search for - * @param schemas - * Optional list of schemas to search for - * @param sourceCodeTypes - * Optional list of source code types to search for - * @param sourceCodeNames - * Optional list of source code names to search for - */ - public List getSourceObjectList(List languages, List schemas, - List sourceCodeTypes, List sourceCodeNames) { - - ResultSet sourceCodeObjects = null; - List sourceObjectsList = new ArrayList<>(); - - List searchLanguages = languages; - List searchSchemas = schemas; - List searchSourceCodeTypes = sourceCodeTypes; - List searchSourceCodeNames = sourceCodeNames; - List wildcardList = Arrays.asList("%"); - - /* - * Assign each search list to the first - * - * explicit parameter dburi field wildcard list - * - */ - if (null == searchLanguages) { - List dbURIList = (null == dburi) ? null : dburi.getLanguagesList(); - if (null == dbURIList || dbURIList.isEmpty()) { - searchLanguages = wildcardList; - } else { - searchLanguages = dbURIList; - } - } - - if (null == searchSchemas) { - List dbURIList = (null == dburi) ? null : dburi.getSchemasList(); - if (null == dbURIList || dbURIList.isEmpty()) { - searchSchemas = wildcardList; - } else { - searchSchemas = dbURIList; - } - } - - if (null == searchSourceCodeTypes) { - List dbURIList = (null == dburi) ? null : dburi.getSourceCodeTypesList(); - if (null == dbURIList || dbURIList.isEmpty()) { - searchSourceCodeTypes = wildcardList; - } else { - searchSourceCodeTypes = dbURIList; - } - } - - if (null == searchSourceCodeNames) { - List dbURIList = (null == dburi) ? null : dburi.getSourceCodeNamesList(); - if (null == dbURIList || dbURIList.isEmpty()) { - searchSourceCodeNames = wildcardList; - } else { - searchSourceCodeNames = dbURIList; - } - } - - try { - - if (null != returnSourceCodeObjectsStatement) { - LOGGER.log(Level.FINE, "Have bespoke returnSourceCodeObjectsStatement from DBURI: \"{0}\"", - returnSourceCodeObjectsStatement); - PreparedStatement sourceCodeObjectsStatement = getConnection() - .prepareStatement(returnSourceCodeObjectsStatement); - - for (String language : searchLanguages) { - for (String schema : searchSchemas) { - for (String sourceCodeType : searchSourceCodeTypes) { - for (String sourceCodeName : searchSourceCodeNames) { - sourceCodeObjectsStatement.setString(1, language); - sourceCodeObjectsStatement.setString(2, schema); - sourceCodeObjectsStatement.setString(3, sourceCodeType); - sourceCodeObjectsStatement.setString(4, sourceCodeName); - LOGGER.finer(String.format( - "searching for language=\"%s\", schema=\"%s\", sourceCodeType=\"%s\", sourceCodeNames=\"%s\" ", - language, schema, sourceCodeType, sourceCodeName)); - - /* - * public ResultSet getProcedures(String catalog - * , String schemaPattern , String - * procedureNamePattern) throws SQLException - */ - - sourceCodeObjects = sourceCodeObjectsStatement.executeQuery(); - - /* - * From Javadoc .... Each procedure description - * has the the following columns: PROCEDURE_CAT - * String => procedure catalog (may be null) - * PROCEDURE_SCHEM String => procedure schema - * (may be null) PROCEDURE_NAME String => - * procedure name reserved for future use - * reserved for future use reserved for future - * use REMARKS String => explanatory comment on - * the procedure PROCEDURE_TYPE short => kind of - * procedure: procedureResultUnknown - Cannot - * determine if a return value will be returned - * procedureNoResult - Does not return a return - * value procedureReturnsResult - Returns a - * return value SPECIFIC_NAME String => The name - * which uniquely identifies this procedure - * within its schema. - */ - while (sourceCodeObjects.next()) { - LOGGER.finest(String.format("Found schema=%s,object_type=%s,object_name=%s", - sourceCodeObjects.getString("PROCEDURE_SCHEM"), - sourceCodeObjects.getString("PROCEDURE_TYPE"), - sourceCodeObjects.getString("PROCEDURE_NAME"))); - - sourceObjectsList - .add(new SourceObject(sourceCodeObjects.getString("PROCEDURE_SCHEM"), - sourceCodeObjects.getString("PROCEDURE_TYPE"), - sourceCodeObjects.getString("PROCEDURE_NAME"), null)); - } - } - } - } - } - } else { - // Use standard DatabaseMetaData interface - LOGGER.fine( - "Have dbUri - no returnSourceCodeObjectsStatement, reverting to DatabaseMetaData.getProcedures(...)"); - - DatabaseMetaData metadata = connection.getMetaData(); - List schemasList = dburi.getSchemasList(); - for (String schema : schemasList) { - for (String sourceCodeName : dburi.getSourceCodeNamesList()) { - /* - * public ResultSet getProcedures(String catalog , - * String schemaPattern , String procedureNamePattern) - * throws SQLException - */ - sourceCodeObjects = metadata.getProcedures(null, schema, sourceCodeName); - /* - * From Javadoc .... Each procedure description has the - * the following columns: PROCEDURE_CAT String => - * procedure catalog (may be null) PROCEDURE_SCHEM - * String => procedure schema (may be null) - * PROCEDURE_NAME String => procedure name reserved for - * future use reserved for future use reserved for - * future use REMARKS String => explanatory comment on - * the procedure PROCEDURE_TYPE short => kind of - * procedure: procedureResultUnknown - Cannot determine - * if a return value will be returned procedureNoResult - * - Does not return a return value - * procedureReturnsResult - Returns a return value - * SPECIFIC_NAME String => The name which uniquely - * identifies this procedure within its schema. - * - * Oracle getProcedures actually returns these 8 - * columns:- ResultSet "Matched Procedures" has 8 - * columns and contains ... - * [PROCEDURE_CAT,PROCEDURE_SCHEM,PROCEDURE_NAME,NULL, - * NULL,NULL,REMARKS,PROCEDURE_TYPE - * ,null,PHPDEMO,ADD_JOB_HISTORY,null,null,null, - * Standalone procedure or function,1 - * ,FETCHPERFPKG,PHPDEMO,BULKSELECTPRC,null,null,null, - * Packaged function,2 - * ,FETCHPERFPKG,PHPDEMO,BULKSELECTPRC,null,null,null, - * Packaged procedure,1 - * ,null,PHPDEMO,CITY_LIST,null,null,null,Standalone - * procedure or function,1 - * ,null,PHPDEMO,EDDISCOUNT,null,null,null,Standalone - * procedure or function,2 - * ,SELPKG_BA,PHPDEMO,EMPSELBULK,null,null,null,Packaged - * function,2 - * ,SELPKG_BA,PHPDEMO,EMPSELBULK,null,null,null,Packaged - * procedure,1 - * ,INSPKG,PHPDEMO,INSFORALL,null,null,null,Packaged - * procedure,1 - * ,null,PHPDEMO,MYDOFETCH,null,null,null,Standalone - * procedure or function,2 - * ,null,PHPDEMO,MYPROC1,null,null,null,Standalone - * procedure or function,1 - * ,null,PHPDEMO,MYPROC2,null,null,null,Standalone - * procedure or function,1 - * ,null,PHPDEMO,MYXAQUERY,null,null,null,Standalone - * procedure or function,1 - * ,null,PHPDEMO,POLICY_VPDPARTS,null,null,null, - * Standalone procedure or function,2 - * ,FETCHPERFPKG,PHPDEMO,REFCURPRC,null,null,null, - * Packaged procedure,1 - * ,null,PHPDEMO,SECURE_DML,null,null,null,Standalone - * procedure or function,1 ... ] - */ - while (sourceCodeObjects.next()) { - LOGGER.finest(String.format("Located schema=%s,object_type=%s,object_name=%s\n", - sourceCodeObjects.getString("PROCEDURE_SCHEM"), - sourceCodeObjects.getString("PROCEDURE_TYPE"), - sourceCodeObjects.getString("PROCEDURE_NAME"))); - - sourceObjectsList.add(new SourceObject(sourceCodeObjects.getString("PROCEDURE_SCHEM"), - sourceCodeObjects.getString("PROCEDURE_TYPE"), - sourceCodeObjects.getString("PROCEDURE_NAME"), null)); - } - } - } - } - - LOGGER.finer(String.format("Identfied=%d sourceObjects", sourceObjectsList.size())); - - return sourceObjectsList; - } catch (SQLException sqle) { - throw new RuntimeException("Problem collecting list of source code objects", sqle); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.database; + +import java.net.MalformedURLException; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Wrap JDBC connection for use by PMD: {@link DBURI} parameters specify the + * source code to be passed to PMD. + * + * @author sturton + */ +public class DBMSMetadata { + + /** + * Classname utility string for use in logging. + */ + private static final String CLASS_NAME = DBMSMetadata.class.getCanonicalName(); + + /** + * Local logger. + */ + private static final Logger LOGGER = Logger.getLogger(CLASS_NAME); + + /** + * Optional DBType property specifying a query to fetch the Source Objects + * from the database. + * + *

+ * If the DBType lacks this property, then the standard + * DatabaseMetaData.getProcedures method is used. + *

+ */ + private static final String GET_SOURCE_OBJECTS_STATEMENT = "getSourceObjectsStatement"; + + /** + * Essential DBType property specifying a CallableStatement to retrieve the + * Source Object's code from the database. + * + *

+ * If the DBType lacks this property, there is no DatabaseMetaData method + * to fallback to. + *

+ */ + private static final String GET_SOURCE_CODE_STATEMENT = "getSourceCodeStatement"; + + /** + * DBURI + */ + protected DBURI dburi = null; + + /** + * Connection management + */ + protected Connection connection = null; + + /** + * Procedural statement to return list of source code objects. + */ + protected String returnSourceCodeObjectsStatement = null; + + /** + * Procedural statement to return source code. + */ + protected String returnSourceCodeStatement = null; + + /** + * CallableStatement to return source code. + */ + protected CallableStatement callableStatement = null; + + /** + * {@link java.sql.Types} value representing the type returned by + * {@link callableStatement} + * + * Currently only java.sql.Types.String and java.sql.Types.Clob are + * supported + */ + protected int returnType = java.sql.Types.CLOB; + + /* constructors */ + /** + * Minimal constructor + * + * @param c + * JDBC Connection + * @throws SQLException + */ + public DBMSMetadata(Connection c) throws SQLException { + connection = c; + } + + /** + * Define database connection and source code to retrieve with explicit + * database username and password. + * + * @param user + * Database username + * @param password + * Database password + * @param dbURI + * {@link DBURI } containing JDBC connection plus parameters to + * specify source code. + * @throws SQLException + * on failing to create JDBC connection + * @throws MalformedURLException + * on attempting to connect with malformed JDBC URL + * @throws ClassNotFoundException + * on failing to locate the JDBC driver class. + */ + public DBMSMetadata(String user, String password, DBURI dbURI) + throws SQLException, MalformedURLException, ClassNotFoundException { + String urlString = init(dbURI); + + Properties mergedProperties = dbURI.getDbType().getProperties(); + Map dbURIParameters = dbURI.getParameters(); + mergedProperties.putAll(dbURIParameters); + mergedProperties.put("user", user); + mergedProperties.put("password", password); + + connection = DriverManager.getConnection(urlString, mergedProperties); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("we have a connection=" + connection); + } + } + + /** + * Define database connection and source code to retrieve with database + * properties. + * + * @param properties + * database settings such as database username, password + * @param dbURI + * {@link DBURI } containing JDBC connection plus parameters to + * specify source code. + * @throws SQLException + * on failing to create JDBC connection + * @throws MalformedURLException + * on attempting to connect with malformed JDBC URL + * @throws ClassNotFoundException + * on failing to locate the JDBC driver class. + */ + public DBMSMetadata(Properties properties, DBURI dbURI) + throws SQLException, MalformedURLException, ClassNotFoundException { + String urlString = init(dbURI); + + Properties mergedProperties = dbURI.getDbType().getProperties(); + Map dbURIParameters = dbURI.getParameters(); + mergedProperties.putAll(dbURIParameters); + mergedProperties.putAll(properties); + + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("Retrieving connection for urlString" + urlString); + } + connection = DriverManager.getConnection(urlString, mergedProperties); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("Secured Connection for DBURI" + dbURI); + } + } + + /** + * Define database connection and source code to retrieve. + * + *

+ * This constructor is reliant on database username and password embedded in + * the JDBC URL or defaulted from the {@link DBURI}'s DriverType. + *

+ * + * @param dbURI + * {@link DBURI } containing JDBC connection plus parameters to + * specify source code. + * @throws SQLException + * on failing to create JDBC connection + * @throws ClassNotFoundException + * on failing to locate the JDBC driver class. + */ + public DBMSMetadata(DBURI dbURI) throws SQLException, ClassNotFoundException { + String urlString = init(dbURI); + + Properties dbURIProperties = dbURI.getDbType().getProperties(); + Map dbURIParameters = dbURI.getParameters(); + + /* + * Overwrite any DBType properties with DBURI parameters allowing JDBC + * connection properties to be inherited from DBType or passed as DBURI + * parameters + */ + dbURIProperties.putAll(dbURIParameters); + + connection = DriverManager.getConnection(urlString, dbURIProperties); + } + + /** + * Return JDBC Connection for direct JDBC access to the specified database. + * + * @return I=JDBC Connection + * @throws SQLException + */ + public Connection getConnection() throws SQLException { + return connection; + } + + private String init(DBURI dbURI) throws ClassNotFoundException { + this.dburi = dbURI; + this.returnSourceCodeObjectsStatement = dbURI.getDbType().getProperties() + .getProperty(GET_SOURCE_OBJECTS_STATEMENT); + this.returnSourceCodeStatement = dbURI.getDbType().getProperties().getProperty(GET_SOURCE_CODE_STATEMENT); + this.returnType = dbURI.getSourceCodeType(); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("returnSourceCodeStatement=" + returnSourceCodeStatement + ", returnType=" + returnType); + } + + String driverClass = dbURI.getDriverClass(); + String urlString = dbURI.getURL().toString(); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("driverClass=" + driverClass + ", urlString=" + urlString); + } + Class.forName(driverClass); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("Located class for driverClass=" + driverClass); + } + return urlString; + } + + /** + * Return source code text from the database. + * + * @param sourceObject object + * @return source code + * @throws SQLException + */ + public java.io.Reader getSourceCode(SourceObject sourceObject) throws SQLException { + return getSourceCode(sourceObject.getType(), sourceObject.getName(), sourceObject.getSchema()); + + } + + /** + * return source code text + * + * @param objectType + * @param name + * Source Code name + * @param schema + * Owner of the code + * @return Source code text. + * @throws SQLException + * on failing to retrieve the source Code text + */ + public java.io.Reader getSourceCode(String objectType, String name, String schema) throws SQLException { + Object result; + + /* + * Only define callableStatement once and reuse it for subsequent calls + * to getSourceCode() + */ + if (null == callableStatement) { + if (LOGGER.isLoggable(Level.FINEST)) { + LOGGER.finest("getSourceCode: returnSourceCodeStatement=\"" + returnSourceCodeStatement + "\""); + LOGGER.finest("getSourceCode: returnType=\"" + returnType + "\""); + } + callableStatement = getConnection().prepareCall(returnSourceCodeStatement); + callableStatement.registerOutParameter(1, returnType); + } + + // set IN parameters + callableStatement.setString(2, objectType); + callableStatement.setString(3, name); + callableStatement.setString(4, schema); + // + // execute statement + callableStatement.executeUpdate(); + // retrieve OUT parameters + result = callableStatement.getObject(1); + + return (java.sql.Types.CLOB == returnType) ? ((Clob) result).getCharacterStream() + : new java.io.StringReader(result.toString()); + } + + /** + * Return all source code objects associated with any associated DBURI. + * + * @return + */ + public List getSourceObjectList() { + + if (null == dburi) { + LOGGER.warning("No dbUri defined - no further action possible"); + return null; + } else { + return getSourceObjectList(dburi.getLanguagesList(), dburi.getSchemasList(), dburi.getSourceCodeTypesList(), + dburi.getSourceCodeNamesList()); + } + + } + + /** + * Return all source code objects associated with the specified languages, + * schemas, source code types and source code names. + * + *

+ * Each parameter may be null and the appropriate field from any related + * DBURI is assigned, defaulting to the normal SQL wildcard expression + * ("%"). + *

+ * + * @param languages + * Optional list of languages to search for + * @param schemas + * Optional list of schemas to search for + * @param sourceCodeTypes + * Optional list of source code types to search for + * @param sourceCodeNames + * Optional list of source code names to search for + */ + public List getSourceObjectList(List languages, List schemas, + List sourceCodeTypes, List sourceCodeNames) { + + ResultSet sourceCodeObjects = null; + List sourceObjectsList = new ArrayList<>(); + + List searchLanguages = languages; + List searchSchemas = schemas; + List searchSourceCodeTypes = sourceCodeTypes; + List searchSourceCodeNames = sourceCodeNames; + List wildcardList = Arrays.asList("%"); + + /* + * Assign each search list to the first + * + * explicit parameter dburi field wildcard list + * + */ + if (null == searchLanguages) { + List dbURIList = (null == dburi) ? null : dburi.getLanguagesList(); + if (null == dbURIList || dbURIList.isEmpty()) { + searchLanguages = wildcardList; + } else { + searchLanguages = dbURIList; + } + } + + if (null == searchSchemas) { + List dbURIList = (null == dburi) ? null : dburi.getSchemasList(); + if (null == dbURIList || dbURIList.isEmpty()) { + searchSchemas = wildcardList; + } else { + searchSchemas = dbURIList; + } + } + + if (null == searchSourceCodeTypes) { + List dbURIList = (null == dburi) ? null : dburi.getSourceCodeTypesList(); + if (null == dbURIList || dbURIList.isEmpty()) { + searchSourceCodeTypes = wildcardList; + } else { + searchSourceCodeTypes = dbURIList; + } + } + + if (null == searchSourceCodeNames) { + List dbURIList = (null == dburi) ? null : dburi.getSourceCodeNamesList(); + if (null == dbURIList || dbURIList.isEmpty()) { + searchSourceCodeNames = wildcardList; + } else { + searchSourceCodeNames = dbURIList; + } + } + + try { + + if (null != returnSourceCodeObjectsStatement) { + LOGGER.log(Level.FINE, "Have bespoke returnSourceCodeObjectsStatement from DBURI: \"{0}\"", + returnSourceCodeObjectsStatement); + PreparedStatement sourceCodeObjectsStatement = getConnection() + .prepareStatement(returnSourceCodeObjectsStatement); + + for (String language : searchLanguages) { + for (String schema : searchSchemas) { + for (String sourceCodeType : searchSourceCodeTypes) { + for (String sourceCodeName : searchSourceCodeNames) { + sourceCodeObjectsStatement.setString(1, language); + sourceCodeObjectsStatement.setString(2, schema); + sourceCodeObjectsStatement.setString(3, sourceCodeType); + sourceCodeObjectsStatement.setString(4, sourceCodeName); + LOGGER.finer(String.format( + "searching for language=\"%s\", schema=\"%s\", sourceCodeType=\"%s\", sourceCodeNames=\"%s\" ", + language, schema, sourceCodeType, sourceCodeName)); + + /* + * public ResultSet getProcedures(String catalog + * , String schemaPattern , String + * procedureNamePattern) throws SQLException + */ + + sourceCodeObjects = sourceCodeObjectsStatement.executeQuery(); + + /* + * From Javadoc .... Each procedure description + * has the the following columns: PROCEDURE_CAT + * String => procedure catalog (may be null) + * PROCEDURE_SCHEM String => procedure schema + * (may be null) PROCEDURE_NAME String => + * procedure name reserved for future use + * reserved for future use reserved for future + * use REMARKS String => explanatory comment on + * the procedure PROCEDURE_TYPE short => kind of + * procedure: procedureResultUnknown - Cannot + * determine if a return value will be returned + * procedureNoResult - Does not return a return + * value procedureReturnsResult - Returns a + * return value SPECIFIC_NAME String => The name + * which uniquely identifies this procedure + * within its schema. + */ + while (sourceCodeObjects.next()) { + LOGGER.finest(String.format("Found schema=%s,object_type=%s,object_name=%s", + sourceCodeObjects.getString("PROCEDURE_SCHEM"), + sourceCodeObjects.getString("PROCEDURE_TYPE"), + sourceCodeObjects.getString("PROCEDURE_NAME"))); + + sourceObjectsList + .add(new SourceObject(sourceCodeObjects.getString("PROCEDURE_SCHEM"), + sourceCodeObjects.getString("PROCEDURE_TYPE"), + sourceCodeObjects.getString("PROCEDURE_NAME"), null)); + } + } + } + } + } + } else { + // Use standard DatabaseMetaData interface + LOGGER.fine( + "Have dbUri - no returnSourceCodeObjectsStatement, reverting to DatabaseMetaData.getProcedures(...)"); + + DatabaseMetaData metadata = connection.getMetaData(); + List schemasList = dburi.getSchemasList(); + for (String schema : schemasList) { + for (String sourceCodeName : dburi.getSourceCodeNamesList()) { + /* + * public ResultSet getProcedures(String catalog , + * String schemaPattern , String procedureNamePattern) + * throws SQLException + */ + sourceCodeObjects = metadata.getProcedures(null, schema, sourceCodeName); + /* + * From Javadoc .... Each procedure description has the + * the following columns: PROCEDURE_CAT String => + * procedure catalog (may be null) PROCEDURE_SCHEM + * String => procedure schema (may be null) + * PROCEDURE_NAME String => procedure name reserved for + * future use reserved for future use reserved for + * future use REMARKS String => explanatory comment on + * the procedure PROCEDURE_TYPE short => kind of + * procedure: procedureResultUnknown - Cannot determine + * if a return value will be returned procedureNoResult + * - Does not return a return value + * procedureReturnsResult - Returns a return value + * SPECIFIC_NAME String => The name which uniquely + * identifies this procedure within its schema. + * + * Oracle getProcedures actually returns these 8 + * columns:- ResultSet "Matched Procedures" has 8 + * columns and contains ... + * [PROCEDURE_CAT,PROCEDURE_SCHEM,PROCEDURE_NAME,NULL, + * NULL,NULL,REMARKS,PROCEDURE_TYPE + * ,null,PHPDEMO,ADD_JOB_HISTORY,null,null,null, + * Standalone procedure or function,1 + * ,FETCHPERFPKG,PHPDEMO,BULKSELECTPRC,null,null,null, + * Packaged function,2 + * ,FETCHPERFPKG,PHPDEMO,BULKSELECTPRC,null,null,null, + * Packaged procedure,1 + * ,null,PHPDEMO,CITY_LIST,null,null,null,Standalone + * procedure or function,1 + * ,null,PHPDEMO,EDDISCOUNT,null,null,null,Standalone + * procedure or function,2 + * ,SELPKG_BA,PHPDEMO,EMPSELBULK,null,null,null,Packaged + * function,2 + * ,SELPKG_BA,PHPDEMO,EMPSELBULK,null,null,null,Packaged + * procedure,1 + * ,INSPKG,PHPDEMO,INSFORALL,null,null,null,Packaged + * procedure,1 + * ,null,PHPDEMO,MYDOFETCH,null,null,null,Standalone + * procedure or function,2 + * ,null,PHPDEMO,MYPROC1,null,null,null,Standalone + * procedure or function,1 + * ,null,PHPDEMO,MYPROC2,null,null,null,Standalone + * procedure or function,1 + * ,null,PHPDEMO,MYXAQUERY,null,null,null,Standalone + * procedure or function,1 + * ,null,PHPDEMO,POLICY_VPDPARTS,null,null,null, + * Standalone procedure or function,2 + * ,FETCHPERFPKG,PHPDEMO,REFCURPRC,null,null,null, + * Packaged procedure,1 + * ,null,PHPDEMO,SECURE_DML,null,null,null,Standalone + * procedure or function,1 ... ] + */ + while (sourceCodeObjects.next()) { + LOGGER.finest(String.format("Located schema=%s,object_type=%s,object_name=%s\n", + sourceCodeObjects.getString("PROCEDURE_SCHEM"), + sourceCodeObjects.getString("PROCEDURE_TYPE"), + sourceCodeObjects.getString("PROCEDURE_NAME"))); + + sourceObjectsList.add(new SourceObject(sourceCodeObjects.getString("PROCEDURE_SCHEM"), + sourceCodeObjects.getString("PROCEDURE_TYPE"), + sourceCodeObjects.getString("PROCEDURE_NAME"), null)); + } + } + } + } + + LOGGER.finer(String.format("Identfied=%d sourceObjects", sourceObjectsList.size())); + + return sourceObjectsList; + } catch (SQLException sqle) { + throw new RuntimeException("Problem collecting list of source code objects", sqle); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractCompoundFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractCompoundFilter.java index 18c0f86d18..0b8d26ea63 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractCompoundFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractCompoundFilter.java @@ -1,61 +1,61 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * A base class for Filters which implements behavior using a List of other - * Filters. - * - * @param - * The underlying type on which the filter applies. - */ -public abstract class AbstractCompoundFilter implements Filter { - - protected List> filters; - - public AbstractCompoundFilter() { - filters = new ArrayList<>(2); - } - - public AbstractCompoundFilter(Filter... filters) { - this.filters = Arrays.asList(filters); - } - - public List> getFilters() { - return filters; - } - - public void setFilters(List> filters) { - this.filters = filters; - } - - public void addFilter(Filter filter) { - filters.add(filter); - } - - protected abstract String getOperator(); - - @Override - public String toString() { - - if (filters.isEmpty()) { - return "()"; - } - - StringBuilder builder = new StringBuilder(); - builder.append('(').append(filters.get(0)); - - for (int i = 1; i < filters.size(); i++) { - builder.append(' ').append(getOperator()).append(' '); - builder.append(filters.get(i)); - } - builder.append(')'); - return builder.toString(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A base class for Filters which implements behavior using a List of other + * Filters. + * + * @param + * The underlying type on which the filter applies. + */ +public abstract class AbstractCompoundFilter implements Filter { + + protected List> filters; + + public AbstractCompoundFilter() { + filters = new ArrayList<>(2); + } + + public AbstractCompoundFilter(Filter... filters) { + this.filters = Arrays.asList(filters); + } + + public List> getFilters() { + return filters; + } + + public void setFilters(List> filters) { + this.filters = filters; + } + + public void addFilter(Filter filter) { + filters.add(filter); + } + + protected abstract String getOperator(); + + @Override + public String toString() { + + if (filters.isEmpty()) { + return "()"; + } + + StringBuilder builder = new StringBuilder(); + builder.append('(').append(filters.get(0)); + + for (int i = 1; i < filters.size(); i++) { + builder.append(' ').append(getOperator()).append(' '); + builder.append(filters.get(i)); + } + builder.append(')'); + return builder.toString(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractDelegateFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractDelegateFilter.java index cb0589a6ec..96ad9cb7c4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractDelegateFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AbstractDelegateFilter.java @@ -1,43 +1,43 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -/** - * A base class for Filters which implements behavior using delegation to an - * underlying filter. - * - * @param - * The underlying type on which the filter applies. - */ -public abstract class AbstractDelegateFilter implements Filter { - protected Filter filter; - - public AbstractDelegateFilter() { - } - - public AbstractDelegateFilter(Filter filter) { - this.filter = filter; - } - - public Filter getFilter() { - return filter; - } - - public void setFilter(Filter filter) { - this.filter = filter; - } - - // Subclass should override to do something other the simply delegate. - @Override - public boolean filter(T obj) { - return filter.filter(obj); - } - - // Subclass should override to do something other the simply delegate. - @Override - public String toString() { - return filter.toString(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +/** + * A base class for Filters which implements behavior using delegation to an + * underlying filter. + * + * @param + * The underlying type on which the filter applies. + */ +public abstract class AbstractDelegateFilter implements Filter { + protected Filter filter; + + public AbstractDelegateFilter() { + } + + public AbstractDelegateFilter(Filter filter) { + this.filter = filter; + } + + public Filter getFilter() { + return filter; + } + + public void setFilter(Filter filter) { + this.filter = filter; + } + + // Subclass should override to do something other the simply delegate. + @Override + public boolean filter(T obj) { + return filter.filter(obj); + } + + // Subclass should override to do something other the simply delegate. + @Override + public String toString() { + return filter.toString(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AndFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AndFilter.java index 1a6076c9c2..01f388f175 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AndFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/AndFilter.java @@ -1,39 +1,39 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -/** - * A logical AND of a list of Filters. This implementation is short circuiting. - * - * @param - * The underlying type on which the filter applies. - */ -public class AndFilter extends AbstractCompoundFilter { - - public AndFilter() { - super(); - } - - public AndFilter(Filter... filters) { - super(filters); - } - - @Override - public boolean filter(T obj) { - boolean match = true; - for (Filter filter : filters) { - if (!filter.filter(obj)) { - match = false; - break; - } - } - return match; - } - - @Override - protected String getOperator() { - return "and"; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +/** + * A logical AND of a list of Filters. This implementation is short circuiting. + * + * @param + * The underlying type on which the filter applies. + */ +public class AndFilter extends AbstractCompoundFilter { + + public AndFilter() { + super(); + } + + public AndFilter(Filter... filters) { + super(filters); + } + + @Override + public boolean filter(T obj) { + boolean match = true; + for (Filter filter : filters) { + if (!filter.filter(obj)) { + match = false; + break; + } + } + return match; + } + + @Override + protected String getOperator() { + return "and"; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/DirectoryFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/DirectoryFilter.java index 2e377de150..754a34f9dd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/DirectoryFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/DirectoryFilter.java @@ -1,27 +1,27 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -import java.io.File; - -/** - * Directory filter. - */ -public final class DirectoryFilter implements Filter { - public static final DirectoryFilter INSTANCE = new DirectoryFilter(); - - private DirectoryFilter() { - } - - @Override - public boolean filter(File file) { - return file.isDirectory(); - } - - @Override - public String toString() { - return "is Directory"; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +import java.io.File; + +/** + * Directory filter. + */ +public final class DirectoryFilter implements Filter { + public static final DirectoryFilter INSTANCE = new DirectoryFilter(); + + private DirectoryFilter() { + } + + @Override + public boolean filter(File file) { + return file.isDirectory(); + } + + @Override + public String toString() { + return "is Directory"; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/FileExtensionFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/FileExtensionFilter.java index 252d6adab0..f0b18afc68 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/FileExtensionFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/FileExtensionFilter.java @@ -1,47 +1,47 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -import java.io.File; - -public class FileExtensionFilter implements Filter { - protected final String[] extensions; - protected final boolean ignoreCase; - - /** - * Matches any files with the given extensions, ignoring case - */ - public FileExtensionFilter(String... extensions) { - this(true, extensions); - } - - /** - * Matches any files with the given extensions, optionally ignoring case. - */ - public FileExtensionFilter(boolean ignoreCase, String... extensions) { - this.extensions = extensions; - this.ignoreCase = ignoreCase; - if (ignoreCase) { - for (int i = 0; i < this.extensions.length; i++) { - this.extensions[i] = this.extensions[i].toUpperCase(); - } - } - } - - @Override - public boolean filter(File file) { - boolean accept = extensions == null; - if (!accept) { - for (String extension : extensions) { - String name = file.getName(); - if (ignoreCase ? name.toUpperCase().endsWith(extension) : name.endsWith(extension)) { - accept = true; - break; - } - } - } - return accept; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +import java.io.File; + +public class FileExtensionFilter implements Filter { + protected final String[] extensions; + protected final boolean ignoreCase; + + /** + * Matches any files with the given extensions, ignoring case + */ + public FileExtensionFilter(String... extensions) { + this(true, extensions); + } + + /** + * Matches any files with the given extensions, optionally ignoring case. + */ + public FileExtensionFilter(boolean ignoreCase, String... extensions) { + this.extensions = extensions; + this.ignoreCase = ignoreCase; + if (ignoreCase) { + for (int i = 0; i < this.extensions.length; i++) { + this.extensions[i] = this.extensions[i].toUpperCase(); + } + } + } + + @Override + public boolean filter(File file) { + boolean accept = extensions == null; + if (!accept) { + for (String extension : extensions) { + String name = file.getName(); + if (ignoreCase ? name.toUpperCase().endsWith(extension) : name.endsWith(extension)) { + accept = true; + break; + } + } + } + return accept; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filter.java index de6364d2aa..f0f159799b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filter.java @@ -1,15 +1,15 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -/** - * A Filter interface, used for filtering arbitrary objects. - * - * @param - * The underlying type on which the filter applies. - */ -public interface Filter { - boolean filter(T obj); -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +/** + * A Filter interface, used for filtering arbitrary objects. + * + * @param + * The underlying type on which the filter applies. + */ +public interface Filter { + boolean filter(T obj); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filters.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filters.java index c8b63d84ba..9e8fecd309 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/Filters.java @@ -1,237 +1,237 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -import java.io.File; -import java.io.FilenameFilter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * Utility class for working with Filters. Contains builder style methods, apply - * methods, as well as mechanisms for adapting Filters and FilenameFilters. - */ -public class Filters { - - private Filters() { } - - /** - * Filter a given Collection. - * - * @param - * Type of the Collection. - * @param filter - * A Filter upon the Type of objects in the Collection. - * @param collection - * The Collection to filter. - * @return A List containing only those objects for which the Filter - * returned true. - */ - public static List filter(Filter filter, Collection collection) { - List list = new ArrayList<>(); - for (T obj : collection) { - if (filter.filter(obj)) { - list.add(obj); - } - } - return list; - } - - /** - * Get a File Filter for files with the given extensions, ignoring case. - * - * @param extensions - * The extensions to filter. - * @return A File Filter. - */ - public static Filter getFileExtensionFilter(String... extensions) { - return new FileExtensionFilter(extensions); - } - - /** - * Get a File Filter for directories. - * - * @return A File Filter. - */ - public static Filter getDirectoryFilter() { - return DirectoryFilter.INSTANCE; - } - - /** - * Get a File Filter for directories or for files with the given extensions, - * ignoring case. - * - * @param extensions - * The extensions to filter. - * @return A File Filter. - */ - public static Filter getFileExtensionOrDirectoryFilter(String... extensions) { - return new OrFilter<>(getFileExtensionFilter(extensions), getDirectoryFilter()); - } - - /** - * Given a String Filter, expose as a File Filter. The File paths are - * normalized to a standard pattern using / as a path separator - * which can be used cross platform easily in a regular expression based - * String Filter. - * - * @param filter - * A String Filter. - * @return A File Filter. - */ - public static Filter toNormalizedFileFilter(final Filter filter) { - return new Filter() { - @Override - public boolean filter(File file) { - String path = file.getPath(); - path = path.replace('\\', '/'); - return filter.filter(path); - } - - @Override - public String toString() { - return filter.toString(); - } - }; - } - - /** - * Given a String Filter, expose as a Filter on another type. The - * toString() method is called on the objects of the other type - * and delegated to the String Filter. - * - * @param - * The desired type. - * @param filter - * The existing String Filter. - * @return A Filter on the desired type. - */ - public static Filter fromStringFilter(final Filter filter) { - return new Filter() { - @Override - public boolean filter(T obj) { - return filter.filter(obj.toString()); - } - - @Override - public String toString() { - return filter.toString(); - } - }; - } - - /** - * Given a File Filter, expose as a FilenameFilter. - * - * @param filter - * The File Filter. - * @return A FilenameFilter. - */ - public static FilenameFilter toFilenameFilter(final Filter filter) { - return new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return filter.filter(new File(dir, name)); - } - - @Override - public String toString() { - return filter.toString(); - } - }; - } - - /** - * Given a FilenameFilter, expose as a File Filter. - * - * @param filter - * The FilenameFilter. - * @return A File Filter. - */ - public static Filter toFileFilter(final FilenameFilter filter) { - return new Filter() { - @Override - public boolean filter(File file) { - return filter.accept(file.getParentFile(), file.getName()); - } - - @Override - public String toString() { - return filter.toString(); - } - }; - } - - /** - * Construct a String Filter using set of include and exclude regular - * expressions. If there are no include regular expressions provide, then a - * regular expression is added which matches every String by default. A - * String is included as long as it matches an include regular expression - * and does not match an exclude regular expression. - *

- * In other words, exclude patterns override include patterns. - * - * @param includeRegexes - * The include regular expressions. May be null. - * @param excludeRegexes - * The exclude regular expressions. May be null. - * @return A String Filter. - */ - public static Filter buildRegexFilterExcludeOverInclude(List includeRegexes, - List excludeRegexes) { - OrFilter includeFilter = new OrFilter<>(); - if (includeRegexes == null || includeRegexes.isEmpty()) { - includeFilter.addFilter(new RegexStringFilter(".*")); - } else { - for (String includeRegex : includeRegexes) { - includeFilter.addFilter(new RegexStringFilter(includeRegex)); - } - } - - OrFilter excludeFilter = new OrFilter<>(); - if (excludeRegexes != null) { - for (String excludeRegex : excludeRegexes) { - excludeFilter.addFilter(new RegexStringFilter(excludeRegex)); - } - } - - return new AndFilter<>(includeFilter, new NotFilter<>(excludeFilter)); - } - - /** - * Construct a String Filter using set of include and exclude regular - * expressions. If there are no include regular expressions provide, then a - * regular expression is added which matches every String by default. A - * String is included as long as the case that there is an include which - * matches or there is not an exclude which matches. - *

- * In other words, include patterns override exclude patterns. - * - * @param includeRegexes - * The include regular expressions. May be null. - * @param excludeRegexes - * The exclude regular expressions. May be null. - * @return A String Filter. - */ - public static Filter buildRegexFilterIncludeOverExclude(List includeRegexes, - List excludeRegexes) { - OrFilter includeFilter = new OrFilter<>(); - if (includeRegexes != null) { - for (String includeRegex : includeRegexes) { - includeFilter.addFilter(new RegexStringFilter(includeRegex)); - } - } - - OrFilter excludeFilter = new OrFilter<>(); - if (excludeRegexes != null) { - for (String excludeRegex : excludeRegexes) { - excludeFilter.addFilter(new RegexStringFilter(excludeRegex)); - } - } - - return new OrFilter<>(includeFilter, new NotFilter<>(excludeFilter)); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Utility class for working with Filters. Contains builder style methods, apply + * methods, as well as mechanisms for adapting Filters and FilenameFilters. + */ +public class Filters { + + private Filters() { } + + /** + * Filter a given Collection. + * + * @param + * Type of the Collection. + * @param filter + * A Filter upon the Type of objects in the Collection. + * @param collection + * The Collection to filter. + * @return A List containing only those objects for which the Filter + * returned true. + */ + public static List filter(Filter filter, Collection collection) { + List list = new ArrayList<>(); + for (T obj : collection) { + if (filter.filter(obj)) { + list.add(obj); + } + } + return list; + } + + /** + * Get a File Filter for files with the given extensions, ignoring case. + * + * @param extensions + * The extensions to filter. + * @return A File Filter. + */ + public static Filter getFileExtensionFilter(String... extensions) { + return new FileExtensionFilter(extensions); + } + + /** + * Get a File Filter for directories. + * + * @return A File Filter. + */ + public static Filter getDirectoryFilter() { + return DirectoryFilter.INSTANCE; + } + + /** + * Get a File Filter for directories or for files with the given extensions, + * ignoring case. + * + * @param extensions + * The extensions to filter. + * @return A File Filter. + */ + public static Filter getFileExtensionOrDirectoryFilter(String... extensions) { + return new OrFilter<>(getFileExtensionFilter(extensions), getDirectoryFilter()); + } + + /** + * Given a String Filter, expose as a File Filter. The File paths are + * normalized to a standard pattern using / as a path separator + * which can be used cross platform easily in a regular expression based + * String Filter. + * + * @param filter + * A String Filter. + * @return A File Filter. + */ + public static Filter toNormalizedFileFilter(final Filter filter) { + return new Filter() { + @Override + public boolean filter(File file) { + String path = file.getPath(); + path = path.replace('\\', '/'); + return filter.filter(path); + } + + @Override + public String toString() { + return filter.toString(); + } + }; + } + + /** + * Given a String Filter, expose as a Filter on another type. The + * toString() method is called on the objects of the other type + * and delegated to the String Filter. + * + * @param + * The desired type. + * @param filter + * The existing String Filter. + * @return A Filter on the desired type. + */ + public static Filter fromStringFilter(final Filter filter) { + return new Filter() { + @Override + public boolean filter(T obj) { + return filter.filter(obj.toString()); + } + + @Override + public String toString() { + return filter.toString(); + } + }; + } + + /** + * Given a File Filter, expose as a FilenameFilter. + * + * @param filter + * The File Filter. + * @return A FilenameFilter. + */ + public static FilenameFilter toFilenameFilter(final Filter filter) { + return new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return filter.filter(new File(dir, name)); + } + + @Override + public String toString() { + return filter.toString(); + } + }; + } + + /** + * Given a FilenameFilter, expose as a File Filter. + * + * @param filter + * The FilenameFilter. + * @return A File Filter. + */ + public static Filter toFileFilter(final FilenameFilter filter) { + return new Filter() { + @Override + public boolean filter(File file) { + return filter.accept(file.getParentFile(), file.getName()); + } + + @Override + public String toString() { + return filter.toString(); + } + }; + } + + /** + * Construct a String Filter using set of include and exclude regular + * expressions. If there are no include regular expressions provide, then a + * regular expression is added which matches every String by default. A + * String is included as long as it matches an include regular expression + * and does not match an exclude regular expression. + *

+ * In other words, exclude patterns override include patterns. + * + * @param includeRegexes + * The include regular expressions. May be null. + * @param excludeRegexes + * The exclude regular expressions. May be null. + * @return A String Filter. + */ + public static Filter buildRegexFilterExcludeOverInclude(List includeRegexes, + List excludeRegexes) { + OrFilter includeFilter = new OrFilter<>(); + if (includeRegexes == null || includeRegexes.isEmpty()) { + includeFilter.addFilter(new RegexStringFilter(".*")); + } else { + for (String includeRegex : includeRegexes) { + includeFilter.addFilter(new RegexStringFilter(includeRegex)); + } + } + + OrFilter excludeFilter = new OrFilter<>(); + if (excludeRegexes != null) { + for (String excludeRegex : excludeRegexes) { + excludeFilter.addFilter(new RegexStringFilter(excludeRegex)); + } + } + + return new AndFilter<>(includeFilter, new NotFilter<>(excludeFilter)); + } + + /** + * Construct a String Filter using set of include and exclude regular + * expressions. If there are no include regular expressions provide, then a + * regular expression is added which matches every String by default. A + * String is included as long as the case that there is an include which + * matches or there is not an exclude which matches. + *

+ * In other words, include patterns override exclude patterns. + * + * @param includeRegexes + * The include regular expressions. May be null. + * @param excludeRegexes + * The exclude regular expressions. May be null. + * @return A String Filter. + */ + public static Filter buildRegexFilterIncludeOverExclude(List includeRegexes, + List excludeRegexes) { + OrFilter includeFilter = new OrFilter<>(); + if (includeRegexes != null) { + for (String includeRegex : includeRegexes) { + includeFilter.addFilter(new RegexStringFilter(includeRegex)); + } + } + + OrFilter excludeFilter = new OrFilter<>(); + if (excludeRegexes != null) { + for (String excludeRegex : excludeRegexes) { + excludeFilter.addFilter(new RegexStringFilter(excludeRegex)); + } + } + + return new OrFilter<>(includeFilter, new NotFilter<>(excludeFilter)); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/NotFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/NotFilter.java index 31d3aa81a9..2e73875b27 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/NotFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/NotFilter.java @@ -1,31 +1,31 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -/** - * A logical NEGATION of a Filter. - * - * @param - * The underlying type on which the filter applies. - */ -public class NotFilter extends AbstractDelegateFilter { - public NotFilter() { - super(); - } - - public NotFilter(Filter filter) { - super(filter); - } - - @Override - public boolean filter(T obj) { - return !filter.filter(obj); - } - - @Override - public String toString() { - return "not (" + filter + ")"; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +/** + * A logical NEGATION of a Filter. + * + * @param + * The underlying type on which the filter applies. + */ +public class NotFilter extends AbstractDelegateFilter { + public NotFilter() { + super(); + } + + public NotFilter(Filter filter) { + super(filter); + } + + @Override + public boolean filter(T obj) { + return !filter.filter(obj); + } + + @Override + public String toString() { + return "not (" + filter + ")"; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/OrFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/OrFilter.java index 571f3c68be..f5c46f57d3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/OrFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/OrFilter.java @@ -1,39 +1,39 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -/** - * A logical OR of a list of Filters. This implementation is short circuiting. - * - * @param - * The underlying type on which the filter applies. - */ -public class OrFilter extends AbstractCompoundFilter { - - public OrFilter() { - super(); - } - - public OrFilter(Filter... filters) { - super(filters); - } - - @Override - public boolean filter(T obj) { - boolean match = false; - for (Filter filter : filters) { - if (filter.filter(obj)) { - match = true; - break; - } - } - return match; - } - - @Override - protected String getOperator() { - return "or"; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +/** + * A logical OR of a list of Filters. This implementation is short circuiting. + * + * @param + * The underlying type on which the filter applies. + */ +public class OrFilter extends AbstractCompoundFilter { + + public OrFilter() { + super(); + } + + public OrFilter(Filter... filters) { + super(filters); + } + + @Override + public boolean filter(T obj) { + boolean match = false; + for (Filter filter : filters) { + if (filter.filter(obj)) { + match = true; + break; + } + } + return match; + } + + @Override + protected String getOperator() { + return "or"; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/RegexStringFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/RegexStringFilter.java index b655aaf0a6..606416d549 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/RegexStringFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/filter/RegexStringFilter.java @@ -1,94 +1,94 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * A filter which uses a regular expression to match Strings. Invalid regular - * expressions will match nothing. - *

- * Because regular expression matching is slow, and a common usage is to match - * some sort of relative file path, the regular expression is checked to see if - * it can be evaluated using much faster calls to - * {@link String#endsWith(String)}. - */ -public class RegexStringFilter implements Filter { - /** - * Matches regular expressions begin with an optional {@code ^}, then - * {@code .*}, then a literal path, with an optional file extension, and - * finally an optional {@code $} at the end. The {@code .} in the extension - * may or may not be preceded by a {@code \} escape. The literal path - * portion is determine by the absence of any of the following characters: - * \ [ ( . * ? + | { $ - * - * There are two capturing groups in the expression. The first is for the - * literal path. The second is for the file extension, without the escaping. - * The concatenation of these two captures creates the {@link String} which - * can be used with {@link String#endsWith(String)}. - * - * For ease of reference, the non-Java escaped form of this pattern is: - * \^?\.\*([^\\\[\(\.\*\?\+\|\{\$]+)(?:\\?(\.\w+))?\$? - */ - private static final Pattern ENDS_WITH = Pattern - .compile("\\^?\\.\\*([^\\\\\\[\\(\\.\\*\\?\\+\\|\\{\\$]+)(?:\\\\?(\\.\\w+))?\\$?"); - - protected String regex; - protected Pattern pattern; - protected String endsWith; - - public RegexStringFilter(String regex) { - this.regex = regex; - optimize(); - } - - public String getRegex() { - return this.regex; - } - - public String getEndsWith() { - return this.endsWith; - } - - protected void optimize() { - final Matcher matcher = ENDS_WITH.matcher(this.regex); - if (matcher.matches()) { - final String literalPath = matcher.group(1); - final String fileExtension = matcher.group(2); - if (fileExtension != null) { - this.endsWith = literalPath + fileExtension; - } else { - this.endsWith = literalPath; - } - } else { - try { - this.pattern = Pattern.compile(this.regex); - } catch (PatternSyntaxException e) { - // If the regular expression is invalid, then pattern will be - // null. - } - } - } - - @Override - public boolean filter(String obj) { - if (this.endsWith != null) { - return obj.endsWith(this.endsWith); - } else if (this.pattern != null) { - return this.pattern.matcher(obj).matches(); - } else { - // The regular expression must have been bad, so it will match - // nothing. - return false; - } - } - - @Override - public String toString() { - return "matches " + this.regex; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * A filter which uses a regular expression to match Strings. Invalid regular + * expressions will match nothing. + *

+ * Because regular expression matching is slow, and a common usage is to match + * some sort of relative file path, the regular expression is checked to see if + * it can be evaluated using much faster calls to + * {@link String#endsWith(String)}. + */ +public class RegexStringFilter implements Filter { + /** + * Matches regular expressions begin with an optional {@code ^}, then + * {@code .*}, then a literal path, with an optional file extension, and + * finally an optional {@code $} at the end. The {@code .} in the extension + * may or may not be preceded by a {@code \} escape. The literal path + * portion is determine by the absence of any of the following characters: + * \ [ ( . * ? + | { $ + * + * There are two capturing groups in the expression. The first is for the + * literal path. The second is for the file extension, without the escaping. + * The concatenation of these two captures creates the {@link String} which + * can be used with {@link String#endsWith(String)}. + * + * For ease of reference, the non-Java escaped form of this pattern is: + * \^?\.\*([^\\\[\(\.\*\?\+\|\{\$]+)(?:\\?(\.\w+))?\$? + */ + private static final Pattern ENDS_WITH = Pattern + .compile("\\^?\\.\\*([^\\\\\\[\\(\\.\\*\\?\\+\\|\\{\\$]+)(?:\\\\?(\\.\\w+))?\\$?"); + + protected String regex; + protected Pattern pattern; + protected String endsWith; + + public RegexStringFilter(String regex) { + this.regex = regex; + optimize(); + } + + public String getRegex() { + return this.regex; + } + + public String getEndsWith() { + return this.endsWith; + } + + protected void optimize() { + final Matcher matcher = ENDS_WITH.matcher(this.regex); + if (matcher.matches()) { + final String literalPath = matcher.group(1); + final String fileExtension = matcher.group(2); + if (fileExtension != null) { + this.endsWith = literalPath + fileExtension; + } else { + this.endsWith = literalPath; + } + } else { + try { + this.pattern = Pattern.compile(this.regex); + } catch (PatternSyntaxException e) { + // If the regular expression is invalid, then pattern will be + // null. + } + } + } + + @Override + public boolean filter(String obj) { + if (this.endsWith != null) { + return obj.endsWith(this.endsWith); + } else if (this.pattern != null) { + return this.pattern.matcher(obj).matches(); + } else { + // The regular expression must have been bad, so it will match + // nothing. + return false; + } + } + + @Override + public String toString() { + return "matches " + this.regex; + } +} diff --git a/pmd-core/src/main/resources/rulesets/internal/all-ecmascript.xml b/pmd-core/src/main/resources/rulesets/internal/all-ecmascript.xml index 589012b715..f83e1c08f0 100644 --- a/pmd-core/src/main/resources/rulesets/internal/all-ecmascript.xml +++ b/pmd-core/src/main/resources/rulesets/internal/all-ecmascript.xml @@ -1,12 +1,12 @@ - - - - Every ECMAScript Rule in PMD - - - - - + + + + Every ECMAScript Rule in PMD + + + + + diff --git a/pmd-core/src/main/resources/rulesets/internal/all-java.xml b/pmd-core/src/main/resources/rulesets/internal/all-java.xml index 5902958e04..c5c86dda10 100644 --- a/pmd-core/src/main/resources/rulesets/internal/all-java.xml +++ b/pmd-core/src/main/resources/rulesets/internal/all-java.xml @@ -1,35 +1,35 @@ - - - - Every Java Rule in PMD - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Every Java Rule in PMD + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pmd-core/src/main/resources/rulesets/internal/dogfood-goal.xml b/pmd-core/src/main/resources/rulesets/internal/dogfood-goal.xml index cbc54cc09b..ff49b78093 100644 --- a/pmd-core/src/main/resources/rulesets/internal/dogfood-goal.xml +++ b/pmd-core/src/main/resources/rulesets/internal/dogfood-goal.xml @@ -1,10 +1,10 @@ - - - Dogfood goal, delete this when we reach it. - + + + Dogfood goal, delete this when we reach it. + .*net/sourceforge/pmd/lang/ast/JavaCharStream.java .*net/sourceforge/pmd/lang/ast/SimpleCharStream.java @@ -17,103 +17,103 @@ .*lang/(java|jsp|cpp)/ast/JJT.*ParserState.java .*lang/(java|jsp|cpp)/ast/ParseException.java .*lang/(java|jsp|cpp)/ast/Token.java - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pmd-core/src/main/resources/rulesets/releases/41.xml b/pmd-core/src/main/resources/rulesets/releases/41.xml index 9c90942dde..d8308b0d75 100644 --- a/pmd-core/src/main/resources/rulesets/releases/41.xml +++ b/pmd-core/src/main/resources/rulesets/releases/41.xml @@ -16,9 +16,9 @@ This ruleset contains links to rules that are new in PMD v4.1 - - - + + + diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java index 6b30a23ceb..98f9829189 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java @@ -1,201 +1,201 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Properties; - -import org.junit.Test; - -import net.sourceforge.pmd.cache.FileAnalysisCache; -import net.sourceforge.pmd.cache.NoopAnalysisCache; -import net.sourceforge.pmd.renderers.CSVRenderer; -import net.sourceforge.pmd.renderers.Renderer; -import net.sourceforge.pmd.util.ClasspathClassLoader; - -public class ConfigurationTest { - - @Test - public void testSuppressMarker() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default suppress marker", PMD.SUPPRESS_MARKER, configuration.getSuppressMarker()); - configuration.setSuppressMarker("CUSTOM_MARKER"); - assertEquals("Changed suppress marker", "CUSTOM_MARKER", configuration.getSuppressMarker()); - } - - @Test - public void testThreads() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default threads", Runtime.getRuntime().availableProcessors(), configuration.getThreads()); - configuration.setThreads(0); - assertEquals("Changed threads", 0, configuration.getThreads()); - } - - @Test - public void testClassLoader() throws IOException { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default ClassLoader", PMDConfiguration.class.getClassLoader(), configuration.getClassLoader()); - configuration.prependClasspath("some.jar"); - assertEquals("Prepended ClassLoader class", ClasspathClassLoader.class, - configuration.getClassLoader().getClass()); - URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); - assertEquals("urls length", 1, urls.length); - assertTrue("url[0]", urls[0].toString().endsWith("/some.jar")); - assertEquals("parent classLoader", PMDConfiguration.class.getClassLoader(), - configuration.getClassLoader().getParent()); - configuration.setClassLoader(null); - assertEquals("Revert to default ClassLoader", PMDConfiguration.class.getClassLoader(), - configuration.getClassLoader()); - } - - @Test - public void testRuleSets() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default RuleSets", null, configuration.getRuleSets()); - configuration.setRuleSets("/rulesets/basic.xml"); - assertEquals("Changed RuleSets", "/rulesets/basic.xml", configuration.getRuleSets()); - } - - @Test - public void testMinimumPriority() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default minimum priority", RulePriority.LOW, configuration.getMinimumPriority()); - configuration.setMinimumPriority(RulePriority.HIGH); - assertEquals("Changed minimum priority", RulePriority.HIGH, configuration.getMinimumPriority()); - } - - @Test - public void testSourceEncoding() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default source encoding", System.getProperty("file.encoding"), configuration.getSourceEncoding()); - configuration.setSourceEncoding("some_other_encoding"); - assertEquals("Changed source encoding", "some_other_encoding", configuration.getSourceEncoding()); - } - - @Test - public void testInputPaths() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default input paths", null, configuration.getInputPaths()); - configuration.setInputPaths("a,b,c"); - assertEquals("Changed input paths", "a,b,c", configuration.getInputPaths()); - } - - @Test - public void testReportShortNames() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report short names", false, configuration.isReportShortNames()); - configuration.setReportShortNames(true); - assertEquals("Changed report short names", true, configuration.isReportShortNames()); - } - - @Test - public void testReportFormat() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report format", null, configuration.getReportFormat()); - configuration.setReportFormat("csv"); - assertEquals("Changed report format", "csv", configuration.getReportFormat()); - } - - @Test - public void testCreateRenderer() { - PMDConfiguration configuration = new PMDConfiguration(); - configuration.setReportFormat("csv"); - Renderer renderer = configuration.createRenderer(); - assertEquals("Renderer class", CSVRenderer.class, renderer.getClass()); - assertEquals("Default renderer show suppressed violations", false, renderer.isShowSuppressedViolations()); - - configuration.setShowSuppressedViolations(true); - renderer = configuration.createRenderer(); - assertEquals("Renderer class", CSVRenderer.class, renderer.getClass()); - assertEquals("Changed renderer show suppressed violations", true, renderer.isShowSuppressedViolations()); - } - - @Test - public void testReportFile() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report file", null, configuration.getReportFile()); - configuration.setReportFile("somefile"); - assertEquals("Changed report file", "somefile", configuration.getReportFile()); - } - - @Test - public void testShowSuppressedViolations() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default show suppressed violations", false, configuration.isShowSuppressedViolations()); - configuration.setShowSuppressedViolations(true); - assertEquals("Changed show suppressed violations", true, configuration.isShowSuppressedViolations()); - } - - @Test - public void testReportProperties() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report properties size", 0, configuration.getReportProperties().size()); - configuration.getReportProperties().put("key", "value"); - assertEquals("Changed report properties size", 1, configuration.getReportProperties().size()); - assertEquals("Changed report properties value", "value", configuration.getReportProperties().get("key")); - configuration.setReportProperties(new Properties()); - assertEquals("Replaced report properties size", 0, configuration.getReportProperties().size()); - } - - @Test - public void testDebug() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default debug", false, configuration.isDebug()); - configuration.setDebug(true); - assertEquals("Changed debug", true, configuration.isDebug()); - } - - @Test - public void testStressTest() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default stress test", false, configuration.isStressTest()); - configuration.setStressTest(true); - assertEquals("Changed stress test", true, configuration.isStressTest()); - } - - @Test - public void testBenchmark() { - PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default benchmark", false, configuration.isBenchmark()); - configuration.setBenchmark(true); - assertEquals("Changed benchmark", true, configuration.isBenchmark()); - } - - @Test - public void testAnalysisCache() throws IOException { - final PMDConfiguration configuration = new PMDConfiguration(); - assertNotNull("Default cache is null", configuration.getAnalysisCache()); - assertTrue("Default cache is not a noop", configuration.getAnalysisCache() instanceof NoopAnalysisCache); - configuration.setAnalysisCache(null); - assertNotNull("Default cache was set to null", configuration.getAnalysisCache()); - - final File cacheFile = File.createTempFile("pmd-", ".cache"); - cacheFile.deleteOnExit(); - final FileAnalysisCache analysisCache = new FileAnalysisCache(cacheFile); - configuration.setAnalysisCache(analysisCache); - assertSame("Confgured cache not stored", analysisCache, configuration.getAnalysisCache()); - } - - @Test - public void testAnalysisCacheLocation() throws IOException { - final PMDConfiguration configuration = new PMDConfiguration(); - - configuration.setAnalysisCacheLocation(null); - assertNotNull("Null cache location accepted", configuration.getAnalysisCache()); - assertTrue("Null cache location accepted", configuration.getAnalysisCache() instanceof NoopAnalysisCache); - - configuration.setAnalysisCacheLocation("pmd.cache"); - assertNotNull("Not null cache location produces null cache", configuration.getAnalysisCache()); - assertTrue("File cache location doesn't produce a file cache", - configuration.getAnalysisCache() instanceof FileAnalysisCache); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.junit.Test; + +import net.sourceforge.pmd.cache.FileAnalysisCache; +import net.sourceforge.pmd.cache.NoopAnalysisCache; +import net.sourceforge.pmd.renderers.CSVRenderer; +import net.sourceforge.pmd.renderers.Renderer; +import net.sourceforge.pmd.util.ClasspathClassLoader; + +public class ConfigurationTest { + + @Test + public void testSuppressMarker() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default suppress marker", PMD.SUPPRESS_MARKER, configuration.getSuppressMarker()); + configuration.setSuppressMarker("CUSTOM_MARKER"); + assertEquals("Changed suppress marker", "CUSTOM_MARKER", configuration.getSuppressMarker()); + } + + @Test + public void testThreads() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default threads", Runtime.getRuntime().availableProcessors(), configuration.getThreads()); + configuration.setThreads(0); + assertEquals("Changed threads", 0, configuration.getThreads()); + } + + @Test + public void testClassLoader() throws IOException { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default ClassLoader", PMDConfiguration.class.getClassLoader(), configuration.getClassLoader()); + configuration.prependClasspath("some.jar"); + assertEquals("Prepended ClassLoader class", ClasspathClassLoader.class, + configuration.getClassLoader().getClass()); + URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); + assertEquals("urls length", 1, urls.length); + assertTrue("url[0]", urls[0].toString().endsWith("/some.jar")); + assertEquals("parent classLoader", PMDConfiguration.class.getClassLoader(), + configuration.getClassLoader().getParent()); + configuration.setClassLoader(null); + assertEquals("Revert to default ClassLoader", PMDConfiguration.class.getClassLoader(), + configuration.getClassLoader()); + } + + @Test + public void testRuleSets() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default RuleSets", null, configuration.getRuleSets()); + configuration.setRuleSets("/rulesets/basic.xml"); + assertEquals("Changed RuleSets", "/rulesets/basic.xml", configuration.getRuleSets()); + } + + @Test + public void testMinimumPriority() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default minimum priority", RulePriority.LOW, configuration.getMinimumPriority()); + configuration.setMinimumPriority(RulePriority.HIGH); + assertEquals("Changed minimum priority", RulePriority.HIGH, configuration.getMinimumPriority()); + } + + @Test + public void testSourceEncoding() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default source encoding", System.getProperty("file.encoding"), configuration.getSourceEncoding()); + configuration.setSourceEncoding("some_other_encoding"); + assertEquals("Changed source encoding", "some_other_encoding", configuration.getSourceEncoding()); + } + + @Test + public void testInputPaths() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default input paths", null, configuration.getInputPaths()); + configuration.setInputPaths("a,b,c"); + assertEquals("Changed input paths", "a,b,c", configuration.getInputPaths()); + } + + @Test + public void testReportShortNames() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default report short names", false, configuration.isReportShortNames()); + configuration.setReportShortNames(true); + assertEquals("Changed report short names", true, configuration.isReportShortNames()); + } + + @Test + public void testReportFormat() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default report format", null, configuration.getReportFormat()); + configuration.setReportFormat("csv"); + assertEquals("Changed report format", "csv", configuration.getReportFormat()); + } + + @Test + public void testCreateRenderer() { + PMDConfiguration configuration = new PMDConfiguration(); + configuration.setReportFormat("csv"); + Renderer renderer = configuration.createRenderer(); + assertEquals("Renderer class", CSVRenderer.class, renderer.getClass()); + assertEquals("Default renderer show suppressed violations", false, renderer.isShowSuppressedViolations()); + + configuration.setShowSuppressedViolations(true); + renderer = configuration.createRenderer(); + assertEquals("Renderer class", CSVRenderer.class, renderer.getClass()); + assertEquals("Changed renderer show suppressed violations", true, renderer.isShowSuppressedViolations()); + } + + @Test + public void testReportFile() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default report file", null, configuration.getReportFile()); + configuration.setReportFile("somefile"); + assertEquals("Changed report file", "somefile", configuration.getReportFile()); + } + + @Test + public void testShowSuppressedViolations() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default show suppressed violations", false, configuration.isShowSuppressedViolations()); + configuration.setShowSuppressedViolations(true); + assertEquals("Changed show suppressed violations", true, configuration.isShowSuppressedViolations()); + } + + @Test + public void testReportProperties() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default report properties size", 0, configuration.getReportProperties().size()); + configuration.getReportProperties().put("key", "value"); + assertEquals("Changed report properties size", 1, configuration.getReportProperties().size()); + assertEquals("Changed report properties value", "value", configuration.getReportProperties().get("key")); + configuration.setReportProperties(new Properties()); + assertEquals("Replaced report properties size", 0, configuration.getReportProperties().size()); + } + + @Test + public void testDebug() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default debug", false, configuration.isDebug()); + configuration.setDebug(true); + assertEquals("Changed debug", true, configuration.isDebug()); + } + + @Test + public void testStressTest() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default stress test", false, configuration.isStressTest()); + configuration.setStressTest(true); + assertEquals("Changed stress test", true, configuration.isStressTest()); + } + + @Test + public void testBenchmark() { + PMDConfiguration configuration = new PMDConfiguration(); + assertEquals("Default benchmark", false, configuration.isBenchmark()); + configuration.setBenchmark(true); + assertEquals("Changed benchmark", true, configuration.isBenchmark()); + } + + @Test + public void testAnalysisCache() throws IOException { + final PMDConfiguration configuration = new PMDConfiguration(); + assertNotNull("Default cache is null", configuration.getAnalysisCache()); + assertTrue("Default cache is not a noop", configuration.getAnalysisCache() instanceof NoopAnalysisCache); + configuration.setAnalysisCache(null); + assertNotNull("Default cache was set to null", configuration.getAnalysisCache()); + + final File cacheFile = File.createTempFile("pmd-", ".cache"); + cacheFile.deleteOnExit(); + final FileAnalysisCache analysisCache = new FileAnalysisCache(cacheFile); + configuration.setAnalysisCache(analysisCache); + assertSame("Confgured cache not stored", analysisCache, configuration.getAnalysisCache()); + } + + @Test + public void testAnalysisCacheLocation() throws IOException { + final PMDConfiguration configuration = new PMDConfiguration(); + + configuration.setAnalysisCacheLocation(null); + assertNotNull("Null cache location accepted", configuration.getAnalysisCache()); + assertTrue("Null cache location accepted", configuration.getAnalysisCache() instanceof NoopAnalysisCache); + + configuration.setAnalysisCacheLocation("pmd.cache"); + assertNotNull("Not null cache location produces null cache", configuration.getAnalysisCache()); + assertTrue("File cache location doesn't produce a file cache", + configuration.getAnalysisCache() instanceof FileAnalysisCache); + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java index 6417e3f5d0..5bc406b338 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java @@ -1,187 +1,187 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.Dummy2LanguageModule; -import net.sourceforge.pmd.lang.DummyLanguageModule; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.rule.MockRule; -import net.sourceforge.pmd.lang.rule.RuleReference; -import net.sourceforge.pmd.lang.rule.properties.StringProperty; - -public class RuleReferenceTest { - - @Test - public void testRuleSetReference() { - RuleReference ruleReference = new RuleReference(); - RuleSetReference ruleSetReference = new RuleSetReference(); - ruleReference.setRuleSetReference(ruleSetReference); - assertEquals("Not same rule set reference", ruleSetReference, ruleReference.getRuleSetReference()); - } - - @Test - public void testOverride() { - final StringProperty PROPERTY1_DESCRIPTOR = new StringProperty("property1", "Test property", null, 0f); - MockRule rule = new MockRule(); - rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); - rule.setLanguage(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME)); - rule.setName("name1"); - rule.setProperty(PROPERTY1_DESCRIPTOR, "value1"); - rule.setMessage("message1"); - rule.setDescription("description1"); - rule.addExample("example1"); - rule.setExternalInfoUrl("externalInfoUrl1"); - rule.setPriority(RulePriority.HIGH); - - final StringProperty PROPERTY2_DESCRIPTOR = new StringProperty("property2", "Test property", null, 0f); - RuleReference ruleReference = new RuleReference(); - ruleReference.setRule(rule); - ruleReference.definePropertyDescriptor(PROPERTY2_DESCRIPTOR); - ruleReference.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); - ruleReference - .setMinimumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3")); - ruleReference - .setMaximumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7")); - ruleReference.setDeprecated(true); - ruleReference.setName("name2"); - ruleReference.setProperty(PROPERTY1_DESCRIPTOR, "value2"); - ruleReference.setProperty(PROPERTY2_DESCRIPTOR, "value3"); - ruleReference.setMessage("message2"); - ruleReference.setDescription("description2"); - ruleReference.addExample("example2"); - ruleReference.setExternalInfoUrl("externalInfoUrl2"); - ruleReference.setPriority(RulePriority.MEDIUM_HIGH); - - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), - ruleReference.getLanguage()); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), - ruleReference.getOverriddenLanguage()); - - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), - ruleReference.getMinimumLanguageVersion()); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), - ruleReference.getOverriddenMinimumLanguageVersion()); - - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), - ruleReference.getMaximumLanguageVersion()); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), - ruleReference.getOverriddenMaximumLanguageVersion()); - - assertEquals("Override failed", false, ruleReference.getRule().isDeprecated()); - assertEquals("Override failed", true, ruleReference.isDeprecated()); - assertEquals("Override failed", true, ruleReference.isOverriddenDeprecated()); - - assertEquals("Override failed", "name2", ruleReference.getName()); - assertEquals("Override failed", "name2", ruleReference.getOverriddenName()); - - assertEquals("Override failed", "value2", ruleReference.getProperty(PROPERTY1_DESCRIPTOR)); - assertEquals("Override failed", "value3", ruleReference.getProperty(PROPERTY2_DESCRIPTOR)); - assertTrue("Override failed", ruleReference.getPropertyDescriptors().contains(PROPERTY1_DESCRIPTOR)); - assertTrue("Override failed", ruleReference.getPropertyDescriptors().contains(PROPERTY2_DESCRIPTOR)); - assertFalse("Override failed", ruleReference.getOverriddenPropertyDescriptors().contains(PROPERTY1_DESCRIPTOR)); - assertTrue("Override failed", ruleReference.getOverriddenPropertyDescriptors().contains(PROPERTY2_DESCRIPTOR)); - assertTrue("Override failed", - ruleReference.getPropertiesByPropertyDescriptor().containsKey(PROPERTY1_DESCRIPTOR)); - assertTrue("Override failed", - ruleReference.getPropertiesByPropertyDescriptor().containsKey(PROPERTY2_DESCRIPTOR)); - assertTrue("Override failed", - ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(PROPERTY1_DESCRIPTOR)); - assertTrue("Override failed", - ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(PROPERTY2_DESCRIPTOR)); - - assertEquals("Override failed", "message2", ruleReference.getMessage()); - assertEquals("Override failed", "message2", ruleReference.getOverriddenMessage()); - - assertEquals("Override failed", "description2", ruleReference.getDescription()); - assertEquals("Override failed", "description2", ruleReference.getOverriddenDescription()); - - assertEquals("Override failed", 2, ruleReference.getExamples().size()); - assertEquals("Override failed", "example1", ruleReference.getExamples().get(0)); - assertEquals("Override failed", "example2", ruleReference.getExamples().get(1)); - assertEquals("Override failed", "example2", ruleReference.getOverriddenExamples().get(0)); - - assertEquals("Override failed", "externalInfoUrl2", ruleReference.getExternalInfoUrl()); - assertEquals("Override failed", "externalInfoUrl2", ruleReference.getOverriddenExternalInfoUrl()); - - assertEquals("Override failed", RulePriority.MEDIUM_HIGH, ruleReference.getPriority()); - assertEquals("Override failed", RulePriority.MEDIUM_HIGH, ruleReference.getOverriddenPriority()); - } - - @Test - public void testNotOverride() { - final StringProperty PROPERTY1_DESCRIPTOR = new StringProperty("property1", "Test property", null, 0f); - MockRule rule = new MockRule(); - rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); - rule.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); - rule.setMinimumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3")); - rule.setMaximumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7")); - rule.setName("name1"); - rule.setProperty(PROPERTY1_DESCRIPTOR, "value1"); - rule.setMessage("message1"); - rule.setDescription("description1"); - rule.addExample("example1"); - rule.setExternalInfoUrl("externalInfoUrl1"); - rule.setPriority(RulePriority.HIGH); - - RuleReference ruleReference = new RuleReference(); - ruleReference.setRule(rule); - ruleReference.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); - ruleReference - .setMinimumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3")); - ruleReference - .setMaximumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7")); - ruleReference.setDeprecated(false); - ruleReference.setName("name1"); - ruleReference.setProperty(PROPERTY1_DESCRIPTOR, "value1"); - ruleReference.setMessage("message1"); - ruleReference.setDescription("description1"); - ruleReference.addExample("example1"); - ruleReference.setExternalInfoUrl("externalInfoUrl1"); - ruleReference.setPriority(RulePriority.HIGH); - - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), - ruleReference.getLanguage()); - assertNull("Override failed", ruleReference.getOverriddenLanguage()); - - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), - ruleReference.getMinimumLanguageVersion()); - assertNull("Override failed", ruleReference.getOverriddenMinimumLanguageVersion()); - - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), - ruleReference.getMaximumLanguageVersion()); - assertNull("Override failed", ruleReference.getOverriddenMaximumLanguageVersion()); - - assertEquals("Override failed", false, ruleReference.isDeprecated()); - assertNull("Override failed", ruleReference.isOverriddenDeprecated()); - - assertEquals("Override failed", "name1", ruleReference.getName()); - assertNull("Override failed", ruleReference.getOverriddenName()); - - assertEquals("Override failed", "value1", ruleReference.getProperty(PROPERTY1_DESCRIPTOR)); - - assertEquals("Override failed", "message1", ruleReference.getMessage()); - assertNull("Override failed", ruleReference.getOverriddenMessage()); - - assertEquals("Override failed", "description1", ruleReference.getDescription()); - assertNull("Override failed", ruleReference.getOverriddenDescription()); - - assertEquals("Override failed", 1, ruleReference.getExamples().size()); - assertEquals("Override failed", "example1", ruleReference.getExamples().get(0)); - assertNull("Override failed", ruleReference.getOverriddenExamples()); - - assertEquals("Override failed", "externalInfoUrl1", ruleReference.getExternalInfoUrl()); - assertNull("Override failed", ruleReference.getOverriddenExternalInfoUrl()); - - assertEquals("Override failed", RulePriority.HIGH, ruleReference.getPriority()); - assertNull("Override failed", ruleReference.getOverriddenPriority()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.Dummy2LanguageModule; +import net.sourceforge.pmd.lang.DummyLanguageModule; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.rule.MockRule; +import net.sourceforge.pmd.lang.rule.RuleReference; +import net.sourceforge.pmd.lang.rule.properties.StringProperty; + +public class RuleReferenceTest { + + @Test + public void testRuleSetReference() { + RuleReference ruleReference = new RuleReference(); + RuleSetReference ruleSetReference = new RuleSetReference(); + ruleReference.setRuleSetReference(ruleSetReference); + assertEquals("Not same rule set reference", ruleSetReference, ruleReference.getRuleSetReference()); + } + + @Test + public void testOverride() { + final StringProperty PROPERTY1_DESCRIPTOR = new StringProperty("property1", "Test property", null, 0f); + MockRule rule = new MockRule(); + rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); + rule.setLanguage(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME)); + rule.setName("name1"); + rule.setProperty(PROPERTY1_DESCRIPTOR, "value1"); + rule.setMessage("message1"); + rule.setDescription("description1"); + rule.addExample("example1"); + rule.setExternalInfoUrl("externalInfoUrl1"); + rule.setPriority(RulePriority.HIGH); + + final StringProperty PROPERTY2_DESCRIPTOR = new StringProperty("property2", "Test property", null, 0f); + RuleReference ruleReference = new RuleReference(); + ruleReference.setRule(rule); + ruleReference.definePropertyDescriptor(PROPERTY2_DESCRIPTOR); + ruleReference.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); + ruleReference + .setMinimumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3")); + ruleReference + .setMaximumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7")); + ruleReference.setDeprecated(true); + ruleReference.setName("name2"); + ruleReference.setProperty(PROPERTY1_DESCRIPTOR, "value2"); + ruleReference.setProperty(PROPERTY2_DESCRIPTOR, "value3"); + ruleReference.setMessage("message2"); + ruleReference.setDescription("description2"); + ruleReference.addExample("example2"); + ruleReference.setExternalInfoUrl("externalInfoUrl2"); + ruleReference.setPriority(RulePriority.MEDIUM_HIGH); + + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), + ruleReference.getLanguage()); + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), + ruleReference.getOverriddenLanguage()); + + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), + ruleReference.getMinimumLanguageVersion()); + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), + ruleReference.getOverriddenMinimumLanguageVersion()); + + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), + ruleReference.getMaximumLanguageVersion()); + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), + ruleReference.getOverriddenMaximumLanguageVersion()); + + assertEquals("Override failed", false, ruleReference.getRule().isDeprecated()); + assertEquals("Override failed", true, ruleReference.isDeprecated()); + assertEquals("Override failed", true, ruleReference.isOverriddenDeprecated()); + + assertEquals("Override failed", "name2", ruleReference.getName()); + assertEquals("Override failed", "name2", ruleReference.getOverriddenName()); + + assertEquals("Override failed", "value2", ruleReference.getProperty(PROPERTY1_DESCRIPTOR)); + assertEquals("Override failed", "value3", ruleReference.getProperty(PROPERTY2_DESCRIPTOR)); + assertTrue("Override failed", ruleReference.getPropertyDescriptors().contains(PROPERTY1_DESCRIPTOR)); + assertTrue("Override failed", ruleReference.getPropertyDescriptors().contains(PROPERTY2_DESCRIPTOR)); + assertFalse("Override failed", ruleReference.getOverriddenPropertyDescriptors().contains(PROPERTY1_DESCRIPTOR)); + assertTrue("Override failed", ruleReference.getOverriddenPropertyDescriptors().contains(PROPERTY2_DESCRIPTOR)); + assertTrue("Override failed", + ruleReference.getPropertiesByPropertyDescriptor().containsKey(PROPERTY1_DESCRIPTOR)); + assertTrue("Override failed", + ruleReference.getPropertiesByPropertyDescriptor().containsKey(PROPERTY2_DESCRIPTOR)); + assertTrue("Override failed", + ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(PROPERTY1_DESCRIPTOR)); + assertTrue("Override failed", + ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(PROPERTY2_DESCRIPTOR)); + + assertEquals("Override failed", "message2", ruleReference.getMessage()); + assertEquals("Override failed", "message2", ruleReference.getOverriddenMessage()); + + assertEquals("Override failed", "description2", ruleReference.getDescription()); + assertEquals("Override failed", "description2", ruleReference.getOverriddenDescription()); + + assertEquals("Override failed", 2, ruleReference.getExamples().size()); + assertEquals("Override failed", "example1", ruleReference.getExamples().get(0)); + assertEquals("Override failed", "example2", ruleReference.getExamples().get(1)); + assertEquals("Override failed", "example2", ruleReference.getOverriddenExamples().get(0)); + + assertEquals("Override failed", "externalInfoUrl2", ruleReference.getExternalInfoUrl()); + assertEquals("Override failed", "externalInfoUrl2", ruleReference.getOverriddenExternalInfoUrl()); + + assertEquals("Override failed", RulePriority.MEDIUM_HIGH, ruleReference.getPriority()); + assertEquals("Override failed", RulePriority.MEDIUM_HIGH, ruleReference.getOverriddenPriority()); + } + + @Test + public void testNotOverride() { + final StringProperty PROPERTY1_DESCRIPTOR = new StringProperty("property1", "Test property", null, 0f); + MockRule rule = new MockRule(); + rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); + rule.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); + rule.setMinimumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3")); + rule.setMaximumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7")); + rule.setName("name1"); + rule.setProperty(PROPERTY1_DESCRIPTOR, "value1"); + rule.setMessage("message1"); + rule.setDescription("description1"); + rule.addExample("example1"); + rule.setExternalInfoUrl("externalInfoUrl1"); + rule.setPriority(RulePriority.HIGH); + + RuleReference ruleReference = new RuleReference(); + ruleReference.setRule(rule); + ruleReference.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); + ruleReference + .setMinimumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3")); + ruleReference + .setMaximumLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7")); + ruleReference.setDeprecated(false); + ruleReference.setName("name1"); + ruleReference.setProperty(PROPERTY1_DESCRIPTOR, "value1"); + ruleReference.setMessage("message1"); + ruleReference.setDescription("description1"); + ruleReference.addExample("example1"); + ruleReference.setExternalInfoUrl("externalInfoUrl1"); + ruleReference.setPriority(RulePriority.HIGH); + + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), + ruleReference.getLanguage()); + assertNull("Override failed", ruleReference.getOverriddenLanguage()); + + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), + ruleReference.getMinimumLanguageVersion()); + assertNull("Override failed", ruleReference.getOverriddenMinimumLanguageVersion()); + + assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), + ruleReference.getMaximumLanguageVersion()); + assertNull("Override failed", ruleReference.getOverriddenMaximumLanguageVersion()); + + assertEquals("Override failed", false, ruleReference.isDeprecated()); + assertNull("Override failed", ruleReference.isOverriddenDeprecated()); + + assertEquals("Override failed", "name1", ruleReference.getName()); + assertNull("Override failed", ruleReference.getOverriddenName()); + + assertEquals("Override failed", "value1", ruleReference.getProperty(PROPERTY1_DESCRIPTOR)); + + assertEquals("Override failed", "message1", ruleReference.getMessage()); + assertNull("Override failed", ruleReference.getOverriddenMessage()); + + assertEquals("Override failed", "description1", ruleReference.getDescription()); + assertNull("Override failed", ruleReference.getOverriddenDescription()); + + assertEquals("Override failed", 1, ruleReference.getExamples().size()); + assertEquals("Override failed", "example1", ruleReference.getExamples().get(0)); + assertNull("Override failed", ruleReference.getOverriddenExamples()); + + assertEquals("Override failed", "externalInfoUrl1", ruleReference.getExternalInfoUrl()); + assertNull("Override failed", ruleReference.getOverriddenExternalInfoUrl()); + + assertEquals("Override failed", RulePriority.HIGH, ruleReference.getPriority()); + assertNull("Override failed", ruleReference.getOverriddenPriority()); + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java index 0e813d7486..f5cf7c5f5a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java @@ -1,322 +1,322 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.findAll; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.head; -import static com.github.tomakehurst.wiremock.client.WireMock.headRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.InputStream; -import java.util.List; - -import org.apache.commons.io.IOUtils; -import org.junit.Test; - -import com.github.tomakehurst.wiremock.junit.WireMockRule; - -public class RuleSetReferenceIdTest { - - private static void assertRuleSetReferenceId(final boolean expectedExternal, final String expectedRuleSetFileName, - final boolean expectedAllRules, final String expectedRuleName, final String expectedToString, - final RuleSetReferenceId reference) { - - assertEquals("Wrong external", expectedExternal, reference.isExternal()); - assertEquals("Wrong RuleSet file name", expectedRuleSetFileName, reference.getRuleSetFileName()); - assertEquals("Wrong all Rule reference", expectedAllRules, reference.isAllRules()); - assertEquals("Wrong Rule name", expectedRuleName, reference.getRuleName()); - assertEquals("Wrong toString()", expectedToString, reference.toString()); - } - - @Test(expected = IllegalArgumentException.class) - public void testCommaInSingleId() { - - new RuleSetReferenceId("bad,id"); - } - - @Test(expected = IllegalArgumentException.class) - public void testInternalWithInternal() { - - new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("SomeOtherRule")); - } - - @Test(expected = IllegalArgumentException.class) - public void testExternalWithExternal() { - - new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule")); - } - - @Test(expected = IllegalArgumentException.class) - public void testExternalWithInternal() { - - new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("SomeOtherRule")); - } - - @Test - public void testInteralWithExternal() { - - // This is okay - new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule")); - } - - @Test - public void testEmptyRuleSet() { - - // This is representative of how the Test framework creates - // RuleSetReferenceId from static RuleSet XMLs - RuleSetReferenceId reference = new RuleSetReferenceId(null); - assertRuleSetReferenceId(true, null, true, null, "anonymous all Rule", reference); - } - - @Test - public void testInternalWithExternalRuleSet() { - - // This is representative of how the RuleSetFactory temporarily pairs an - // internal reference - // with an external reference. - RuleSetReferenceId internalRuleSetReferenceId = new RuleSetReferenceId("MockRuleName"); - assertRuleSetReferenceId(false, null, false, "MockRuleName", "MockRuleName", internalRuleSetReferenceId); - RuleSetReferenceId externalRuleSetReferenceId = new RuleSetReferenceId("rulesets/java/basic.xml"); - assertRuleSetReferenceId(true, "rulesets/java/basic.xml", true, null, "rulesets/java/basic.xml", - externalRuleSetReferenceId); - - RuleSetReferenceId pairRuleSetReferenceId = new RuleSetReferenceId("MockRuleName", externalRuleSetReferenceId); - assertRuleSetReferenceId(true, "rulesets/java/basic.xml", false, "MockRuleName", - "rulesets/java/basic.xml/MockRuleName", pairRuleSetReferenceId); - } - - @Test - public void testConstructorGivenHttpUrlIdSucceedsAndProcessesIdCorrectly() { - - final String sonarRulesetUrlId = "http://localhost:54321/profiles/export?format=pmd&language=java&name=Sonar%2520way"; - - RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + sonarRulesetUrlId + " "); - assertRuleSetReferenceId(true, sonarRulesetUrlId, true, null, sonarRulesetUrlId, ruleSetReferenceId); - } - - @org.junit.Rule - public WireMockRule wireMockRule = new WireMockRule(0); - - @Test - public void testConstructorGivenHttpUrlInputStream() throws Exception { - String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way"; - String rulesetUrl = "http://localhost:" + wireMockRule.port() + path; - stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200))); - stubFor(get(urlEqualTo(path)) - .willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody("xyz"))); - - RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + rulesetUrl + " "); - assertRuleSetReferenceId(true, rulesetUrl, true, null, rulesetUrl, ruleSetReferenceId); - - InputStream inputStream = ruleSetReferenceId.getInputStream(RuleSetReferenceIdTest.class.getClassLoader()); - String loaded = IOUtils.toString(inputStream, "UTF-8"); - assertEquals("xyz", loaded); - - verify(1, headRequestedFor(urlEqualTo(path))); - verify(0, headRequestedFor(urlEqualTo("/profiles"))); - verify(1, getRequestedFor(urlEqualTo(path))); - assertEquals(1, findAll(headRequestedFor(urlMatching(".*"))).size()); - assertEquals(1, findAll(getRequestedFor(urlMatching(".*"))).size()); - } - - @Test - public void testConstructorGivenHttpUrlSingleRuleInputStream() throws Exception { - String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way"; - String completePath = path + "/DummyBasicMockRule"; - String hostpart = "http://localhost:" + wireMockRule.port(); - String basicRuleSet = IOUtils - .toString(RuleSetReferenceId.class.getResourceAsStream("/rulesets/dummy/basic.xml")); - - stubFor(head(urlEqualTo(completePath)).willReturn(aResponse().withStatus(404))); - stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml"))); - stubFor(get(urlEqualTo(path)) - .willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody(basicRuleSet))); - - RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + hostpart + completePath + " "); - assertRuleSetReferenceId(true, hostpart + path, false, "DummyBasicMockRule", hostpart + completePath, - ruleSetReferenceId); - - InputStream inputStream = ruleSetReferenceId.getInputStream(RuleSetReferenceIdTest.class.getClassLoader()); - String loaded = IOUtils.toString(inputStream, "UTF-8"); - assertEquals(basicRuleSet, loaded); - - verify(1, headRequestedFor(urlEqualTo(completePath))); - verify(1, headRequestedFor(urlEqualTo(path))); - verify(1, getRequestedFor(urlEqualTo(path))); - verify(0, getRequestedFor(urlEqualTo(completePath))); - assertEquals(2, findAll(headRequestedFor(urlMatching(".*"))).size()); - assertEquals(1, findAll(getRequestedFor(urlMatching(".*"))).size()); - } - - @Test - public void testOneSimpleRuleSet() { - - List references = RuleSetReferenceId.parse("dummy-basic"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", - references.get(0)); - } - - @Test - public void testMultipleSimpleRuleSet() { - List references = RuleSetReferenceId.parse("dummy-unusedcode,dummy-basic"); - assertEquals(2, references.size()); - assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", - references.get(0)); - assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", - references.get(1)); - } - - /** - * See https://sourceforge.net/p/pmd/bugs/1201/ - */ - @Test - public void testMultipleRulesWithSpaces() { - List references = RuleSetReferenceId.parse("dummy-basic, dummy-unusedcode, dummy2-basic"); - assertEquals(3, references.size()); - assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", - references.get(0)); - assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", - references.get(1)); - assertRuleSetReferenceId(true, "rulesets/dummy2/basic.xml", true, null, "rulesets/dummy2/basic.xml", - references.get(2)); - } - - @Test - public void testOneReleaseRuleSet() { - List references = RuleSetReferenceId.parse("50"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "rulesets/releases/50.xml", true, null, "rulesets/releases/50.xml", - references.get(0)); - } - - @Test - public void testOneFullRuleSet() { - List references = RuleSetReferenceId.parse("rulesets/java/unusedcode.xml"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "rulesets/java/unusedcode.xml", true, null, "rulesets/java/unusedcode.xml", - references.get(0)); - } - - @Test - public void testOneFullRuleSetURL() { - List references = RuleSetReferenceId.parse("file://somepath/rulesets/java/unusedcode.xml"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "file://somepath/rulesets/java/unusedcode.xml", true, null, - "file://somepath/rulesets/java/unusedcode.xml", references.get(0)); - } - - @Test - public void testMultipleFullRuleSet() { - List references = RuleSetReferenceId - .parse("rulesets/java/unusedcode.xml,rulesets/java/basic.xml"); - assertEquals(2, references.size()); - assertRuleSetReferenceId(true, "rulesets/java/unusedcode.xml", true, null, "rulesets/java/unusedcode.xml", - references.get(0)); - assertRuleSetReferenceId(true, "rulesets/java/basic.xml", true, null, "rulesets/java/basic.xml", - references.get(1)); - } - - @Test - public void testMixRuleSet() { - List references = RuleSetReferenceId.parse("rulesets/dummy/unusedcode.xml,dummy2-basic"); - assertEquals(2, references.size()); - assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", - references.get(0)); - assertRuleSetReferenceId(true, "rulesets/dummy2/basic.xml", true, null, "rulesets/dummy2/basic.xml", - references.get(1)); - } - - @Test - public void testUnknownRuleSet() { - List references = RuleSetReferenceId.parse("nonexistant.xml"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "nonexistant.xml", true, null, "nonexistant.xml", references.get(0)); - } - - @Test - public void testUnknownAndSimpleRuleSet() { - List references = RuleSetReferenceId.parse("dummy-basic,nonexistant.xml"); - assertEquals(2, references.size()); - assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", - references.get(0)); - assertRuleSetReferenceId(true, "nonexistant.xml", true, null, "nonexistant.xml", references.get(1)); - } - - @Test - public void testSimpleRuleSetAndRule() { - List references = RuleSetReferenceId.parse("dummy-basic/DummyBasicMockRule"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", false, "DummyBasicMockRule", - "rulesets/dummy/basic.xml/DummyBasicMockRule", references.get(0)); - } - - @Test - public void testFullRuleSetAndRule() { - List references = RuleSetReferenceId.parse("rulesets/java/basic.xml/EmptyCatchBlock"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "rulesets/java/basic.xml", false, "EmptyCatchBlock", - "rulesets/java/basic.xml/EmptyCatchBlock", references.get(0)); - } - - @Test - public void testFullRuleSetURLAndRule() { - List references = RuleSetReferenceId - .parse("file://somepath/rulesets/java/unusedcode.xml/EmptyCatchBlock"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "file://somepath/rulesets/java/unusedcode.xml", false, "EmptyCatchBlock", - "file://somepath/rulesets/java/unusedcode.xml/EmptyCatchBlock", references.get(0)); - } - - @Test - public void testInternalRuleSetAndRule() { - List references = RuleSetReferenceId.parse("EmptyCatchBlock"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(false, null, false, "EmptyCatchBlock", "EmptyCatchBlock", references.get(0)); - } - - @Test - public void testRelativePathRuleSet() { - List references = RuleSetReferenceId.parse("pmd/pmd-ruleset.xml"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "pmd/pmd-ruleset.xml", true, null, "pmd/pmd-ruleset.xml", references.get(0)); - } - - @Test - public void testAbsolutePathRuleSet() { - List references = RuleSetReferenceId.parse("/home/foo/pmd/pmd-ruleset.xml"); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, "/home/foo/pmd/pmd-ruleset.xml", true, null, "/home/foo/pmd/pmd-ruleset.xml", - references.get(0)); - } - - @Test - public void testFooRules() throws Exception { - String fooRulesFile = new File("./src/test/resources/net/sourceforge/pmd/rulesets/foo-project/foo-rules") - .getCanonicalPath(); - List references = RuleSetReferenceId.parse(fooRulesFile); - assertEquals(1, references.size()); - assertRuleSetReferenceId(true, fooRulesFile, true, null, fooRulesFile, references.get(0)); - } - - @Test - public void testNullRulesetString() throws Exception { - List references = RuleSetReferenceId.parse(null); - assertTrue(references.isEmpty()); - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(RuleSetReferenceIdTest.class); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.findAll; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.head; +import static com.github.tomakehurst.wiremock.client.WireMock.headRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.InputStream; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; + +public class RuleSetReferenceIdTest { + + private static void assertRuleSetReferenceId(final boolean expectedExternal, final String expectedRuleSetFileName, + final boolean expectedAllRules, final String expectedRuleName, final String expectedToString, + final RuleSetReferenceId reference) { + + assertEquals("Wrong external", expectedExternal, reference.isExternal()); + assertEquals("Wrong RuleSet file name", expectedRuleSetFileName, reference.getRuleSetFileName()); + assertEquals("Wrong all Rule reference", expectedAllRules, reference.isAllRules()); + assertEquals("Wrong Rule name", expectedRuleName, reference.getRuleName()); + assertEquals("Wrong toString()", expectedToString, reference.toString()); + } + + @Test(expected = IllegalArgumentException.class) + public void testCommaInSingleId() { + + new RuleSetReferenceId("bad,id"); + } + + @Test(expected = IllegalArgumentException.class) + public void testInternalWithInternal() { + + new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("SomeOtherRule")); + } + + @Test(expected = IllegalArgumentException.class) + public void testExternalWithExternal() { + + new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule")); + } + + @Test(expected = IllegalArgumentException.class) + public void testExternalWithInternal() { + + new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("SomeOtherRule")); + } + + @Test + public void testInteralWithExternal() { + + // This is okay + new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule")); + } + + @Test + public void testEmptyRuleSet() { + + // This is representative of how the Test framework creates + // RuleSetReferenceId from static RuleSet XMLs + RuleSetReferenceId reference = new RuleSetReferenceId(null); + assertRuleSetReferenceId(true, null, true, null, "anonymous all Rule", reference); + } + + @Test + public void testInternalWithExternalRuleSet() { + + // This is representative of how the RuleSetFactory temporarily pairs an + // internal reference + // with an external reference. + RuleSetReferenceId internalRuleSetReferenceId = new RuleSetReferenceId("MockRuleName"); + assertRuleSetReferenceId(false, null, false, "MockRuleName", "MockRuleName", internalRuleSetReferenceId); + RuleSetReferenceId externalRuleSetReferenceId = new RuleSetReferenceId("rulesets/java/basic.xml"); + assertRuleSetReferenceId(true, "rulesets/java/basic.xml", true, null, "rulesets/java/basic.xml", + externalRuleSetReferenceId); + + RuleSetReferenceId pairRuleSetReferenceId = new RuleSetReferenceId("MockRuleName", externalRuleSetReferenceId); + assertRuleSetReferenceId(true, "rulesets/java/basic.xml", false, "MockRuleName", + "rulesets/java/basic.xml/MockRuleName", pairRuleSetReferenceId); + } + + @Test + public void testConstructorGivenHttpUrlIdSucceedsAndProcessesIdCorrectly() { + + final String sonarRulesetUrlId = "http://localhost:54321/profiles/export?format=pmd&language=java&name=Sonar%2520way"; + + RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + sonarRulesetUrlId + " "); + assertRuleSetReferenceId(true, sonarRulesetUrlId, true, null, sonarRulesetUrlId, ruleSetReferenceId); + } + + @org.junit.Rule + public WireMockRule wireMockRule = new WireMockRule(0); + + @Test + public void testConstructorGivenHttpUrlInputStream() throws Exception { + String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way"; + String rulesetUrl = "http://localhost:" + wireMockRule.port() + path; + stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200))); + stubFor(get(urlEqualTo(path)) + .willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody("xyz"))); + + RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + rulesetUrl + " "); + assertRuleSetReferenceId(true, rulesetUrl, true, null, rulesetUrl, ruleSetReferenceId); + + InputStream inputStream = ruleSetReferenceId.getInputStream(RuleSetReferenceIdTest.class.getClassLoader()); + String loaded = IOUtils.toString(inputStream, "UTF-8"); + assertEquals("xyz", loaded); + + verify(1, headRequestedFor(urlEqualTo(path))); + verify(0, headRequestedFor(urlEqualTo("/profiles"))); + verify(1, getRequestedFor(urlEqualTo(path))); + assertEquals(1, findAll(headRequestedFor(urlMatching(".*"))).size()); + assertEquals(1, findAll(getRequestedFor(urlMatching(".*"))).size()); + } + + @Test + public void testConstructorGivenHttpUrlSingleRuleInputStream() throws Exception { + String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way"; + String completePath = path + "/DummyBasicMockRule"; + String hostpart = "http://localhost:" + wireMockRule.port(); + String basicRuleSet = IOUtils + .toString(RuleSetReferenceId.class.getResourceAsStream("/rulesets/dummy/basic.xml")); + + stubFor(head(urlEqualTo(completePath)).willReturn(aResponse().withStatus(404))); + stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml"))); + stubFor(get(urlEqualTo(path)) + .willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody(basicRuleSet))); + + RuleSetReferenceId ruleSetReferenceId = new RuleSetReferenceId(" " + hostpart + completePath + " "); + assertRuleSetReferenceId(true, hostpart + path, false, "DummyBasicMockRule", hostpart + completePath, + ruleSetReferenceId); + + InputStream inputStream = ruleSetReferenceId.getInputStream(RuleSetReferenceIdTest.class.getClassLoader()); + String loaded = IOUtils.toString(inputStream, "UTF-8"); + assertEquals(basicRuleSet, loaded); + + verify(1, headRequestedFor(urlEqualTo(completePath))); + verify(1, headRequestedFor(urlEqualTo(path))); + verify(1, getRequestedFor(urlEqualTo(path))); + verify(0, getRequestedFor(urlEqualTo(completePath))); + assertEquals(2, findAll(headRequestedFor(urlMatching(".*"))).size()); + assertEquals(1, findAll(getRequestedFor(urlMatching(".*"))).size()); + } + + @Test + public void testOneSimpleRuleSet() { + + List references = RuleSetReferenceId.parse("dummy-basic"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", + references.get(0)); + } + + @Test + public void testMultipleSimpleRuleSet() { + List references = RuleSetReferenceId.parse("dummy-unusedcode,dummy-basic"); + assertEquals(2, references.size()); + assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", + references.get(0)); + assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", + references.get(1)); + } + + /** + * See https://sourceforge.net/p/pmd/bugs/1201/ + */ + @Test + public void testMultipleRulesWithSpaces() { + List references = RuleSetReferenceId.parse("dummy-basic, dummy-unusedcode, dummy2-basic"); + assertEquals(3, references.size()); + assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", + references.get(0)); + assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", + references.get(1)); + assertRuleSetReferenceId(true, "rulesets/dummy2/basic.xml", true, null, "rulesets/dummy2/basic.xml", + references.get(2)); + } + + @Test + public void testOneReleaseRuleSet() { + List references = RuleSetReferenceId.parse("50"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "rulesets/releases/50.xml", true, null, "rulesets/releases/50.xml", + references.get(0)); + } + + @Test + public void testOneFullRuleSet() { + List references = RuleSetReferenceId.parse("rulesets/java/unusedcode.xml"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "rulesets/java/unusedcode.xml", true, null, "rulesets/java/unusedcode.xml", + references.get(0)); + } + + @Test + public void testOneFullRuleSetURL() { + List references = RuleSetReferenceId.parse("file://somepath/rulesets/java/unusedcode.xml"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "file://somepath/rulesets/java/unusedcode.xml", true, null, + "file://somepath/rulesets/java/unusedcode.xml", references.get(0)); + } + + @Test + public void testMultipleFullRuleSet() { + List references = RuleSetReferenceId + .parse("rulesets/java/unusedcode.xml,rulesets/java/basic.xml"); + assertEquals(2, references.size()); + assertRuleSetReferenceId(true, "rulesets/java/unusedcode.xml", true, null, "rulesets/java/unusedcode.xml", + references.get(0)); + assertRuleSetReferenceId(true, "rulesets/java/basic.xml", true, null, "rulesets/java/basic.xml", + references.get(1)); + } + + @Test + public void testMixRuleSet() { + List references = RuleSetReferenceId.parse("rulesets/dummy/unusedcode.xml,dummy2-basic"); + assertEquals(2, references.size()); + assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", + references.get(0)); + assertRuleSetReferenceId(true, "rulesets/dummy2/basic.xml", true, null, "rulesets/dummy2/basic.xml", + references.get(1)); + } + + @Test + public void testUnknownRuleSet() { + List references = RuleSetReferenceId.parse("nonexistant.xml"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "nonexistant.xml", true, null, "nonexistant.xml", references.get(0)); + } + + @Test + public void testUnknownAndSimpleRuleSet() { + List references = RuleSetReferenceId.parse("dummy-basic,nonexistant.xml"); + assertEquals(2, references.size()); + assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", + references.get(0)); + assertRuleSetReferenceId(true, "nonexistant.xml", true, null, "nonexistant.xml", references.get(1)); + } + + @Test + public void testSimpleRuleSetAndRule() { + List references = RuleSetReferenceId.parse("dummy-basic/DummyBasicMockRule"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", false, "DummyBasicMockRule", + "rulesets/dummy/basic.xml/DummyBasicMockRule", references.get(0)); + } + + @Test + public void testFullRuleSetAndRule() { + List references = RuleSetReferenceId.parse("rulesets/java/basic.xml/EmptyCatchBlock"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "rulesets/java/basic.xml", false, "EmptyCatchBlock", + "rulesets/java/basic.xml/EmptyCatchBlock", references.get(0)); + } + + @Test + public void testFullRuleSetURLAndRule() { + List references = RuleSetReferenceId + .parse("file://somepath/rulesets/java/unusedcode.xml/EmptyCatchBlock"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "file://somepath/rulesets/java/unusedcode.xml", false, "EmptyCatchBlock", + "file://somepath/rulesets/java/unusedcode.xml/EmptyCatchBlock", references.get(0)); + } + + @Test + public void testInternalRuleSetAndRule() { + List references = RuleSetReferenceId.parse("EmptyCatchBlock"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(false, null, false, "EmptyCatchBlock", "EmptyCatchBlock", references.get(0)); + } + + @Test + public void testRelativePathRuleSet() { + List references = RuleSetReferenceId.parse("pmd/pmd-ruleset.xml"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "pmd/pmd-ruleset.xml", true, null, "pmd/pmd-ruleset.xml", references.get(0)); + } + + @Test + public void testAbsolutePathRuleSet() { + List references = RuleSetReferenceId.parse("/home/foo/pmd/pmd-ruleset.xml"); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, "/home/foo/pmd/pmd-ruleset.xml", true, null, "/home/foo/pmd/pmd-ruleset.xml", + references.get(0)); + } + + @Test + public void testFooRules() throws Exception { + String fooRulesFile = new File("./src/test/resources/net/sourceforge/pmd/rulesets/foo-project/foo-rules") + .getCanonicalPath(); + List references = RuleSetReferenceId.parse(fooRulesFile); + assertEquals(1, references.size()); + assertRuleSetReferenceId(true, fooRulesFile, true, null, fooRulesFile, references.get(0)); + } + + @Test + public void testNullRulesetString() throws Exception { + List references = RuleSetReferenceId.parse(null); + assertTrue(references.isEmpty()); + } + + public static junit.framework.Test suite() { + return new junit.framework.JUnit4TestAdapter(RuleSetReferenceIdTest.class); + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java index 1b441f88ab..80e72959dc 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java @@ -1,89 +1,89 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.DummyNode; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.MockRule; -import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; - -import junit.framework.JUnit4TestAdapter; - -public class RuleViolationComparatorTest { - - @Test - public void testComparator() { - Rule rule1 = new MockRule("name1", "desc", "msg", "rulesetname1"); - Rule rule2 = new MockRule("name2", "desc", "msg", "rulesetname2"); - - // RuleViolations created in pre-sorted order - RuleViolation[] expectedOrder = new RuleViolation[12]; - - int index = 0; - // Different begin line - expectedOrder[index++] = createJavaRuleViolation(rule1, "file1", 10, "desc1", 0, 20, 80); - expectedOrder[index++] = createJavaRuleViolation(rule1, "file1", 20, "desc1", 0, 20, 80); - // Different description - expectedOrder[index++] = createJavaRuleViolation(rule1, "file2", 10, "desc1", 0, 20, 80); - expectedOrder[index++] = createJavaRuleViolation(rule1, "file2", 10, "desc2", 0, 20, 80); - // Different begin column - expectedOrder[index++] = createJavaRuleViolation(rule1, "file3", 10, "desc1", 0, 20, 80); - expectedOrder[index++] = createJavaRuleViolation(rule1, "file3", 10, "desc1", 10, 20, 80); - // Different end line - expectedOrder[index++] = createJavaRuleViolation(rule1, "file4", 10, "desc1", 0, 20, 80); - expectedOrder[index++] = createJavaRuleViolation(rule1, "file4", 10, "desc1", 0, 30, 80); - // Different end column - expectedOrder[index++] = createJavaRuleViolation(rule1, "file5", 10, "desc1", 0, 20, 80); - expectedOrder[index++] = createJavaRuleViolation(rule1, "file5", 10, "desc1", 0, 20, 90); - // Different rule name - expectedOrder[index++] = createJavaRuleViolation(rule1, "file6", 10, "desc1", 0, 20, 80); - expectedOrder[index++] = createJavaRuleViolation(rule2, "file6", 10, "desc1", 0, 20, 80); - - // Randomize - List ruleViolations = new ArrayList<>(Arrays.asList(expectedOrder)); - long seed = System.nanoTime(); - Random random = new Random(seed); - Collections.shuffle(ruleViolations, random); - - // Sort - Collections.sort(ruleViolations, RuleViolationComparator.INSTANCE); - - // Check - int count = 0; - for (int i = 0; i < expectedOrder.length; i++) { - count++; - assertSame("Wrong RuleViolation " + i + ", usind seed: " + seed, expectedOrder[i], ruleViolations.get(i)); - } - assertEquals("Missing assertion for every RuleViolation", expectedOrder.length, count); - } - - private RuleViolation createJavaRuleViolation(Rule rule, String fileName, int beginLine, String description, - int beginColumn, int endLine, int endColumn) { - RuleContext ruleContext = new RuleContext(); - ruleContext.setSourceCodeFilename(fileName); - DummyNode simpleNode = new DummyNode(1); - simpleNode.testingOnlySetBeginLine(beginLine); - simpleNode.testingOnlySetBeginColumn(beginColumn); - simpleNode.testingOnlySetEndLine(endLine); - simpleNode.testingOnlySetEndColumn(endColumn); - RuleViolation ruleViolation = new ParametricRuleViolation(rule, ruleContext, simpleNode, description); - return ruleViolation; - } - - public static junit.framework.Test suite() { - return new JUnit4TestAdapter(RuleViolationComparatorTest.class); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.DummyNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.MockRule; +import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; + +import junit.framework.JUnit4TestAdapter; + +public class RuleViolationComparatorTest { + + @Test + public void testComparator() { + Rule rule1 = new MockRule("name1", "desc", "msg", "rulesetname1"); + Rule rule2 = new MockRule("name2", "desc", "msg", "rulesetname2"); + + // RuleViolations created in pre-sorted order + RuleViolation[] expectedOrder = new RuleViolation[12]; + + int index = 0; + // Different begin line + expectedOrder[index++] = createJavaRuleViolation(rule1, "file1", 10, "desc1", 0, 20, 80); + expectedOrder[index++] = createJavaRuleViolation(rule1, "file1", 20, "desc1", 0, 20, 80); + // Different description + expectedOrder[index++] = createJavaRuleViolation(rule1, "file2", 10, "desc1", 0, 20, 80); + expectedOrder[index++] = createJavaRuleViolation(rule1, "file2", 10, "desc2", 0, 20, 80); + // Different begin column + expectedOrder[index++] = createJavaRuleViolation(rule1, "file3", 10, "desc1", 0, 20, 80); + expectedOrder[index++] = createJavaRuleViolation(rule1, "file3", 10, "desc1", 10, 20, 80); + // Different end line + expectedOrder[index++] = createJavaRuleViolation(rule1, "file4", 10, "desc1", 0, 20, 80); + expectedOrder[index++] = createJavaRuleViolation(rule1, "file4", 10, "desc1", 0, 30, 80); + // Different end column + expectedOrder[index++] = createJavaRuleViolation(rule1, "file5", 10, "desc1", 0, 20, 80); + expectedOrder[index++] = createJavaRuleViolation(rule1, "file5", 10, "desc1", 0, 20, 90); + // Different rule name + expectedOrder[index++] = createJavaRuleViolation(rule1, "file6", 10, "desc1", 0, 20, 80); + expectedOrder[index++] = createJavaRuleViolation(rule2, "file6", 10, "desc1", 0, 20, 80); + + // Randomize + List ruleViolations = new ArrayList<>(Arrays.asList(expectedOrder)); + long seed = System.nanoTime(); + Random random = new Random(seed); + Collections.shuffle(ruleViolations, random); + + // Sort + Collections.sort(ruleViolations, RuleViolationComparator.INSTANCE); + + // Check + int count = 0; + for (int i = 0; i < expectedOrder.length; i++) { + count++; + assertSame("Wrong RuleViolation " + i + ", usind seed: " + seed, expectedOrder[i], ruleViolations.get(i)); + } + assertEquals("Missing assertion for every RuleViolation", expectedOrder.length, count); + } + + private RuleViolation createJavaRuleViolation(Rule rule, String fileName, int beginLine, String description, + int beginColumn, int endLine, int endColumn) { + RuleContext ruleContext = new RuleContext(); + ruleContext.setSourceCodeFilename(fileName); + DummyNode simpleNode = new DummyNode(1); + simpleNode.testingOnlySetBeginLine(beginLine); + simpleNode.testingOnlySetBeginColumn(beginColumn); + simpleNode.testingOnlySetEndLine(endLine); + simpleNode.testingOnlySetEndColumn(endColumn); + RuleViolation ruleViolation = new ParametricRuleViolation(rule, ruleContext, simpleNode, description); + return ruleViolation; + } + + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(RuleViolationComparatorTest.class); + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java index 062871cc02..4d5ffcdbe0 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java @@ -1,115 +1,115 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.Test; - -import net.sourceforge.pmd.RuleViolation; - -/** - * @author Philip Graf - */ -public final class ViolationNodeTest { - - /** - * Verifies that two violations nodes with equal - * {@code filename, beginLine, endLine, beginColumn, endColumn} and - * {@code variableName} are equal. - */ - @Test - public void testEqualsNodeWithTwoEqualViolations() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - assertTrue("Two equal violations should result in equal nodes", node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code filename} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentFilename() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Bar.java", 1, 1, 5, 15, ""); - assertFalse("Two violations with different filename should result in not equal nodes", node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code beginLine} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentBeginLine() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 2, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 2, 2, 5, 15, ""); - assertFalse("Two violations with different beginLine should result in not equal nodes", - node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code endLine} are not - * equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentEndLine() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 2, 5, 15, ""); - assertFalse("Two violations with different endLine should result in not equal nodes", node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code beginColumn} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentBeginColumn() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 7, 15, ""); - assertFalse("Two violations with different beginColumn should result in not equal nodes", - node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code endColumn} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentEndColumn() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 17, ""); - assertFalse("Two violations with different end column should result in not equal nodes", - node1.equalsNode(node2)); - } - - /** - * Verifies that two violations with different {@code variableName} are not - * equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentVariableName() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, "a"); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 15, "b"); - assertFalse("Two violations with different variableName should result in not equal nodes", - node1.equalsNode(node2)); - } - - private ViolationNode createViolationNode(final String filename, final int beginLine, final int endLine, - final int beginColumn, final int endColumn, final String variableName) { - final RuleViolation violation = mock(RuleViolation.class); - when(violation.getFilename()).thenReturn(filename); - when(violation.getBeginLine()).thenReturn(beginLine); - when(violation.getEndLine()).thenReturn(endLine); - when(violation.getBeginColumn()).thenReturn(beginColumn); - when(violation.getEndColumn()).thenReturn(endColumn); - when(violation.getVariableName()).thenReturn(variableName); - return new ViolationNode(violation); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.dfa.report; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import net.sourceforge.pmd.RuleViolation; + +/** + * @author Philip Graf + */ +public final class ViolationNodeTest { + + /** + * Verifies that two violations nodes with equal + * {@code filename, beginLine, endLine, beginColumn, endColumn} and + * {@code variableName} are equal. + */ + @Test + public void testEqualsNodeWithTwoEqualViolations() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); + final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); + assertTrue("Two equal violations should result in equal nodes", node1.equalsNode(node2)); + } + + /** + * Verifies that two violations nodes with different {@code filename} are + * not equal. + */ + @Test + public void testEqualsNodeWithTwoDifferentViolationsDifferentFilename() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); + final ViolationNode node2 = createViolationNode("Bar.java", 1, 1, 5, 15, ""); + assertFalse("Two violations with different filename should result in not equal nodes", node1.equalsNode(node2)); + } + + /** + * Verifies that two violations nodes with different {@code beginLine} are + * not equal. + */ + @Test + public void testEqualsNodeWithTwoDifferentViolationsDifferentBeginLine() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 2, 5, 15, ""); + final ViolationNode node2 = createViolationNode("Foo.java", 2, 2, 5, 15, ""); + assertFalse("Two violations with different beginLine should result in not equal nodes", + node1.equalsNode(node2)); + } + + /** + * Verifies that two violations nodes with different {@code endLine} are not + * equal. + */ + @Test + public void testEqualsNodeWithTwoDifferentViolationsDifferentEndLine() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); + final ViolationNode node2 = createViolationNode("Foo.java", 1, 2, 5, 15, ""); + assertFalse("Two violations with different endLine should result in not equal nodes", node1.equalsNode(node2)); + } + + /** + * Verifies that two violations nodes with different {@code beginColumn} are + * not equal. + */ + @Test + public void testEqualsNodeWithTwoDifferentViolationsDifferentBeginColumn() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); + final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 7, 15, ""); + assertFalse("Two violations with different beginColumn should result in not equal nodes", + node1.equalsNode(node2)); + } + + /** + * Verifies that two violations nodes with different {@code endColumn} are + * not equal. + */ + @Test + public void testEqualsNodeWithTwoDifferentViolationsDifferentEndColumn() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); + final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 17, ""); + assertFalse("Two violations with different end column should result in not equal nodes", + node1.equalsNode(node2)); + } + + /** + * Verifies that two violations with different {@code variableName} are not + * equal. + */ + @Test + public void testEqualsNodeWithTwoDifferentViolationsDifferentVariableName() { + final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, "a"); + final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 15, "b"); + assertFalse("Two violations with different variableName should result in not equal nodes", + node1.equalsNode(node2)); + } + + private ViolationNode createViolationNode(final String filename, final int beginLine, final int endLine, + final int beginColumn, final int endColumn, final String variableName) { + final RuleViolation violation = mock(RuleViolation.class); + when(violation.getFilename()).thenReturn(filename); + when(violation.getBeginLine()).thenReturn(beginLine); + when(violation.getEndLine()).thenReturn(endLine); + when(violation.getBeginColumn()).thenReturn(beginColumn); + when(violation.getEndColumn()).thenReturn(endColumn); + when(violation.getVariableName()).thenReturn(variableName); + return new ViolationNode(violation); + } + +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/CompoundListTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/CompoundListTest.java index e5be745820..86b41ff4cb 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/CompoundListTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/CompoundListTest.java @@ -1,92 +1,92 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import org.junit.Before; -import org.junit.Test; - -public class CompoundListTest { - - private List l1; - private List l2; - private Iterator iterator; - - @Before - public void setUp() { - l1 = new ArrayList<>(); - l1.add("1"); - l1.add("2"); - l2 = new ArrayList<>(); - l2.add("3"); - l2.add("4"); - - iterator = new CompoundIterator<>(l1.iterator(), l2.iterator()); - } - - @Test - public void testHappyPath() { - assertTrue(iterator.hasNext()); - assertEquals("1", iterator.next()); - assertTrue(iterator.hasNext()); - assertEquals("2", iterator.next()); - assertTrue(iterator.hasNext()); - assertEquals("3", iterator.next()); - assertTrue(iterator.hasNext()); - assertEquals("4", iterator.next()); - assertFalse(iterator.hasNext()); - assertEquals(2, l1.size()); - assertEquals(2, l2.size()); - } - - @Test - public void testHappyPathRemove() { - assertTrue(iterator.hasNext()); - assertEquals("1", iterator.next()); - iterator.remove(); - assertTrue(iterator.hasNext()); - assertEquals("2", iterator.next()); - assertTrue(iterator.hasNext()); - assertEquals("3", iterator.next()); - iterator.remove(); - assertTrue(iterator.hasNext()); - assertEquals("4", iterator.next()); - assertFalse(iterator.hasNext()); - assertEquals(1, l1.size()); - assertEquals("2", l1.get(0)); - assertEquals(1, l2.size()); - assertEquals("4", l2.get(0)); - } - - @Test - public void testEmpty() { - Iterator iterator = new CompoundIterator(); - assertFalse(iterator.hasNext()); - } - - @Test(expected = NoSuchElementException.class) - public void testEmptyBadNext() { - Iterator iterator = new CompoundIterator(); - iterator.next(); - } - - @Test(expected = IllegalStateException.class) - public void testEmptyBadRemove() { - Iterator iterator = new CompoundIterator(); - iterator.remove(); - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(CompoundListTest.class); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.junit.Before; +import org.junit.Test; + +public class CompoundListTest { + + private List l1; + private List l2; + private Iterator iterator; + + @Before + public void setUp() { + l1 = new ArrayList<>(); + l1.add("1"); + l1.add("2"); + l2 = new ArrayList<>(); + l2.add("3"); + l2.add("4"); + + iterator = new CompoundIterator<>(l1.iterator(), l2.iterator()); + } + + @Test + public void testHappyPath() { + assertTrue(iterator.hasNext()); + assertEquals("1", iterator.next()); + assertTrue(iterator.hasNext()); + assertEquals("2", iterator.next()); + assertTrue(iterator.hasNext()); + assertEquals("3", iterator.next()); + assertTrue(iterator.hasNext()); + assertEquals("4", iterator.next()); + assertFalse(iterator.hasNext()); + assertEquals(2, l1.size()); + assertEquals(2, l2.size()); + } + + @Test + public void testHappyPathRemove() { + assertTrue(iterator.hasNext()); + assertEquals("1", iterator.next()); + iterator.remove(); + assertTrue(iterator.hasNext()); + assertEquals("2", iterator.next()); + assertTrue(iterator.hasNext()); + assertEquals("3", iterator.next()); + iterator.remove(); + assertTrue(iterator.hasNext()); + assertEquals("4", iterator.next()); + assertFalse(iterator.hasNext()); + assertEquals(1, l1.size()); + assertEquals("2", l1.get(0)); + assertEquals(1, l2.size()); + assertEquals("4", l2.get(0)); + } + + @Test + public void testEmpty() { + Iterator iterator = new CompoundIterator(); + assertFalse(iterator.hasNext()); + } + + @Test(expected = NoSuchElementException.class) + public void testEmptyBadNext() { + Iterator iterator = new CompoundIterator(); + iterator.next(); + } + + @Test(expected = IllegalStateException.class) + public void testEmptyBadRemove() { + Iterator iterator = new CompoundIterator(); + iterator.remove(); + } + + public static junit.framework.Test suite() { + return new junit.framework.JUnit4TestAdapter(CompoundListTest.class); + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/filter/RegexStringFilterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/filter/RegexStringFilterTest.java index 0427c16b14..277bf0851c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/filter/RegexStringFilterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/filter/RegexStringFilterTest.java @@ -1,114 +1,114 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util.filter; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -public class RegexStringFilterTest { - - @Test - public void testFilterAbsoluteWithExtension() { - String pattern = "C:/workspace/project/X.java"; - verifyFilterFalse("same relative path w/ extension", pattern, "X.java"); - verifyFilterFalse("same relative path w/o extension", pattern, "X"); - verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); - verifyFilterFalse("different relative path w/o extension", pattern, "Y"); - verifyFilterTrue("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); - verifyFilterFalse("same absolute path w/o extension", pattern, "C:/workspace/project/X"); - verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); - verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); - } - - @Test - public void testFilterAbsoluteWithoutExtension() { - String pattern = "C:/workspace/project/X"; - verifyFilterFalse("same relative path w/ extension", pattern, "X.java"); - verifyFilterFalse("same relative path w/o extension", pattern, "X"); - verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); - verifyFilterFalse("different relative path w/o extension", pattern, "Y"); - verifyFilterFalse("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); - verifyFilterTrue("same absolute path w/o extension", pattern, "C:/workspace/project/X"); - verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); - verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); - } - - @Test - public void testFilterRelativeWithExtension() { - String pattern = ".*X.java"; - verifyFilterTrue("same relative path w/ extension", pattern, "X.java"); - verifyFilterFalse("same relative path w/o extension", pattern, "X"); - verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); - verifyFilterFalse("different relative path w/o extension", pattern, "Y"); - verifyFilterTrue("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); - verifyFilterFalse("same absolute path w/o extension", pattern, "C:/workspace/project/X"); - verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); - verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); - } - - @Test - public void testFilterRelativeWithoutExtension() { - String pattern = ".*X"; - verifyFilterFalse("same relative path w/ extension", pattern, "X.java"); - verifyFilterTrue("same relative path w/o extension", pattern, "X"); - verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); - verifyFilterFalse("different relative path w/o extension", pattern, "Y"); - verifyFilterFalse("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); - verifyFilterTrue("same absolute path w/o extension", pattern, "C:/workspace/project/X"); - verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); - verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); - } - - @Test - public void testEndsWith() { - // These patterns cannot be optimized to use String.endsWith - verifyEndsWith("no literal path", ".*", null); - verifyEndsWith("not ends with", "x", null); - verifyEndsWith("glob on end", ".*XXX.*", null); - verifyEndsWith("special character \\", ".*X\\Y", null); - verifyEndsWith("special character [", ".*X[Y", null); - verifyEndsWith("special character (", ".*X(Y", null); - verifyEndsWith("special character *", ".*X*Y", null); - verifyEndsWith("special character ?", ".*X?Y", null); - verifyEndsWith("special character +", ".*X+Y", null); - verifyEndsWith("special character |", ".*X|Y", null); - verifyEndsWith("special character {", ".*X{Y", null); - verifyEndsWith("special character $", ".*X$Y", null); - verifyEndsWith("too many .", ".*X.Y.java", null); - - // These patterns can be optimized to use String.endsWith - verifyEndsWith("unescaped .", ".*X.java", "X.java"); - verifyEndsWith("escaped .", ".*X\\.java", "X.java"); - verifyEndsWith("no extension", ".*X", "X"); - verifyEndsWith("begin anchor, unescaped .", "^.*X.java", "X.java"); - verifyEndsWith("begin anchor, escaped .", "^.*X\\.java", "X.java"); - verifyEndsWith("begin anchor, no extension", "^.*X", "X"); - verifyEndsWith("end anchor, unescaped .", ".*X.java$", "X.java"); - verifyEndsWith("end anchor, escaped .", ".*X\\.java$", "X.java"); - verifyEndsWith("end anchor, no extension", ".*X$", "X"); - verifyEndsWith("begin and end anchors, unescaped .", "^.*X.java$", "X.java"); - verifyEndsWith("begin and end anchors, escaped .", "^.*X\\.java$", "X.java"); - verifyEndsWith("begin and end anchors, no extension", "^.*X$", "X"); - } - - private static void verifyFilterTrue(final String message, final String pattern, final String file) { - assertTrue("filter: " + message, new RegexStringFilter(pattern).filter(file)); - } - - private static void verifyFilterFalse(final String message, final String pattern, final String file) { - assertFalse("filter: " + message, new RegexStringFilter(pattern).filter(file)); - } - - private static void verifyEndsWith(final String message, final String pattern, final String endsWith) { - assertEquals("endsWith: " + message, endsWith, new RegexStringFilter(pattern).getEndsWith()); - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(RegexStringFilterTest.class); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class RegexStringFilterTest { + + @Test + public void testFilterAbsoluteWithExtension() { + String pattern = "C:/workspace/project/X.java"; + verifyFilterFalse("same relative path w/ extension", pattern, "X.java"); + verifyFilterFalse("same relative path w/o extension", pattern, "X"); + verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); + verifyFilterFalse("different relative path w/o extension", pattern, "Y"); + verifyFilterTrue("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); + verifyFilterFalse("same absolute path w/o extension", pattern, "C:/workspace/project/X"); + verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); + verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); + } + + @Test + public void testFilterAbsoluteWithoutExtension() { + String pattern = "C:/workspace/project/X"; + verifyFilterFalse("same relative path w/ extension", pattern, "X.java"); + verifyFilterFalse("same relative path w/o extension", pattern, "X"); + verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); + verifyFilterFalse("different relative path w/o extension", pattern, "Y"); + verifyFilterFalse("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); + verifyFilterTrue("same absolute path w/o extension", pattern, "C:/workspace/project/X"); + verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); + verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); + } + + @Test + public void testFilterRelativeWithExtension() { + String pattern = ".*X.java"; + verifyFilterTrue("same relative path w/ extension", pattern, "X.java"); + verifyFilterFalse("same relative path w/o extension", pattern, "X"); + verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); + verifyFilterFalse("different relative path w/o extension", pattern, "Y"); + verifyFilterTrue("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); + verifyFilterFalse("same absolute path w/o extension", pattern, "C:/workspace/project/X"); + verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); + verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); + } + + @Test + public void testFilterRelativeWithoutExtension() { + String pattern = ".*X"; + verifyFilterFalse("same relative path w/ extension", pattern, "X.java"); + verifyFilterTrue("same relative path w/o extension", pattern, "X"); + verifyFilterFalse("different relative path w/ extension", pattern, "Y.java"); + verifyFilterFalse("different relative path w/o extension", pattern, "Y"); + verifyFilterFalse("same absolute path w/ extension", pattern, "C:/workspace/project/X.java"); + verifyFilterTrue("same absolute path w/o extension", pattern, "C:/workspace/project/X"); + verifyFilterFalse("different absolute path w/ extension", pattern, "C:/workspace/project/Y.java"); + verifyFilterFalse("different absolute path w/o extension", pattern, "C:/workspace/project/Y"); + } + + @Test + public void testEndsWith() { + // These patterns cannot be optimized to use String.endsWith + verifyEndsWith("no literal path", ".*", null); + verifyEndsWith("not ends with", "x", null); + verifyEndsWith("glob on end", ".*XXX.*", null); + verifyEndsWith("special character \\", ".*X\\Y", null); + verifyEndsWith("special character [", ".*X[Y", null); + verifyEndsWith("special character (", ".*X(Y", null); + verifyEndsWith("special character *", ".*X*Y", null); + verifyEndsWith("special character ?", ".*X?Y", null); + verifyEndsWith("special character +", ".*X+Y", null); + verifyEndsWith("special character |", ".*X|Y", null); + verifyEndsWith("special character {", ".*X{Y", null); + verifyEndsWith("special character $", ".*X$Y", null); + verifyEndsWith("too many .", ".*X.Y.java", null); + + // These patterns can be optimized to use String.endsWith + verifyEndsWith("unescaped .", ".*X.java", "X.java"); + verifyEndsWith("escaped .", ".*X\\.java", "X.java"); + verifyEndsWith("no extension", ".*X", "X"); + verifyEndsWith("begin anchor, unescaped .", "^.*X.java", "X.java"); + verifyEndsWith("begin anchor, escaped .", "^.*X\\.java", "X.java"); + verifyEndsWith("begin anchor, no extension", "^.*X", "X"); + verifyEndsWith("end anchor, unescaped .", ".*X.java$", "X.java"); + verifyEndsWith("end anchor, escaped .", ".*X\\.java$", "X.java"); + verifyEndsWith("end anchor, no extension", ".*X$", "X"); + verifyEndsWith("begin and end anchors, unescaped .", "^.*X.java$", "X.java"); + verifyEndsWith("begin and end anchors, escaped .", "^.*X\\.java$", "X.java"); + verifyEndsWith("begin and end anchors, no extension", "^.*X$", "X"); + } + + private static void verifyFilterTrue(final String message, final String pattern, final String file) { + assertTrue("filter: " + message, new RegexStringFilter(pattern).filter(file)); + } + + private static void verifyFilterFalse(final String message, final String pattern, final String file) { + assertFalse("filter: " + message, new RegexStringFilter(pattern).filter(file)); + } + + private static void verifyEndsWith(final String message, final String pattern, final String endsWith) { + assertEquals("endsWith: " + message, endsWith, new RegexStringFilter(pattern).getEndsWith()); + } + + public static junit.framework.Test suite() { + return new junit.framework.JUnit4TestAdapter(RegexStringFilterTest.class); + } +} diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/xml/j2ee.xml b/pmd-core/src/test/resources/net/sourceforge/pmd/xml/j2ee.xml index 60dd27a1eb..2e2fd383af 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/xml/j2ee.xml +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/xml/j2ee.xml @@ -1,383 +1,383 @@ - - - - - - These are rules for J2EE - - - - - In J2EE getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead. - - 3 - - - - - - - - - - - - - - - The EJB Specification state that any MessageDrivenBean or SessionBean should be suffixed by Bean. - - 4 - - - - - - - - - - - - - - - - Remote Home interface of a Session EJB should be suffixed by 'Home'. - - 4 - - - - - - - - - - - - - - - - - - The Local Interface of a Session EJB should be suffixed by 'Local'. - - 4 - - - - - - - - - - - - - - - - - - The Local Home interface of a Session EJB should be suffixed by 'LocalHome'. - - 4 - - - - - - - - - - - - - - - - - - Remote Interface of a Session EJB should NOT be suffixed. - - 4 - - - - - - - - - - - - - - - - - - - - - 3 - - - - - - - - - - - -According to the J2EE specification (p.494), an EJB should not have any static fields -with write access. However, static read only fields are allowed. This ensures proper -behavior especially when instances are distributed by the container on several JREs. - - 3 - - - - - - - - - - - - - 3 - - - - - - - - - - - - - + + + + + + These are rules for J2EE + + + + + In J2EE getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead. + + 3 + + + + + + + + + + + + + + + The EJB Specification state that any MessageDrivenBean or SessionBean should be suffixed by Bean. + + 4 + + + + + + + + + + + + + + + + Remote Home interface of a Session EJB should be suffixed by 'Home'. + + 4 + + + + + + + + + + + + + + + + + + The Local Interface of a Session EJB should be suffixed by 'Local'. + + 4 + + + + + + + + + + + + + + + + + + The Local Home interface of a Session EJB should be suffixed by 'LocalHome'. + + 4 + + + + + + + + + + + + + + + + + + Remote Interface of a Session EJB should NOT be suffixed. + + 4 + + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + +According to the J2EE specification (p.494), an EJB should not have any static fields +with write access. However, static read only fields are allowed. This ensures proper +behavior especially when instances are distributed by the container on several JREs. + + 3 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + diff --git a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/ContinuationReader.java b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/ContinuationReader.java index 30a6f36f91..b0143fa61a 100644 --- a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/ContinuationReader.java +++ b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/ContinuationReader.java @@ -1,86 +1,86 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.cpp; - -import java.io.IOException; -import java.io.PushbackReader; -import java.io.Reader; - -/** - * A custom {@link Reader} which completely omits C/C++ continuation character - * sequences from an underlying reader. Specifically the sequences {@code \ \n} - * (backslash, carriage return), or {@code \ \r \n} (backslash, line feed, - * carriage return). - *

- * This reader exists because to modify a JavaCC lexer to understand arbitrary - * continuations inside of any token is cumbersome, and just removing them from - * the input entirely is easier to implement. See this discussion on the JavaCC - * mailing list on line - * continuation character. - */ -public class ContinuationReader extends Reader { - private static final int EOF = -1; - private static final char BACKSLASH = '\\'; - private static final char CARRIAGE_RETURN = '\n'; - private static final char LINE_FEED = '\r'; - - /** the original stream is wrapped in this pushback reader. */ - protected final PushbackReader in; - - /** - * Creates a new {@link ContinuationReader} which filters the given reader. - * - * @param in - * the given reader - */ - public ContinuationReader(Reader in) { - this.in = new PushbackReader(in, 2); - } - - @Override - public int read(char[] cbuf, int off, int len) throws IOException { - int count = 0; - while (count < len) { - int c1 = in.read(); - if (c1 == EOF) { - break; - } else if (c1 == BACKSLASH) { - int c2 = in.read(); - if (c2 == EOF) { - // No match - } else if (c2 == CARRIAGE_RETURN) { - // Match: backslash, carriage return - continue; - } else if (c2 == LINE_FEED) { - int c3 = in.read(); - if (c3 == EOF) { - // No match - in.unread(c2); - } else if (c3 == CARRIAGE_RETURN) { - // Match: backslash, line feed, carriage return - continue; - } else { - // No match - in.unread(c3); - in.unread(c2); - } - } else { - // No match - in.unread(c2); - } - } - cbuf[off + count] = (char) c1; - count++; - } - - return count > 0 ? count : -1; - } - - @Override - public void close() throws IOException { - in.close(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.cpp; + +import java.io.IOException; +import java.io.PushbackReader; +import java.io.Reader; + +/** + * A custom {@link Reader} which completely omits C/C++ continuation character + * sequences from an underlying reader. Specifically the sequences {@code \ \n} + * (backslash, carriage return), or {@code \ \r \n} (backslash, line feed, + * carriage return). + *

+ * This reader exists because to modify a JavaCC lexer to understand arbitrary + * continuations inside of any token is cumbersome, and just removing them from + * the input entirely is easier to implement. See this discussion on the JavaCC + * mailing list on line + * continuation character. + */ +public class ContinuationReader extends Reader { + private static final int EOF = -1; + private static final char BACKSLASH = '\\'; + private static final char CARRIAGE_RETURN = '\n'; + private static final char LINE_FEED = '\r'; + + /** the original stream is wrapped in this pushback reader. */ + protected final PushbackReader in; + + /** + * Creates a new {@link ContinuationReader} which filters the given reader. + * + * @param in + * the given reader + */ + public ContinuationReader(Reader in) { + this.in = new PushbackReader(in, 2); + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + int count = 0; + while (count < len) { + int c1 = in.read(); + if (c1 == EOF) { + break; + } else if (c1 == BACKSLASH) { + int c2 = in.read(); + if (c2 == EOF) { + // No match + } else if (c2 == CARRIAGE_RETURN) { + // Match: backslash, carriage return + continue; + } else if (c2 == LINE_FEED) { + int c3 = in.read(); + if (c3 == EOF) { + // No match + in.unread(c2); + } else if (c3 == CARRIAGE_RETURN) { + // Match: backslash, line feed, carriage return + continue; + } else { + // No match + in.unread(c3); + in.unread(c2); + } + } else { + // No match + in.unread(c2); + } + } + cbuf[off + count] = (char) c1; + count++; + } + + return count > 0 ? count : -1; + } + + @Override + public void close() throws IOException { + in.close(); + } +} diff --git a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppHandler.java b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppHandler.java index 2606304171..3fab012da8 100644 --- a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppHandler.java +++ b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppHandler.java @@ -1,26 +1,26 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.cpp; - -import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; -import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; - -/** - * Implementation of LanguageVersionHandler for the C++ Language. - */ -public class CppHandler extends AbstractLanguageVersionHandler { - - @Override - public RuleViolationFactory getRuleViolationFactory() { - throw new UnsupportedOperationException("getRuleViolationFactory() is not supported for C++"); - } - - @Override - public Parser getParser(ParserOptions parserOptions) { - return new CppParser(parserOptions); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.cpp; + +import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +/** + * Implementation of LanguageVersionHandler for the C++ Language. + */ +public class CppHandler extends AbstractLanguageVersionHandler { + + @Override + public RuleViolationFactory getRuleViolationFactory() { + throw new UnsupportedOperationException("getRuleViolationFactory() is not supported for C++"); + } + + @Override + public Parser getParser(ParserOptions parserOptions) { + return new CppParser(parserOptions); + } +} diff --git a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppParser.java b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppParser.java index 98f7658797..27a8435144 100644 --- a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppParser.java +++ b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppParser.java @@ -1,52 +1,52 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.cpp; - -import java.io.Reader; -import java.util.Map; - -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.AbstractTokenManager; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.ParseException; - -/** - * Adapter for the C++ Parser. - */ -public class CppParser extends AbstractParser { - - /** - * Creates a new C++ Parser. - * - * @param parserOptions - * the options - */ - public CppParser(ParserOptions parserOptions) { - super(parserOptions); - } - - @Override - public TokenManager createTokenManager(Reader source) { - return new CppTokenManager(source); - } - - @Override - public boolean canParse() { - return false; - } - - @Override - public Node parse(String fileName, Reader source) throws ParseException { - AbstractTokenManager.setFileName(fileName); - throw new UnsupportedOperationException("parse(Reader) is not supported for C++"); - } - - @Override - public Map getSuppressMap() { - throw new UnsupportedOperationException("getSuppressMap() is not supported for C++"); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.cpp; + +import java.io.Reader; +import java.util.Map; + +import net.sourceforge.pmd.lang.AbstractParser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.AbstractTokenManager; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.ParseException; + +/** + * Adapter for the C++ Parser. + */ +public class CppParser extends AbstractParser { + + /** + * Creates a new C++ Parser. + * + * @param parserOptions + * the options + */ + public CppParser(ParserOptions parserOptions) { + super(parserOptions); + } + + @Override + public TokenManager createTokenManager(Reader source) { + return new CppTokenManager(source); + } + + @Override + public boolean canParse() { + return false; + } + + @Override + public Node parse(String fileName, Reader source) throws ParseException { + AbstractTokenManager.setFileName(fileName); + throw new UnsupportedOperationException("parse(Reader) is not supported for C++"); + } + + @Override + public Map getSuppressMap() { + throw new UnsupportedOperationException("getSuppressMap() is not supported for C++"); + } +} diff --git a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppTokenManager.java b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppTokenManager.java index 79509c4a8f..328c85fe1c 100644 --- a/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppTokenManager.java +++ b/pmd-cpp/src/main/java/net/sourceforge/pmd/lang/cpp/CppTokenManager.java @@ -1,37 +1,37 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.cpp; - -import java.io.Reader; - -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.SimpleCharStream; -import net.sourceforge.pmd.lang.cpp.ast.CppParserTokenManager; - -/** - * C++ Token Manager implementation. - */ -public class CppTokenManager implements TokenManager { - private final CppParserTokenManager tokenManager; - - /** - * Creates a new C++ Token Manager from the given source code. - * - * @param source - * the source code - */ - public CppTokenManager(Reader source) { - tokenManager = new CppParserTokenManager(new SimpleCharStream(new ContinuationReader(source))); - } - - public Object getNextToken() { - return tokenManager.getNextToken(); - } - - @Override - public void setFileName(String fileName) { - CppParserTokenManager.setFileName(fileName); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.cpp; + +import java.io.Reader; + +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.SimpleCharStream; +import net.sourceforge.pmd.lang.cpp.ast.CppParserTokenManager; + +/** + * C++ Token Manager implementation. + */ +public class CppTokenManager implements TokenManager { + private final CppParserTokenManager tokenManager; + + /** + * Creates a new C++ Token Manager from the given source code. + * + * @param source + * the source code + */ + public CppTokenManager(Reader source) { + tokenManager = new CppParserTokenManager(new SimpleCharStream(new ContinuationReader(source))); + } + + public Object getNextToken() { + return tokenManager.getNextToken(); + } + + @Override + public void setFileName(String fileName) { + CppParserTokenManager.setFileName(fileName); + } +} diff --git a/pmd-cpp/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-cpp/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java index a4fd491447..532789523b 100644 --- a/pmd-cpp/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java +++ b/pmd-cpp/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java @@ -1,33 +1,33 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.runners.Parameterized.Parameters; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.cpp.CppLanguageModule; - -public class LanguageVersionTest extends AbstractLanguageVersionTest { - - public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { - super(name, terseName, version, expected); - } - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { - { - CppLanguageModule.NAME, - CppLanguageModule.TERSE_NAME, - "", - LanguageRegistry.getLanguage(CppLanguageModule.NAME).getDefaultVersion(), - }, - }); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.runners.Parameterized.Parameters; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.cpp.CppLanguageModule; + +public class LanguageVersionTest extends AbstractLanguageVersionTest { + + public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { + super(name, terseName, version, expected); + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { + { + CppLanguageModule.NAME, + CppLanguageModule.TERSE_NAME, + "", + LanguageRegistry.getLanguage(CppLanguageModule.NAME).getDefaultVersion(), + }, + }); + } +} diff --git a/pmd-cpp/src/test/java/net/sourceforge/pmd/lang/cpp/ContinuationReaderTest.java b/pmd-cpp/src/test/java/net/sourceforge/pmd/lang/cpp/ContinuationReaderTest.java index 9af3d9eef6..add41d7d55 100644 --- a/pmd-cpp/src/test/java/net/sourceforge/pmd/lang/cpp/ContinuationReaderTest.java +++ b/pmd-cpp/src/test/java/net/sourceforge/pmd/lang/cpp/ContinuationReaderTest.java @@ -1,56 +1,56 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.cpp; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.io.StringReader; - -import org.junit.Test; - -public class ContinuationReaderTest { - @Test - public void testHappyPath() throws IOException { - assertEquals("empty", "", filter("")); - assertEquals("anything", "anything", filter("anything")); - - assertEquals("partial: BS", "\\", filter("\\")); - assertEquals("partial: BS LF", "\\\r", filter("\\\r")); - assertEquals("full: BS CR", "", filter("\\\n")); - assertEquals("full: BS LF CR", "", filter("\\\r\n")); - - assertEquals("partial: BS: prefix", "prefix\\", filter("prefix\\")); - assertEquals("partial: BS LF: prefix", "prefix\\\r", filter("prefix\\\r")); - assertEquals("full: BS CR: prefix", "prefix", filter("prefix\\\n")); - assertEquals("full: BS LF CR: prefix", "prefix", filter("prefix\\\r\n")); - - assertEquals("partial: BS: suffix", "\\suffix", filter("\\suffix")); - assertEquals("partial: BS LF: suffix", "\\\rsuffix", filter("\\\rsuffix")); - assertEquals("full: BS CR: suffix", "suffix", filter("\\\nsuffix")); - assertEquals("full: BS LF CR: suffix", "suffix", filter("\\\r\nsuffix")); - - assertEquals("partial: BS: prefix, suffix", "prefix\\suffix", filter("prefix\\suffix")); - assertEquals("partial: BS LF: prefix, suffix", "prefix\\\rsuffix", filter("prefix\\\rsuffix")); - assertEquals("full: BS CR: prefix, suffix", "prefixsuffix", filter("prefix\\\nsuffix")); - assertEquals("full: BS LF CR: prefix, suffix", "prefixsuffix", filter("prefix\\\r\nsuffix")); - - assertEquals("complex mixed", "abc", filter("a\\\r\nb\\\n\\\n\\\r\nc")); - } - - private static String filter(String s) throws IOException { - ContinuationReader reader = new ContinuationReader(new StringReader(s)); - try { - StringBuilder buf = new StringBuilder(); - int c; - while ((c = reader.read()) >= 0) { - buf.append((char) c); - } - return buf.toString(); - } finally { - reader.close(); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.cpp; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.StringReader; + +import org.junit.Test; + +public class ContinuationReaderTest { + @Test + public void testHappyPath() throws IOException { + assertEquals("empty", "", filter("")); + assertEquals("anything", "anything", filter("anything")); + + assertEquals("partial: BS", "\\", filter("\\")); + assertEquals("partial: BS LF", "\\\r", filter("\\\r")); + assertEquals("full: BS CR", "", filter("\\\n")); + assertEquals("full: BS LF CR", "", filter("\\\r\n")); + + assertEquals("partial: BS: prefix", "prefix\\", filter("prefix\\")); + assertEquals("partial: BS LF: prefix", "prefix\\\r", filter("prefix\\\r")); + assertEquals("full: BS CR: prefix", "prefix", filter("prefix\\\n")); + assertEquals("full: BS LF CR: prefix", "prefix", filter("prefix\\\r\n")); + + assertEquals("partial: BS: suffix", "\\suffix", filter("\\suffix")); + assertEquals("partial: BS LF: suffix", "\\\rsuffix", filter("\\\rsuffix")); + assertEquals("full: BS CR: suffix", "suffix", filter("\\\nsuffix")); + assertEquals("full: BS LF CR: suffix", "suffix", filter("\\\r\nsuffix")); + + assertEquals("partial: BS: prefix, suffix", "prefix\\suffix", filter("prefix\\suffix")); + assertEquals("partial: BS LF: prefix, suffix", "prefix\\\rsuffix", filter("prefix\\\rsuffix")); + assertEquals("full: BS CR: prefix, suffix", "prefixsuffix", filter("prefix\\\nsuffix")); + assertEquals("full: BS LF CR: prefix, suffix", "prefixsuffix", filter("prefix\\\r\nsuffix")); + + assertEquals("complex mixed", "abc", filter("a\\\r\nb\\\n\\\n\\\r\nc")); + } + + private static String filter(String s) throws IOException { + ContinuationReader reader = new ContinuationReader(new StringReader(s)); + try { + StringBuilder buf = new StringBuilder(); + int c; + while ((c = reader.read()) >= 0) { + buf.append((char) c); + } + return buf.toString(); + } finally { + reader.close(); + } + } +} diff --git a/pmd-dist/src/main/scripts/bgastviewer.bat b/pmd-dist/src/main/scripts/bgastviewer.bat index 73f51fa4e2..14d07aa883 100644 --- a/pmd-dist/src/main/scripts/bgastviewer.bat +++ b/pmd-dist/src/main/scripts/bgastviewer.bat @@ -1,6 +1,6 @@ -@echo off -set TOPDIR=%~dp0.. -set OPTS= -set MAIN_CLASS=net.sourceforge.pmd.util.viewer.Viewer - -java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* +@echo off +set TOPDIR=%~dp0.. +set OPTS= +set MAIN_CLASS=net.sourceforge.pmd.util.viewer.Viewer + +java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* diff --git a/pmd-dist/src/main/scripts/cpd.bat b/pmd-dist/src/main/scripts/cpd.bat index 60b60851cf..23372dc443 100644 --- a/pmd-dist/src/main/scripts/cpd.bat +++ b/pmd-dist/src/main/scripts/cpd.bat @@ -1,6 +1,6 @@ -@echo off -set TOPDIR=%~dp0.. -set OPTS= -set MAIN_CLASS=net.sourceforge.pmd.cpd.CPD - -java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* +@echo off +set TOPDIR=%~dp0.. +set OPTS= +set MAIN_CLASS=net.sourceforge.pmd.cpd.CPD + +java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* diff --git a/pmd-dist/src/main/scripts/cpdgui.bat b/pmd-dist/src/main/scripts/cpdgui.bat index 2d1aac1f85..fbc976922d 100755 --- a/pmd-dist/src/main/scripts/cpdgui.bat +++ b/pmd-dist/src/main/scripts/cpdgui.bat @@ -1,6 +1,6 @@ -@echo off -set TOPDIR=%~dp0.. -set OPTS= -set MAIN_CLASS=net.sourceforge.pmd.cpd.GUI - -java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* +@echo off +set TOPDIR=%~dp0.. +set OPTS= +set MAIN_CLASS=net.sourceforge.pmd.cpd.GUI + +java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* diff --git a/pmd-dist/src/main/scripts/designer.bat b/pmd-dist/src/main/scripts/designer.bat index de1d7acb95..efd95cbe29 100644 --- a/pmd-dist/src/main/scripts/designer.bat +++ b/pmd-dist/src/main/scripts/designer.bat @@ -1,6 +1,6 @@ -@echo off -set TOPDIR=%~dp0.. -set OPTS= -set MAIN_CLASS=net.sourceforge.pmd.util.designer.Designer - -java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* +@echo off +set TOPDIR=%~dp0.. +set OPTS= +set MAIN_CLASS=net.sourceforge.pmd.util.designer.Designer + +java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* diff --git a/pmd-dist/src/main/scripts/pmd.bat b/pmd-dist/src/main/scripts/pmd.bat index 309874d000..0c1c003b2b 100755 --- a/pmd-dist/src/main/scripts/pmd.bat +++ b/pmd-dist/src/main/scripts/pmd.bat @@ -1,6 +1,6 @@ -@echo off -set TOPDIR=%~dp0.. -set OPTS= -set MAIN_CLASS=net.sourceforge.pmd.PMD - -java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* +@echo off +set TOPDIR=%~dp0.. +set OPTS= +set MAIN_CLASS=net.sourceforge.pmd.PMD + +java -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %* diff --git a/pmd-fortran/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-fortran/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java index d62b64526c..e4cb577784 100644 --- a/pmd-fortran/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java +++ b/pmd-fortran/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java @@ -1,33 +1,33 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.runners.Parameterized.Parameters; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.fortran.FortranLanguageModule; - -public class LanguageVersionTest extends AbstractLanguageVersionTest { - - public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { - super(name, terseName, version, expected); - } - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { - { - FortranLanguageModule.NAME, - FortranLanguageModule.TERSE_NAME, - "", - LanguageRegistry.getLanguage(FortranLanguageModule.NAME).getDefaultVersion(), - }, - }); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.runners.Parameterized.Parameters; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.fortran.FortranLanguageModule; + +public class LanguageVersionTest extends AbstractLanguageVersionTest { + + public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { + super(name, terseName, version, expected); + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { + { + FortranLanguageModule.NAME, + FortranLanguageModule.TERSE_NAME, + "", + LanguageRegistry.getLanguage(FortranLanguageModule.NAME).getDefaultVersion(), + }, + }); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java index ded9824927..0969e1811a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java @@ -1,112 +1,112 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java; - -import java.io.Writer; - -import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; -import net.sourceforge.pmd.lang.DataFlowHandler; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.VisitorStarter; -import net.sourceforge.pmd.lang.XPathHandler; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; -import net.sourceforge.pmd.lang.dfa.DFAGraphRule; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.DumpFacade; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade; -import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule; -import net.sourceforge.pmd.lang.java.rule.JavaRuleViolationFactory; -import net.sourceforge.pmd.lang.java.symboltable.SymbolFacade; -import net.sourceforge.pmd.lang.java.typeresolution.TypeResolutionFacade; -import net.sourceforge.pmd.lang.java.xpath.GetCommentOnFunction; -import net.sourceforge.pmd.lang.java.xpath.JavaFunctions; -import net.sourceforge.pmd.lang.java.xpath.TypeOfFunction; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; - -import net.sf.saxon.sxpath.IndependentContext; - -/** - * Implementation of LanguageVersionHandler for the Java AST. It uses anonymous - * classes as adapters of the visitors to the VisitorStarter interface. - * - * @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be - */ -public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler { - - @Override - public DataFlowHandler getDataFlowHandler() { - return new JavaDataFlowHandler(); - } - - @Override - public XPathHandler getXPathHandler() { - return new AbstractASTXPathHandler() { - public void initialize() { - TypeOfFunction.registerSelfInSimpleContext(); - GetCommentOnFunction.registerSelfInSimpleContext(); - } - - public void initialize(IndependentContext context) { - super.initialize(context, LanguageRegistry.getLanguage(JavaLanguageModule.NAME), JavaFunctions.class); - } - }; - } - - public RuleViolationFactory getRuleViolationFactory() { - return JavaRuleViolationFactory.INSTANCE; - } - - @Override - public VisitorStarter getDataFlowFacade() { - return new VisitorStarter() { - public void start(Node rootNode) { - new DataFlowFacade().initializeWith(getDataFlowHandler(), (ASTCompilationUnit) rootNode); - } - }; - } - - @Override - public VisitorStarter getSymbolFacade() { - return new VisitorStarter() { - public void start(Node rootNode) { - new SymbolFacade().initializeWith(null, (ASTCompilationUnit) rootNode); - } - }; - } - - @Override - public VisitorStarter getSymbolFacade(final ClassLoader classLoader) { - return new VisitorStarter() { - public void start(Node rootNode) { - new SymbolFacade().initializeWith(classLoader, (ASTCompilationUnit) rootNode); - } - }; - } - - @Override - public VisitorStarter getTypeResolutionFacade(final ClassLoader classLoader) { - return new VisitorStarter() { - public void start(Node rootNode) { - new TypeResolutionFacade().initializeWith(classLoader, (ASTCompilationUnit) rootNode); - } - }; - } - - @Override - public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) { - return new VisitorStarter() { - public void start(Node rootNode) { - new DumpFacade().initializeWith(writer, prefix, recurse, (JavaNode) rootNode); - } - }; - } - - @Override - public DFAGraphRule getDFAGraphRule() { - return new JavaDFAGraphRule(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java; + +import java.io.Writer; + +import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; +import net.sourceforge.pmd.lang.DataFlowHandler; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.VisitorStarter; +import net.sourceforge.pmd.lang.XPathHandler; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; +import net.sourceforge.pmd.lang.dfa.DFAGraphRule; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.DumpFacade; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade; +import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule; +import net.sourceforge.pmd.lang.java.rule.JavaRuleViolationFactory; +import net.sourceforge.pmd.lang.java.symboltable.SymbolFacade; +import net.sourceforge.pmd.lang.java.typeresolution.TypeResolutionFacade; +import net.sourceforge.pmd.lang.java.xpath.GetCommentOnFunction; +import net.sourceforge.pmd.lang.java.xpath.JavaFunctions; +import net.sourceforge.pmd.lang.java.xpath.TypeOfFunction; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +import net.sf.saxon.sxpath.IndependentContext; + +/** + * Implementation of LanguageVersionHandler for the Java AST. It uses anonymous + * classes as adapters of the visitors to the VisitorStarter interface. + * + * @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be + */ +public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler { + + @Override + public DataFlowHandler getDataFlowHandler() { + return new JavaDataFlowHandler(); + } + + @Override + public XPathHandler getXPathHandler() { + return new AbstractASTXPathHandler() { + public void initialize() { + TypeOfFunction.registerSelfInSimpleContext(); + GetCommentOnFunction.registerSelfInSimpleContext(); + } + + public void initialize(IndependentContext context) { + super.initialize(context, LanguageRegistry.getLanguage(JavaLanguageModule.NAME), JavaFunctions.class); + } + }; + } + + public RuleViolationFactory getRuleViolationFactory() { + return JavaRuleViolationFactory.INSTANCE; + } + + @Override + public VisitorStarter getDataFlowFacade() { + return new VisitorStarter() { + public void start(Node rootNode) { + new DataFlowFacade().initializeWith(getDataFlowHandler(), (ASTCompilationUnit) rootNode); + } + }; + } + + @Override + public VisitorStarter getSymbolFacade() { + return new VisitorStarter() { + public void start(Node rootNode) { + new SymbolFacade().initializeWith(null, (ASTCompilationUnit) rootNode); + } + }; + } + + @Override + public VisitorStarter getSymbolFacade(final ClassLoader classLoader) { + return new VisitorStarter() { + public void start(Node rootNode) { + new SymbolFacade().initializeWith(classLoader, (ASTCompilationUnit) rootNode); + } + }; + } + + @Override + public VisitorStarter getTypeResolutionFacade(final ClassLoader classLoader) { + return new VisitorStarter() { + public void start(Node rootNode) { + new TypeResolutionFacade().initializeWith(classLoader, (ASTCompilationUnit) rootNode); + } + }; + } + + @Override + public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) { + return new VisitorStarter() { + public void start(Node rootNode) { + new DumpFacade().initializeWith(writer, prefix, recurse, (JavaNode) rootNode); + } + }; + } + + @Override + public DFAGraphRule getDFAGraphRule() { + return new JavaDFAGraphRule(); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaParser.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaParser.java index e31c523a35..a34e113b7f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaParser.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaParser.java @@ -1,63 +1,63 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java; - -import java.io.Reader; -import java.util.Map; - -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.AbstractTokenManager; -import net.sourceforge.pmd.lang.ast.JavaCharStream; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.JavaParser; -import net.sourceforge.pmd.lang.java.ast.ParseException; - -/** - * This is a generic Java specific implementation of the Parser interface. It - * creates a JavaParser instance, and sets the exclude marker. It also exposes - * the exclude map from the JavaParser instance. - * - * @see AbstractParser - * @see JavaParser - */ -public abstract class AbstractJavaParser extends AbstractParser { - private JavaParser parser; - - public AbstractJavaParser(ParserOptions parserOptions) { - super(parserOptions); - } - - @Override - public TokenManager createTokenManager(Reader source) { - return new JavaTokenManager(source); - } - - /** - * Subclass should override this method to modify the JavaParser as needed. - */ - protected JavaParser createJavaParser(Reader source) throws ParseException { - parser = new JavaParser(new JavaCharStream(source)); - String suppressMarker = getParserOptions().getSuppressMarker(); - if (suppressMarker != null) { - parser.setSuppressMarker(suppressMarker); - } - return parser; - } - - public boolean canParse() { - return true; - } - - public Node parse(String fileName, Reader source) throws ParseException { - AbstractTokenManager.setFileName(fileName); - return createJavaParser(source).CompilationUnit(); - } - - public Map getSuppressMap() { - return parser.getSuppressMap(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java; + +import java.io.Reader; +import java.util.Map; + +import net.sourceforge.pmd.lang.AbstractParser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.AbstractTokenManager; +import net.sourceforge.pmd.lang.ast.JavaCharStream; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.JavaParser; +import net.sourceforge.pmd.lang.java.ast.ParseException; + +/** + * This is a generic Java specific implementation of the Parser interface. It + * creates a JavaParser instance, and sets the exclude marker. It also exposes + * the exclude map from the JavaParser instance. + * + * @see AbstractParser + * @see JavaParser + */ +public abstract class AbstractJavaParser extends AbstractParser { + private JavaParser parser; + + public AbstractJavaParser(ParserOptions parserOptions) { + super(parserOptions); + } + + @Override + public TokenManager createTokenManager(Reader source) { + return new JavaTokenManager(source); + } + + /** + * Subclass should override this method to modify the JavaParser as needed. + */ + protected JavaParser createJavaParser(Reader source) throws ParseException { + parser = new JavaParser(new JavaCharStream(source)); + String suppressMarker = getParserOptions().getSuppressMarker(); + if (suppressMarker != null) { + parser.setSuppressMarker(suppressMarker); + } + return parser; + } + + public boolean canParse() { + return true; + } + + public Node parse(String fileName, Reader source) throws ParseException { + AbstractTokenManager.setFileName(fileName); + return createJavaParser(source).CompilationUnit(); + } + + public Map getSuppressMap() { + return parser.getSuppressMap(); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaDataFlowHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaDataFlowHandler.java index a8553fcc75..347aa2010c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaDataFlowHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaDataFlowHandler.java @@ -1,23 +1,23 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java; - -import java.util.List; - -import net.sourceforge.pmd.lang.DataFlowHandler; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.dfa.DataFlowNode; -import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement; -import net.sourceforge.pmd.lang.java.dfa.JavaDataFlowNode; - -public class JavaDataFlowHandler implements DataFlowHandler { - public DataFlowNode createDataFlowNode(List dataFlow, Node node) { - return new JavaDataFlowNode(dataFlow, node); - } - - public Class getLabelStatementNodeClass() { - return ASTLabeledStatement.class; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java; + +import java.util.List; + +import net.sourceforge.pmd.lang.DataFlowHandler; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.dfa.DataFlowNode; +import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement; +import net.sourceforge.pmd.lang.java.dfa.JavaDataFlowNode; + +public class JavaDataFlowHandler implements DataFlowHandler { + public DataFlowNode createDataFlowNode(List dataFlow, Node node) { + return new JavaDataFlowNode(dataFlow, node); + } + + public Class getLabelStatementNodeClass() { + return ASTLabeledStatement.class; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaTokenManager.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaTokenManager.java index d351393e61..7b4eb24a6e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaTokenManager.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaTokenManager.java @@ -1,30 +1,30 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java; - -import java.io.Reader; - -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.JavaCharStream; -import net.sourceforge.pmd.lang.java.ast.JavaParserTokenManager; - -/** - * Java Token Manager implementation. - */ -public class JavaTokenManager implements TokenManager { - private final JavaParserTokenManager tokenManager; - - public JavaTokenManager(Reader source) { - tokenManager = new JavaParserTokenManager(new JavaCharStream(source)); - } - - public Object getNextToken() { - return tokenManager.getNextToken(); - } - - public void setFileName(String fileName) { - tokenManager.setFileName(fileName); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java; + +import java.io.Reader; + +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.JavaCharStream; +import net.sourceforge.pmd.lang.java.ast.JavaParserTokenManager; + +/** + * Java Token Manager implementation. + */ +public class JavaTokenManager implements TokenManager { + private final JavaParserTokenManager tokenManager; + + public JavaTokenManager(Reader source) { + tokenManager = new JavaParserTokenManager(new JavaCharStream(source)); + } + + public Object getNextToken() { + return tokenManager.getNextToken(); + } + + public void setFileName(String fileName) { + tokenManager.setFileName(fileName); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java index 2c37fb4291..4681413195 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java @@ -1,26 +1,26 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ -/* Generated By:JJTree: Do not edit this line. ASTAnnotationMethodDeclaration.java Version 4.1 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ - -package net.sourceforge.pmd.lang.java.ast; - -public class ASTAnnotationMethodDeclaration extends AbstractJavaAccessNode { - public ASTAnnotationMethodDeclaration(int id) { - super(id); - } - - public ASTAnnotationMethodDeclaration(JavaParser p, int id) { - super(p, id); - } - - /** Accept the visitor. **/ - public Object jjtAccept(JavaParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} -/* - * JavaCC - OriginalChecksum=f6dd440446f8aa5c9c191ae760080ee0 (do not edit this - * line) - */ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +/* Generated By:JJTree: Do not edit this line. ASTAnnotationMethodDeclaration.java Version 4.1 */ +/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ + +package net.sourceforge.pmd.lang.java.ast; + +public class ASTAnnotationMethodDeclaration extends AbstractJavaAccessNode { + public ASTAnnotationMethodDeclaration(int id) { + super(id); + } + + public ASTAnnotationMethodDeclaration(JavaParser p, int id) { + super(p, id); + } + + /** Accept the visitor. **/ + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} +/* + * JavaCC - OriginalChecksum=f6dd440446f8aa5c9c191ae760080ee0 (do not edit this + * line) + */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java index 670f54148b..a63b514159 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java @@ -1,140 +1,140 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -public abstract class AbstractJavaAccessNode extends AbstractJavaNode implements AccessNode { - - private int modifiers; - - public AbstractJavaAccessNode(int i) { - super(i); - } - - public AbstractJavaAccessNode(JavaParser parser, int i) { - super(parser, i); - } - - public int getModifiers() { - return this.modifiers; - } - - public void setModifiers(int modifiers) { - this.modifiers = modifiers; - } - - public boolean isPublic() { - return isModifier(PUBLIC); - } - - public void setPublic(boolean isPublic) { - setModifier(isPublic, PUBLIC); - } - - public boolean isProtected() { - return isModifier(PROTECTED); - } - - public void setProtected(boolean isProtected) { - setModifier(isProtected, PROTECTED); - } - - public boolean isPrivate() { - return isModifier(PRIVATE); - } - - public void setPrivate(boolean isPrivate) { - setModifier(isPrivate, PRIVATE); - } - - public boolean isAbstract() { - return isModifier(ABSTRACT); - } - - public void setAbstract(boolean isAbstract) { - setModifier(isAbstract, ABSTRACT); - } - - public boolean isStatic() { - return isModifier(STATIC); - } - - public void setStatic(boolean isStatic) { - setModifier(isStatic, STATIC); - } - - public boolean isFinal() { - return isModifier(FINAL); - } - - public void setFinal(boolean isFinal) { - setModifier(isFinal, FINAL); - } - - public boolean isSynchronized() { - return isModifier(SYNCHRONIZED); - } - - public void setSynchronized(boolean isSynchronized) { - setModifier(isSynchronized, SYNCHRONIZED); - } - - public boolean isNative() { - return isModifier(NATIVE); - } - - public void setNative(boolean isNative) { - setModifier(isNative, NATIVE); - } - - public boolean isTransient() { - return isModifier(TRANSIENT); - } - - public void setTransient(boolean isTransient) { - setModifier(isTransient, TRANSIENT); - } - - public boolean isVolatile() { - return isModifier(VOLATILE); - } - - public void setVolatile(boolean isVolative) { - setModifier(isVolative, VOLATILE); - } - - public boolean isStrictfp() { - return isModifier(STRICTFP); - } - - public void setStrictfp(boolean isStrictfp) { - setModifier(isStrictfp, STRICTFP); - } - - public boolean isDefault() { - return isModifier(DEFAULT); - } - - public void setDefault(boolean isDefault) { - setModifier(isDefault, DEFAULT); - } - - // TODO: fix the rule - around binary expressions the parentheses are needed... - @SuppressWarnings("PMD.UselessParentheses") - private boolean isModifier(int mask) { - return (modifiers & mask) == mask; - } - - private void setModifier(boolean enable, int mask) { - if (enable) { - this.modifiers |= mask; - } else { - this.modifiers &= ~mask; - } - } - - public boolean isPackagePrivate() { - return !isPrivate() && !isPublic() && !isProtected(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +public abstract class AbstractJavaAccessNode extends AbstractJavaNode implements AccessNode { + + private int modifiers; + + public AbstractJavaAccessNode(int i) { + super(i); + } + + public AbstractJavaAccessNode(JavaParser parser, int i) { + super(parser, i); + } + + public int getModifiers() { + return this.modifiers; + } + + public void setModifiers(int modifiers) { + this.modifiers = modifiers; + } + + public boolean isPublic() { + return isModifier(PUBLIC); + } + + public void setPublic(boolean isPublic) { + setModifier(isPublic, PUBLIC); + } + + public boolean isProtected() { + return isModifier(PROTECTED); + } + + public void setProtected(boolean isProtected) { + setModifier(isProtected, PROTECTED); + } + + public boolean isPrivate() { + return isModifier(PRIVATE); + } + + public void setPrivate(boolean isPrivate) { + setModifier(isPrivate, PRIVATE); + } + + public boolean isAbstract() { + return isModifier(ABSTRACT); + } + + public void setAbstract(boolean isAbstract) { + setModifier(isAbstract, ABSTRACT); + } + + public boolean isStatic() { + return isModifier(STATIC); + } + + public void setStatic(boolean isStatic) { + setModifier(isStatic, STATIC); + } + + public boolean isFinal() { + return isModifier(FINAL); + } + + public void setFinal(boolean isFinal) { + setModifier(isFinal, FINAL); + } + + public boolean isSynchronized() { + return isModifier(SYNCHRONIZED); + } + + public void setSynchronized(boolean isSynchronized) { + setModifier(isSynchronized, SYNCHRONIZED); + } + + public boolean isNative() { + return isModifier(NATIVE); + } + + public void setNative(boolean isNative) { + setModifier(isNative, NATIVE); + } + + public boolean isTransient() { + return isModifier(TRANSIENT); + } + + public void setTransient(boolean isTransient) { + setModifier(isTransient, TRANSIENT); + } + + public boolean isVolatile() { + return isModifier(VOLATILE); + } + + public void setVolatile(boolean isVolative) { + setModifier(isVolative, VOLATILE); + } + + public boolean isStrictfp() { + return isModifier(STRICTFP); + } + + public void setStrictfp(boolean isStrictfp) { + setModifier(isStrictfp, STRICTFP); + } + + public boolean isDefault() { + return isModifier(DEFAULT); + } + + public void setDefault(boolean isDefault) { + setModifier(isDefault, DEFAULT); + } + + // TODO: fix the rule - around binary expressions the parentheses are needed... + @SuppressWarnings("PMD.UselessParentheses") + private boolean isModifier(int mask) { + return (modifiers & mask) == mask; + } + + private void setModifier(boolean enable, int mask) { + if (enable) { + this.modifiers |= mask; + } else { + this.modifiers &= ~mask; + } + } + + public boolean isPackagePrivate() { + return !isPrivate() && !isPublic() && !isProtected(); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java index 1f3e5b7bba..cb19cbbc36 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java @@ -1,28 +1,28 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode implements TypeNode { - - private Class type; - - public AbstractJavaAccessTypeNode(int i) { - super(i); - } - - public AbstractJavaAccessTypeNode(JavaParser parser, int i) { - super(parser, i); - } - - @Override - public Class getType() { - return type; - } - - @Override - public void setType(Class type) { - this.type = type; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode implements TypeNode { + + private Class type; + + public AbstractJavaAccessTypeNode(int i) { + super(i); + } + + public AbstractJavaAccessTypeNode(JavaParser parser, int i) { + super(parser, i); + } + + @Override + public Class getType() { + return type; + } + + @Override + public void setType(Class type) { + this.type = type; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java index 866f03dbb2..039780fcf6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java @@ -1,34 +1,34 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -/** - * An extension of the SimpleJavaNode which implements the TypeNode interface. - * - * @see AbstractJavaNode - * @see TypeNode - */ -public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements TypeNode { - - private Class type; - - public AbstractJavaTypeNode(int i) { - super(i); - } - - public AbstractJavaTypeNode(JavaParser p, int i) { - super(p, i); - } - - @Override - public Class getType() { - return type; - } - - @Override - public void setType(Class type) { - this.type = type; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +/** + * An extension of the SimpleJavaNode which implements the TypeNode interface. + * + * @see AbstractJavaNode + * @see TypeNode + */ +public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements TypeNode { + + private Class type; + + public AbstractJavaTypeNode(int i) { + super(i); + } + + public AbstractJavaTypeNode(JavaParser p, int i) { + super(p, i); + } + + @Override + public Class getType() { + return type; + } + + @Override + public void setType(Class type) { + this.type = type; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java index 67277f5e8a..66fef23b38 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java @@ -1,255 +1,255 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -public class DumpFacade extends JavaParserVisitorAdapter { - - private PrintWriter writer; - private boolean recurse; - - public void initializeWith(Writer writer, String prefix, boolean recurse, JavaNode node) { - this.writer = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer); - this.recurse = recurse; - this.visit(node, prefix); - try { - writer.flush(); - } catch (IOException e) { - throw new RuntimeException("Problem flushing PrintWriter.", e); - } - } - - @Override - public Object visit(JavaNode node, Object data) { - dump(node, (String) data); - if (recurse) { - return super.visit(node, data + " "); - } else { - return data; - } - } - - private void dump(JavaNode node, String prefix) { - // - // Dump format is generally composed of the following items... - // - - // 1) Dump prefix - writer.print(prefix); - - // 2) JJT Name of the Node - writer.print(node.toString()); - - // - // If there are any additional details, then: - // 1) A colon - // 2) The Node.getImage() if it is non-empty - // 3) Extras in parentheses - // - - // Standard image handling - String image = node.getImage(); - - // Special image handling (e.g. Nodes with normally null images) - if (node instanceof ASTBooleanLiteral) { - image = String.valueOf(((ASTBooleanLiteral) node).isTrue()); - } else if (node instanceof ASTPrimaryPrefix) { - ASTPrimaryPrefix primaryPrefix = (ASTPrimaryPrefix) node; - String result = null; - if (primaryPrefix.usesSuperModifier()) { - result = "super"; - } else if (primaryPrefix.usesThisModifier()) { - result = "this"; - } - if (image != null) { - result += "." + image; - } - image = result; - } else if (node instanceof ASTPrimarySuffix) { - ASTPrimarySuffix primarySuffix = (ASTPrimarySuffix) node; - if (primarySuffix.isArrayDereference()) { - if (image == null) { - image = "["; - } else { - image = "[" + image; - } - } - } - - // Extras - List extras = new ArrayList<>(); - - collectModifiers(node, extras); - - // Standard Dimensionable extras - if (node instanceof Dimensionable) { - Dimensionable dimensionable = (Dimensionable) node; - if (dimensionable.isArray()) { - StringBuilder extra = new StringBuilder("array"); - for (int i = 0; i < dimensionable.getArrayDepth(); i++) { - extra.append('['); - } - extras.add(extra.toString()); - } - } - - // Other extras - if (node instanceof ASTArguments) { - extras.add(String.valueOf(((ASTArguments) node).getArgumentCount())); - } else if (node instanceof ASTAssignmentOperator) { - extras.add(((ASTAssignmentOperator) node).isCompound() ? "compound" : "simple"); - } else if (node instanceof ASTClassOrInterfaceBodyDeclaration) { - if (((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) { - extras.add("anonymous inner class"); - } - if (((ASTClassOrInterfaceBodyDeclaration) node).isEnumChild()) { - extras.add("enum child"); - } - } else if (node instanceof ASTBlock) { - if (((ASTBlock) node).containsComment()) { - extras.add("contains comment"); - } - } else if (node instanceof ASTClassOrInterfaceDeclaration) { - extras.add(((ASTClassOrInterfaceDeclaration) node).isInterface() ? "interface" : "class"); - if (((ASTClassOrInterfaceDeclaration) node).isNested()) { - extras.add("nested"); - } - } else if (node instanceof ASTConditionalExpression) { - if (((ASTConditionalExpression) node).isTernary()) { - extras.add("ternary"); - } - } else if (node instanceof ASTConstructorDeclaration) { - extras.add(String.valueOf(((ASTConstructorDeclaration) node).getParameterCount())); - if (((ASTConstructorDeclaration) node).containsComment()) { - extras.add("contains comment"); - } - } else if (node instanceof ASTExplicitConstructorInvocation) { - extras.add(String.valueOf(((ASTExplicitConstructorInvocation) node).getArgumentCount())); - if (((ASTExplicitConstructorInvocation) node).isThis()) { - extras.add("this"); - } - if (((ASTExplicitConstructorInvocation) node).isSuper()) { - extras.add("super"); - } - } else if (node instanceof ASTFormalParameter) { - if (((ASTFormalParameter) node).isVarargs()) { - extras.add("varargs"); - } - } else if (node instanceof ASTFormalParameters) { - extras.add(String.valueOf(((ASTFormalParameters) node).getParameterCount())); - } else if (node instanceof ASTIfStatement) { - if (((ASTIfStatement) node).hasElse()) { - extras.add("has else"); - } - } else if (node instanceof ASTImportDeclaration) { - if (((ASTImportDeclaration) node).isImportOnDemand()) { - extras.add("on demand"); - } - if (((ASTImportDeclaration) node).isStatic()) { - extras.add("static"); - } - } else if (node instanceof ASTInitializer) { - extras.add(((ASTInitializer) node).isStatic() ? "static" : "nonstatic"); - } else if (node instanceof ASTLiteral) { - ASTLiteral literal = (ASTLiteral) node; - if (literal.isCharLiteral()) { - extras.add("char style"); - } - if (literal.isIntLiteral()) { - extras.add("int style"); - } - if (literal.isFloatLiteral()) { - extras.add("float style"); - } - if (literal.isStringLiteral()) { - extras.add("String style"); - } - if (literal.isDoubleLiteral()) { - extras.add("double style"); - } - if (literal.isLongLiteral()) { - extras.add("long style"); - } - } else if (node instanceof ASTResultType) { - if (((ASTResultType) node).isVoid()) { - extras.add("void"); - } - if (((ASTResultType) node).returnsArray()) { - extras.add("returns array"); - } - } else if (node instanceof ASTSwitchLabel) { - if (((ASTSwitchLabel) node).isDefault()) { - extras.add("default"); - } - } else if (node instanceof ASTTryStatement) { - if (((ASTTryStatement) node).hasFinally()) { - extras.add("has finally"); - } - } - - // Output image and extras - if (image != null || !extras.isEmpty()) { - writer.print(':'); - if (image != null) { - writer.print(image); - } - for (String extra : extras) { - writer.print('('); - writer.print(extra); - writer.print(')'); - } - } - - writer.println(); - } - - private void collectModifiers(JavaNode node, List extras) { - // Standard AccessNode extras - if (node instanceof AccessNode) { - AccessNode accessNode = (AccessNode) node; - if (accessNode.isPackagePrivate()) { - extras.add("package private"); - } - if (accessNode.isPrivate()) { - extras.add("private"); - } - if (accessNode.isPublic()) { - extras.add("public"); - } - if (accessNode.isProtected()) { - extras.add("protected"); - } - if (accessNode.isAbstract()) { - extras.add("abstract"); - } - if (accessNode.isStatic()) { - extras.add("static"); - } - if (accessNode.isFinal()) { - extras.add("final"); - } - if (accessNode.isSynchronized()) { - extras.add("synchronized"); - } - if (accessNode.isNative()) { - extras.add("native"); - } - if (accessNode.isStrictfp()) { - extras.add("strict"); - } - if (accessNode.isTransient()) { - extras.add("transient"); - } - if (accessNode.isDefault()) { - extras.add("default"); - } - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +public class DumpFacade extends JavaParserVisitorAdapter { + + private PrintWriter writer; + private boolean recurse; + + public void initializeWith(Writer writer, String prefix, boolean recurse, JavaNode node) { + this.writer = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer); + this.recurse = recurse; + this.visit(node, prefix); + try { + writer.flush(); + } catch (IOException e) { + throw new RuntimeException("Problem flushing PrintWriter.", e); + } + } + + @Override + public Object visit(JavaNode node, Object data) { + dump(node, (String) data); + if (recurse) { + return super.visit(node, data + " "); + } else { + return data; + } + } + + private void dump(JavaNode node, String prefix) { + // + // Dump format is generally composed of the following items... + // + + // 1) Dump prefix + writer.print(prefix); + + // 2) JJT Name of the Node + writer.print(node.toString()); + + // + // If there are any additional details, then: + // 1) A colon + // 2) The Node.getImage() if it is non-empty + // 3) Extras in parentheses + // + + // Standard image handling + String image = node.getImage(); + + // Special image handling (e.g. Nodes with normally null images) + if (node instanceof ASTBooleanLiteral) { + image = String.valueOf(((ASTBooleanLiteral) node).isTrue()); + } else if (node instanceof ASTPrimaryPrefix) { + ASTPrimaryPrefix primaryPrefix = (ASTPrimaryPrefix) node; + String result = null; + if (primaryPrefix.usesSuperModifier()) { + result = "super"; + } else if (primaryPrefix.usesThisModifier()) { + result = "this"; + } + if (image != null) { + result += "." + image; + } + image = result; + } else if (node instanceof ASTPrimarySuffix) { + ASTPrimarySuffix primarySuffix = (ASTPrimarySuffix) node; + if (primarySuffix.isArrayDereference()) { + if (image == null) { + image = "["; + } else { + image = "[" + image; + } + } + } + + // Extras + List extras = new ArrayList<>(); + + collectModifiers(node, extras); + + // Standard Dimensionable extras + if (node instanceof Dimensionable) { + Dimensionable dimensionable = (Dimensionable) node; + if (dimensionable.isArray()) { + StringBuilder extra = new StringBuilder("array"); + for (int i = 0; i < dimensionable.getArrayDepth(); i++) { + extra.append('['); + } + extras.add(extra.toString()); + } + } + + // Other extras + if (node instanceof ASTArguments) { + extras.add(String.valueOf(((ASTArguments) node).getArgumentCount())); + } else if (node instanceof ASTAssignmentOperator) { + extras.add(((ASTAssignmentOperator) node).isCompound() ? "compound" : "simple"); + } else if (node instanceof ASTClassOrInterfaceBodyDeclaration) { + if (((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) { + extras.add("anonymous inner class"); + } + if (((ASTClassOrInterfaceBodyDeclaration) node).isEnumChild()) { + extras.add("enum child"); + } + } else if (node instanceof ASTBlock) { + if (((ASTBlock) node).containsComment()) { + extras.add("contains comment"); + } + } else if (node instanceof ASTClassOrInterfaceDeclaration) { + extras.add(((ASTClassOrInterfaceDeclaration) node).isInterface() ? "interface" : "class"); + if (((ASTClassOrInterfaceDeclaration) node).isNested()) { + extras.add("nested"); + } + } else if (node instanceof ASTConditionalExpression) { + if (((ASTConditionalExpression) node).isTernary()) { + extras.add("ternary"); + } + } else if (node instanceof ASTConstructorDeclaration) { + extras.add(String.valueOf(((ASTConstructorDeclaration) node).getParameterCount())); + if (((ASTConstructorDeclaration) node).containsComment()) { + extras.add("contains comment"); + } + } else if (node instanceof ASTExplicitConstructorInvocation) { + extras.add(String.valueOf(((ASTExplicitConstructorInvocation) node).getArgumentCount())); + if (((ASTExplicitConstructorInvocation) node).isThis()) { + extras.add("this"); + } + if (((ASTExplicitConstructorInvocation) node).isSuper()) { + extras.add("super"); + } + } else if (node instanceof ASTFormalParameter) { + if (((ASTFormalParameter) node).isVarargs()) { + extras.add("varargs"); + } + } else if (node instanceof ASTFormalParameters) { + extras.add(String.valueOf(((ASTFormalParameters) node).getParameterCount())); + } else if (node instanceof ASTIfStatement) { + if (((ASTIfStatement) node).hasElse()) { + extras.add("has else"); + } + } else if (node instanceof ASTImportDeclaration) { + if (((ASTImportDeclaration) node).isImportOnDemand()) { + extras.add("on demand"); + } + if (((ASTImportDeclaration) node).isStatic()) { + extras.add("static"); + } + } else if (node instanceof ASTInitializer) { + extras.add(((ASTInitializer) node).isStatic() ? "static" : "nonstatic"); + } else if (node instanceof ASTLiteral) { + ASTLiteral literal = (ASTLiteral) node; + if (literal.isCharLiteral()) { + extras.add("char style"); + } + if (literal.isIntLiteral()) { + extras.add("int style"); + } + if (literal.isFloatLiteral()) { + extras.add("float style"); + } + if (literal.isStringLiteral()) { + extras.add("String style"); + } + if (literal.isDoubleLiteral()) { + extras.add("double style"); + } + if (literal.isLongLiteral()) { + extras.add("long style"); + } + } else if (node instanceof ASTResultType) { + if (((ASTResultType) node).isVoid()) { + extras.add("void"); + } + if (((ASTResultType) node).returnsArray()) { + extras.add("returns array"); + } + } else if (node instanceof ASTSwitchLabel) { + if (((ASTSwitchLabel) node).isDefault()) { + extras.add("default"); + } + } else if (node instanceof ASTTryStatement) { + if (((ASTTryStatement) node).hasFinally()) { + extras.add("has finally"); + } + } + + // Output image and extras + if (image != null || !extras.isEmpty()) { + writer.print(':'); + if (image != null) { + writer.print(image); + } + for (String extra : extras) { + writer.print('('); + writer.print(extra); + writer.print(')'); + } + } + + writer.println(); + } + + private void collectModifiers(JavaNode node, List extras) { + // Standard AccessNode extras + if (node instanceof AccessNode) { + AccessNode accessNode = (AccessNode) node; + if (accessNode.isPackagePrivate()) { + extras.add("package private"); + } + if (accessNode.isPrivate()) { + extras.add("private"); + } + if (accessNode.isPublic()) { + extras.add("public"); + } + if (accessNode.isProtected()) { + extras.add("protected"); + } + if (accessNode.isAbstract()) { + extras.add("abstract"); + } + if (accessNode.isStatic()) { + extras.add("static"); + } + if (accessNode.isFinal()) { + extras.add("final"); + } + if (accessNode.isSynchronized()) { + extras.add("synchronized"); + } + if (accessNode.isNative()) { + extras.add("native"); + } + if (accessNode.isStrictfp()) { + extras.add("strict"); + } + if (accessNode.isTransient()) { + extras.add("transient"); + } + if (accessNode.isDefault()) { + extras.add("default"); + } + } + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/JavaDataFlowNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/JavaDataFlowNode.java index 99faaeaf66..aee3c7d5ea 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/JavaDataFlowNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/JavaDataFlowNode.java @@ -1,30 +1,30 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.dfa; - -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.dfa.AbstractDataFlowNode; -import net.sourceforge.pmd.lang.dfa.DataFlowNode; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; - -public class JavaDataFlowNode extends AbstractDataFlowNode { - - public JavaDataFlowNode(List dataFlow, Node node) { - super(dataFlow, node); - } - - public String toString() { - String res = "DataFlowNode: line " + this.getLine() + ", "; - if (node instanceof ASTMethodDeclaration || node instanceof ASTConstructorDeclaration) { - res += node instanceof ASTMethodDeclaration ? "(method)" : "(constructor)"; - } else { - res = super.toString(); - } - return res; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.dfa; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.dfa.AbstractDataFlowNode; +import net.sourceforge.pmd.lang.dfa.DataFlowNode; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; + +public class JavaDataFlowNode extends AbstractDataFlowNode { + + public JavaDataFlowNode(List dataFlow, Node node) { + super(dataFlow, node); + } + + public String toString() { + String res = "DataFlowNode: line " + this.getLine() + ", "; + if (node instanceof ASTMethodDeclaration || node instanceof ASTConstructorDeclaration) { + res += node instanceof ASTMethodDeclaration ? "(method)" : "(constructor)"; + } else { + res = super.toString(); + } + return res; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractStatisticalJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractStatisticalJavaRule.java index c43a022070..ae43ab56d7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractStatisticalJavaRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractStatisticalJavaRule.java @@ -1,32 +1,32 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule; - -import java.util.List; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.rule.stat.StatisticalRule; -import net.sourceforge.pmd.lang.rule.stat.StatisticalRuleHelper; -import net.sourceforge.pmd.stat.DataPoint; - -public abstract class AbstractStatisticalJavaRule extends AbstractJavaRule implements StatisticalRule { - - private final StatisticalRuleHelper helper = new StatisticalRuleHelper(this); - - public void addDataPoint(DataPoint point) { - helper.addDataPoint(point); - } - - public Object[] getViolationParameters(DataPoint point) { - return null; - } - - @Override - public void apply(List nodes, RuleContext ctx) { - super.apply(nodes, ctx); - helper.apply(ctx); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule; + +import java.util.List; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.stat.StatisticalRule; +import net.sourceforge.pmd.lang.rule.stat.StatisticalRuleHelper; +import net.sourceforge.pmd.stat.DataPoint; + +public abstract class AbstractStatisticalJavaRule extends AbstractJavaRule implements StatisticalRule { + + private final StatisticalRuleHelper helper = new StatisticalRuleHelper(this); + + public void addDataPoint(DataPoint point) { + helper.addDataPoint(point); + } + + public Object[] getViolationParameters(DataPoint point) { + return null; + } + + @Override + public void apply(List nodes, RuleContext ctx) { + super.apply(nodes, ctx); + helper.apply(ctx); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java index 5373646f03..be8622ae03 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java @@ -1,148 +1,148 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule; - -import java.util.Set; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.ast.AccessNode; -import net.sourceforge.pmd.lang.java.ast.CanSuppressWarnings; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.symboltable.ClassNameDeclaration; -import net.sourceforge.pmd.lang.java.symboltable.ClassScope; -import net.sourceforge.pmd.lang.java.symboltable.MethodScope; -import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope; -import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; -import net.sourceforge.pmd.lang.symboltable.Scope; - -/** - * This is a Java RuleViolation. It knows how to try to extract the following - * extra information from the violation node: - *

    - *
  • Package name
  • - *
  • Class name
  • - *
  • Method name
  • - *
  • Variable name
  • - *
  • Suppression indicator
  • - *
- */ -public class JavaRuleViolation extends ParametricRuleViolation { - - public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message, int beginLine, int endLine) { - this(rule, ctx, node, message); - - setLines(beginLine, endLine); - } - - public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message) { - super(rule, ctx, node, message); - - if (node != null) { - final Scope scope = node.getScope(); - final SourceFileScope sourceFileScope = scope.getEnclosingScope(SourceFileScope.class); - - // Package name is on SourceFileScope - packageName = sourceFileScope.getPackageName() == null ? "" : sourceFileScope.getPackageName(); - - // Class name is built from enclosing ClassScopes - setClassNameFrom(node); - - // Method name comes from 1st enclosing MethodScope - if (scope.getEnclosingScope(MethodScope.class) != null) { - methodName = scope.getEnclosingScope(MethodScope.class).getName(); - } - // Variable name node specific - setVariableNameIfExists(node); - - if (!suppressed) { - suppressed = isSupressed(node, getRule()); - } - } - } - - /** - * Check for suppression on this node, on parents, and on contained types - * for ASTCompilationUnit - * - * @param node - */ - public static boolean isSupressed(Node node, Rule rule) { - boolean result = suppresses(node, rule); - - if (!result && node instanceof ASTCompilationUnit) { - for (int i = 0; !result && i < node.jjtGetNumChildren(); i++) { - result = suppresses(node.jjtGetChild(i), rule); - } - } - if (!result) { - Node parent = node.jjtGetParent(); - while (!result && parent != null) { - result = suppresses(parent, rule); - parent = parent.jjtGetParent(); - } - } - return result; - } - - private void setClassNameFrom(JavaNode node) { - String qualifiedName = null; - for (ASTClassOrInterfaceDeclaration parent : node.getParentsOfType(ASTClassOrInterfaceDeclaration.class)) { - String clsName = parent.getScope().getEnclosingScope(ClassScope.class).getClassName(); - if (qualifiedName == null) { - qualifiedName = clsName; - } else { - qualifiedName = clsName + '$' + qualifiedName; - } - } - - if (qualifiedName == null) { - Set classes = node.getScope().getEnclosingScope(SourceFileScope.class) - .getClassDeclarations().keySet(); - for (ClassNameDeclaration c : classes) { - // find the first public class/enum declaration - if (c.getAccessNodeParent() instanceof AccessNode) { - if (((AccessNode) c.getAccessNodeParent()).isPublic()) { - qualifiedName = c.getImage(); - break; - } - } - } - } - - if (qualifiedName != null) { - className = qualifiedName; - } - } - - private static boolean suppresses(final Node node, Rule rule) { - return node instanceof CanSuppressWarnings - && ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule); - } - - private void setVariableNameIfExists(Node node) { - if (node instanceof ASTFieldDeclaration) { - variableName = ((ASTFieldDeclaration) node).getVariableName(); - } else if (node instanceof ASTLocalVariableDeclaration) { - variableName = ((ASTLocalVariableDeclaration) node).getVariableName(); - } else if (node instanceof ASTVariableDeclarator) { - variableName = node.jjtGetChild(0).getImage(); - } else if (node instanceof ASTVariableDeclaratorId) { - variableName = node.getImage(); - } else if (node instanceof ASTFormalParameter) { - setVariableNameIfExists(node.getFirstChildOfType(ASTVariableDeclaratorId.class)); - } else { - variableName = ""; - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule; + +import java.util.Set; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.ast.CanSuppressWarnings; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.symboltable.ClassNameDeclaration; +import net.sourceforge.pmd.lang.java.symboltable.ClassScope; +import net.sourceforge.pmd.lang.java.symboltable.MethodScope; +import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope; +import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; +import net.sourceforge.pmd.lang.symboltable.Scope; + +/** + * This is a Java RuleViolation. It knows how to try to extract the following + * extra information from the violation node: + *
    + *
  • Package name
  • + *
  • Class name
  • + *
  • Method name
  • + *
  • Variable name
  • + *
  • Suppression indicator
  • + *
+ */ +public class JavaRuleViolation extends ParametricRuleViolation { + + public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message, int beginLine, int endLine) { + this(rule, ctx, node, message); + + setLines(beginLine, endLine); + } + + public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message) { + super(rule, ctx, node, message); + + if (node != null) { + final Scope scope = node.getScope(); + final SourceFileScope sourceFileScope = scope.getEnclosingScope(SourceFileScope.class); + + // Package name is on SourceFileScope + packageName = sourceFileScope.getPackageName() == null ? "" : sourceFileScope.getPackageName(); + + // Class name is built from enclosing ClassScopes + setClassNameFrom(node); + + // Method name comes from 1st enclosing MethodScope + if (scope.getEnclosingScope(MethodScope.class) != null) { + methodName = scope.getEnclosingScope(MethodScope.class).getName(); + } + // Variable name node specific + setVariableNameIfExists(node); + + if (!suppressed) { + suppressed = isSupressed(node, getRule()); + } + } + } + + /** + * Check for suppression on this node, on parents, and on contained types + * for ASTCompilationUnit + * + * @param node + */ + public static boolean isSupressed(Node node, Rule rule) { + boolean result = suppresses(node, rule); + + if (!result && node instanceof ASTCompilationUnit) { + for (int i = 0; !result && i < node.jjtGetNumChildren(); i++) { + result = suppresses(node.jjtGetChild(i), rule); + } + } + if (!result) { + Node parent = node.jjtGetParent(); + while (!result && parent != null) { + result = suppresses(parent, rule); + parent = parent.jjtGetParent(); + } + } + return result; + } + + private void setClassNameFrom(JavaNode node) { + String qualifiedName = null; + for (ASTClassOrInterfaceDeclaration parent : node.getParentsOfType(ASTClassOrInterfaceDeclaration.class)) { + String clsName = parent.getScope().getEnclosingScope(ClassScope.class).getClassName(); + if (qualifiedName == null) { + qualifiedName = clsName; + } else { + qualifiedName = clsName + '$' + qualifiedName; + } + } + + if (qualifiedName == null) { + Set classes = node.getScope().getEnclosingScope(SourceFileScope.class) + .getClassDeclarations().keySet(); + for (ClassNameDeclaration c : classes) { + // find the first public class/enum declaration + if (c.getAccessNodeParent() instanceof AccessNode) { + if (((AccessNode) c.getAccessNodeParent()).isPublic()) { + qualifiedName = c.getImage(); + break; + } + } + } + } + + if (qualifiedName != null) { + className = qualifiedName; + } + } + + private static boolean suppresses(final Node node, Rule rule) { + return node instanceof CanSuppressWarnings + && ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule); + } + + private void setVariableNameIfExists(Node node) { + if (node instanceof ASTFieldDeclaration) { + variableName = ((ASTFieldDeclaration) node).getVariableName(); + } else if (node instanceof ASTLocalVariableDeclaration) { + variableName = ((ASTLocalVariableDeclaration) node).getVariableName(); + } else if (node instanceof ASTVariableDeclarator) { + variableName = node.jjtGetChild(0).getImage(); + } else if (node instanceof ASTVariableDeclaratorId) { + variableName = node.getImage(); + } else if (node instanceof ASTFormalParameter) { + setVariableNameIfExists(node.getFirstChildOfType(ASTVariableDeclaratorId.class)); + } else { + variableName = ""; + } + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationFactory.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationFactory.java index 3301b96808..0c09a95cde 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationFactory.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationFactory.java @@ -1,33 +1,33 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; - -public final class JavaRuleViolationFactory extends AbstractRuleViolationFactory { - - public static final RuleViolationFactory INSTANCE = new JavaRuleViolationFactory(); - - private JavaRuleViolationFactory() { - } - - @Override - protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) { - return new JavaRuleViolation(rule, ruleContext, (JavaNode) node, message); - } - - @Override - protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, - int beginLine, int endLine) { - return new JavaRuleViolation(rule, ruleContext, (JavaNode) node, message, beginLine, endLine); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +public final class JavaRuleViolationFactory extends AbstractRuleViolationFactory { + + public static final RuleViolationFactory INSTANCE = new JavaRuleViolationFactory(); + + private JavaRuleViolationFactory() { + } + + @Override + protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) { + return new JavaRuleViolation(rule, ruleContext, (JavaNode) node, message); + } + + @Override + protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, + int beginLine, int endLine) { + return new JavaRuleViolation(rule, ruleContext, (JavaNode) node, message, beginLine, endLine); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidBranchingStatementAsLastInLoopRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidBranchingStatementAsLastInLoopRule.java index 6b1f044d0f..008195c95c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidBranchingStatementAsLastInLoopRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidBranchingStatementAsLastInLoopRule.java @@ -1,109 +1,109 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.basic; - -import net.sourceforge.pmd.PropertySource; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement; -import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement; -import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; -import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.EnumeratedMultiProperty; - -public class AvoidBranchingStatementAsLastInLoopRule extends AbstractJavaRule { - - public static final String CHECK_FOR = "for"; - public static final String CHECK_DO = "do"; - public static final String CHECK_WHILE = "while"; - - private static final String[] ALL_LOOP_TYPES_LABELS = new String[] { CHECK_FOR, CHECK_DO, CHECK_WHILE }; - private static final String[] ALL_LOOP_TYPES_VALUES = ALL_LOOP_TYPES_LABELS; - private static final int[] ALL_LOOP_TYPES_DEFAULTS = new int[] { 0, 1, 2 }; - - public static final EnumeratedMultiProperty CHECK_BREAK_LOOP_TYPES = new EnumeratedMultiProperty<>( - "checkBreakLoopTypes", "Check for break statements in loop types", ALL_LOOP_TYPES_LABELS, - ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 1); - public static final EnumeratedMultiProperty CHECK_CONTINUE_LOOP_TYPES = new EnumeratedMultiProperty<>( - "checkContinueLoopTypes", "Check for continue statements in loop types", ALL_LOOP_TYPES_LABELS, - ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 2); - public static final EnumeratedMultiProperty CHECK_RETURN_LOOP_TYPES = new EnumeratedMultiProperty<>( - "checkReturnLoopTypes", "Check for return statements in loop types", ALL_LOOP_TYPES_LABELS, - ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 3); - - public AvoidBranchingStatementAsLastInLoopRule() { - definePropertyDescriptor(CHECK_BREAK_LOOP_TYPES); - definePropertyDescriptor(CHECK_CONTINUE_LOOP_TYPES); - definePropertyDescriptor(CHECK_RETURN_LOOP_TYPES); - - addRuleChainVisit(ASTBreakStatement.class); - addRuleChainVisit(ASTContinueStatement.class); - addRuleChainVisit(ASTReturnStatement.class); - } - - @Override - public Object visit(ASTBreakStatement node, Object data) { - // skip breaks, that are within a switch statement - if (node.getNthParent(3) instanceof ASTSwitchStatement) { - return data; - } - return check(CHECK_BREAK_LOOP_TYPES, node, data); - } - - @Override - public Object visit(ASTContinueStatement node, Object data) { - return check(CHECK_CONTINUE_LOOP_TYPES, node, data); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - return check(CHECK_RETURN_LOOP_TYPES, node, data); - } - - protected Object check(EnumeratedMultiProperty property, Node node, Object data) { - Node parent = node.getNthParent(5); - if (parent instanceof ASTForStatement) { - if (hasPropertyValue(property, CHECK_FOR)) { - super.addViolation(data, node); - } - } else if (parent instanceof ASTWhileStatement) { - if (hasPropertyValue(property, CHECK_WHILE)) { - super.addViolation(data, node); - } - } else if (parent instanceof ASTDoStatement) { - if (hasPropertyValue(property, CHECK_DO)) { - super.addViolation(data, node); - } - } - return data; - } - - protected boolean hasPropertyValue(EnumeratedMultiProperty property, String value) { - final Object[] values = getProperty(property); - for (int i = 0; i < values.length; i++) { - if (value.equals(values[i])) { - return true; - } - } - return false; - } - - public boolean checksNothing() { - - return getProperty(CHECK_BREAK_LOOP_TYPES).length == 0 && getProperty(CHECK_CONTINUE_LOOP_TYPES).length == 0 - && getProperty(CHECK_RETURN_LOOP_TYPES).length == 0; - } - - /** - * @see PropertySource#dysfunctionReason() - */ - @Override - public String dysfunctionReason() { - return checksNothing() ? "All loop types are ignored" : null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.basic; + +import net.sourceforge.pmd.PropertySource; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement; +import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement; +import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; +import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.EnumeratedMultiProperty; + +public class AvoidBranchingStatementAsLastInLoopRule extends AbstractJavaRule { + + public static final String CHECK_FOR = "for"; + public static final String CHECK_DO = "do"; + public static final String CHECK_WHILE = "while"; + + private static final String[] ALL_LOOP_TYPES_LABELS = new String[] { CHECK_FOR, CHECK_DO, CHECK_WHILE }; + private static final String[] ALL_LOOP_TYPES_VALUES = ALL_LOOP_TYPES_LABELS; + private static final int[] ALL_LOOP_TYPES_DEFAULTS = new int[] { 0, 1, 2 }; + + public static final EnumeratedMultiProperty CHECK_BREAK_LOOP_TYPES = new EnumeratedMultiProperty<>( + "checkBreakLoopTypes", "Check for break statements in loop types", ALL_LOOP_TYPES_LABELS, + ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 1); + public static final EnumeratedMultiProperty CHECK_CONTINUE_LOOP_TYPES = new EnumeratedMultiProperty<>( + "checkContinueLoopTypes", "Check for continue statements in loop types", ALL_LOOP_TYPES_LABELS, + ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 2); + public static final EnumeratedMultiProperty CHECK_RETURN_LOOP_TYPES = new EnumeratedMultiProperty<>( + "checkReturnLoopTypes", "Check for return statements in loop types", ALL_LOOP_TYPES_LABELS, + ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 3); + + public AvoidBranchingStatementAsLastInLoopRule() { + definePropertyDescriptor(CHECK_BREAK_LOOP_TYPES); + definePropertyDescriptor(CHECK_CONTINUE_LOOP_TYPES); + definePropertyDescriptor(CHECK_RETURN_LOOP_TYPES); + + addRuleChainVisit(ASTBreakStatement.class); + addRuleChainVisit(ASTContinueStatement.class); + addRuleChainVisit(ASTReturnStatement.class); + } + + @Override + public Object visit(ASTBreakStatement node, Object data) { + // skip breaks, that are within a switch statement + if (node.getNthParent(3) instanceof ASTSwitchStatement) { + return data; + } + return check(CHECK_BREAK_LOOP_TYPES, node, data); + } + + @Override + public Object visit(ASTContinueStatement node, Object data) { + return check(CHECK_CONTINUE_LOOP_TYPES, node, data); + } + + @Override + public Object visit(ASTReturnStatement node, Object data) { + return check(CHECK_RETURN_LOOP_TYPES, node, data); + } + + protected Object check(EnumeratedMultiProperty property, Node node, Object data) { + Node parent = node.getNthParent(5); + if (parent instanceof ASTForStatement) { + if (hasPropertyValue(property, CHECK_FOR)) { + super.addViolation(data, node); + } + } else if (parent instanceof ASTWhileStatement) { + if (hasPropertyValue(property, CHECK_WHILE)) { + super.addViolation(data, node); + } + } else if (parent instanceof ASTDoStatement) { + if (hasPropertyValue(property, CHECK_DO)) { + super.addViolation(data, node); + } + } + return data; + } + + protected boolean hasPropertyValue(EnumeratedMultiProperty property, String value) { + final Object[] values = getProperty(property); + for (int i = 0; i < values.length; i++) { + if (value.equals(values[i])) { + return true; + } + } + return false; + } + + public boolean checksNothing() { + + return getProperty(CHECK_BREAK_LOOP_TYPES).length == 0 && getProperty(CHECK_CONTINUE_LOOP_TYPES).length == 0 + && getProperty(CHECK_RETURN_LOOP_TYPES).length == 0; + } + + /** + * @see PropertySource#dysfunctionReason() + */ + @Override + public String dysfunctionReason() { + return checksNothing() ? "All loop types are ignored" : null; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidMultipleUnaryOperatorsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidMultipleUnaryOperatorsRule.java index 04ac40dfaa..54f528e45e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidMultipleUnaryOperatorsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/AvoidMultipleUnaryOperatorsRule.java @@ -1,72 +1,72 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.basic; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class AvoidMultipleUnaryOperatorsRule extends AbstractJavaRule { - - public AvoidMultipleUnaryOperatorsRule() { - super.addRuleChainVisit(ASTUnaryExpression.class); - super.addRuleChainVisit(ASTUnaryExpressionNotPlusMinus.class); - } - - @Override - public Object visit(ASTUnaryExpression node, Object data) { - checkUnaryDescendent(node, data); - return data; - } - - @Override - public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { - checkUnaryDescendent(node, data); - return data; - } - - private void checkUnaryDescendent(Node node, Object data) { - boolean match = false; - if (node.jjtGetNumChildren() == 1) { - Node child = node.jjtGetChild(0); - if (child instanceof ASTUnaryExpression || child instanceof ASTUnaryExpressionNotPlusMinus) { - match = true; - } else if (child instanceof ASTPrimaryExpression) { - Node primaryExpression = child; - // Skip down PrimaryExpression/PrimaryPrefix/Expression chains - // created by parentheses - while (true) { - if (primaryExpression.jjtGetNumChildren() == 1 - && primaryExpression.jjtGetChild(0) instanceof ASTPrimaryPrefix - && primaryExpression.jjtGetChild(0).jjtGetNumChildren() == 1 - && primaryExpression.jjtGetChild(0).jjtGetChild(0) instanceof ASTExpression - && primaryExpression.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 1) { - Node candidate = primaryExpression.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); - if (candidate instanceof ASTUnaryExpression - || candidate instanceof ASTUnaryExpressionNotPlusMinus) { - match = true; - break; - } else if (candidate instanceof ASTPrimaryExpression) { - primaryExpression = candidate; - continue; - } else { - break; - } - } else { - break; - } - } - } - } - - if (match) { - addViolation(data, node); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.basic; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class AvoidMultipleUnaryOperatorsRule extends AbstractJavaRule { + + public AvoidMultipleUnaryOperatorsRule() { + super.addRuleChainVisit(ASTUnaryExpression.class); + super.addRuleChainVisit(ASTUnaryExpressionNotPlusMinus.class); + } + + @Override + public Object visit(ASTUnaryExpression node, Object data) { + checkUnaryDescendent(node, data); + return data; + } + + @Override + public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { + checkUnaryDescendent(node, data); + return data; + } + + private void checkUnaryDescendent(Node node, Object data) { + boolean match = false; + if (node.jjtGetNumChildren() == 1) { + Node child = node.jjtGetChild(0); + if (child instanceof ASTUnaryExpression || child instanceof ASTUnaryExpressionNotPlusMinus) { + match = true; + } else if (child instanceof ASTPrimaryExpression) { + Node primaryExpression = child; + // Skip down PrimaryExpression/PrimaryPrefix/Expression chains + // created by parentheses + while (true) { + if (primaryExpression.jjtGetNumChildren() == 1 + && primaryExpression.jjtGetChild(0) instanceof ASTPrimaryPrefix + && primaryExpression.jjtGetChild(0).jjtGetNumChildren() == 1 + && primaryExpression.jjtGetChild(0).jjtGetChild(0) instanceof ASTExpression + && primaryExpression.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 1) { + Node candidate = primaryExpression.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); + if (candidate instanceof ASTUnaryExpression + || candidate instanceof ASTUnaryExpressionNotPlusMinus) { + match = true; + break; + } else if (candidate instanceof ASTPrimaryExpression) { + primaryExpression = candidate; + continue; + } else { + break; + } + } else { + break; + } + } + } + } + + if (match) { + addViolation(data, node); + } + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/CheckSkipResultRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/CheckSkipResultRule.java index f516461135..f433df46dc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/CheckSkipResultRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/CheckSkipResultRule.java @@ -1,61 +1,61 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.basic; - -import java.io.InputStream; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -public class CheckSkipResultRule extends AbstractJavaRule { - - @Override - public Object visit(ASTVariableDeclaratorId node, Object data) { - ASTType typeNode = node.getTypeNode(); - if (typeNode == null || !TypeHelper.isA(typeNode, InputStream.class)) { - return data; - } - for (NameOccurrence occ : node.getUsages()) { - JavaNameOccurrence jocc = (JavaNameOccurrence) occ; - NameOccurrence qualifier = jocc.getNameForWhichThisIsAQualifier(); - if (qualifier != null && "skip".equals(qualifier.getImage())) { - Node loc = jocc.getLocation(); - if (loc != null) { - ASTPrimaryExpression exp = loc.getFirstParentOfType(ASTPrimaryExpression.class); - while (exp != null) { - if (exp.jjtGetParent() instanceof ASTStatementExpression) { - // if exp is in a bare statement, - // the returned value is not used - addViolation(data, occ.getLocation()); - break; - } else if (exp.jjtGetParent() instanceof ASTExpression - && exp.jjtGetParent().jjtGetParent() instanceof ASTPrimaryPrefix) { - // if exp is enclosed in a pair of parenthesis - // let's have a look at the enclosing expression - // we'll see if it's in a bare statement - exp = exp.getFirstParentOfType(ASTPrimaryExpression.class); - } else { - // if exp is neither in a bare statement - // or between a pair of parentheses, - // it's in some other kind of statement - // or assignement so the returned value is used - break; - } - } - } - } - } - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.basic; + +import java.io.InputStream; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; +import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +public class CheckSkipResultRule extends AbstractJavaRule { + + @Override + public Object visit(ASTVariableDeclaratorId node, Object data) { + ASTType typeNode = node.getTypeNode(); + if (typeNode == null || !TypeHelper.isA(typeNode, InputStream.class)) { + return data; + } + for (NameOccurrence occ : node.getUsages()) { + JavaNameOccurrence jocc = (JavaNameOccurrence) occ; + NameOccurrence qualifier = jocc.getNameForWhichThisIsAQualifier(); + if (qualifier != null && "skip".equals(qualifier.getImage())) { + Node loc = jocc.getLocation(); + if (loc != null) { + ASTPrimaryExpression exp = loc.getFirstParentOfType(ASTPrimaryExpression.class); + while (exp != null) { + if (exp.jjtGetParent() instanceof ASTStatementExpression) { + // if exp is in a bare statement, + // the returned value is not used + addViolation(data, occ.getLocation()); + break; + } else if (exp.jjtGetParent() instanceof ASTExpression + && exp.jjtGetParent().jjtGetParent() instanceof ASTPrimaryPrefix) { + // if exp is enclosed in a pair of parenthesis + // let's have a look at the enclosing expression + // we'll see if it's in a bare statement + exp = exp.getFirstParentOfType(ASTPrimaryExpression.class); + } else { + // if exp is neither in a bare statement + // or between a pair of parentheses, + // it's in some other kind of statement + // or assignement so the returned value is used + break; + } + } + } + } + } + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/DoubleCheckedLockingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/DoubleCheckedLockingRule.java index 998eb62152..363aa51d27 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/DoubleCheckedLockingRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/DoubleCheckedLockingRule.java @@ -1,274 +1,274 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.basic; - -import java.util.ArrayList; -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; -import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; -import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -/** - *
- * void method() {
- *   if (x == null) {
- *     synchronized(this){
- *       if (x == null) {
- *         x = new | method();
- *       }
- *     }
- *   }
- * }
- * 
- * - *

The error is when one uses the value assigned within a synchronized - * section, outside of a synchronized section.

- * - *
- * if (x == null) // is outside of synchronized section
- *   x = new | method();
- * 
- * - *

Very very specific check for double checked locking.

- * - * @author CL Gilbert (dnoyeb@users.sourceforge.net) - */ -public class DoubleCheckedLockingRule extends AbstractJavaRule { - - private List volatileFields; - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTCompilationUnit compilationUnit, Object data) { - if (this.volatileFields == null) { - this.volatileFields = new ArrayList<>(0); - } else { - this.volatileFields.clear(); - } - return super.visit(compilationUnit, data); - } - - @Override - public Object visit(ASTFieldDeclaration fieldDeclaration, Object data) { - if (fieldDeclaration.isVolatile()) { - for (ASTVariableDeclaratorId declarator : fieldDeclaration - .findDescendantsOfType(ASTVariableDeclaratorId.class)) { - this.volatileFields.add(declarator.getImage()); - } - } - return super.visit(fieldDeclaration, data); - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - if (node.getResultType().isVoid()) { - return super.visit(node, data); - } - - ASTType typeNode = (ASTType) node.getResultType().jjtGetChild(0); - if (typeNode.jjtGetNumChildren() == 0 || !(typeNode.jjtGetChild(0) instanceof ASTReferenceType)) { - return super.visit(node, data); - } - - List rsl = node.findDescendantsOfType(ASTReturnStatement.class); - if (rsl.size() != 1) { - return super.visit(node, data); - } - ASTReturnStatement rs = rsl.get(0); - - List pel = rs.findDescendantsOfType(ASTPrimaryExpression.class); - ASTPrimaryExpression ape = pel.get(0); - Node lastChild = ape.jjtGetChild(ape.jjtGetNumChildren() - 1); - String returnVariableName = null; - if (lastChild instanceof ASTPrimaryPrefix) { - returnVariableName = getNameFromPrimaryPrefix((ASTPrimaryPrefix) lastChild); - } - // With Java5 and volatile keyword, DCL is no longer an issue - if (returnVariableName == null || this.volatileFields.contains(returnVariableName)) { - return super.visit(node, data); - } - // if the return variable is local and only written with the volatile - // field, then it's ok, too - if (checkLocalVariableUsage(node, returnVariableName)) { - return super.visit(node, data); - } - List isl = node.findDescendantsOfType(ASTIfStatement.class); - if (isl.size() == 2) { - ASTIfStatement is = isl.get(0); - if (ifVerify(is, returnVariableName)) { - // find synchronized - List ssl = is.findDescendantsOfType(ASTSynchronizedStatement.class); - if (ssl.size() == 1) { - ASTSynchronizedStatement ss = ssl.get(0); - isl = ss.findDescendantsOfType(ASTIfStatement.class); - if (isl.size() == 1) { - ASTIfStatement is2 = isl.get(0); - if (ifVerify(is2, returnVariableName)) { - List sel = is2.findDescendantsOfType(ASTStatementExpression.class); - if (sel.size() == 1) { - ASTStatementExpression se = sel.get(0); - if (se.jjtGetNumChildren() == 3) { - // primaryExpression, AssignmentOperator, Expression - if (se.jjtGetChild(0) instanceof ASTPrimaryExpression) { - ASTPrimaryExpression pe = (ASTPrimaryExpression) se.jjtGetChild(0); - if (matchName(pe, returnVariableName)) { - if (se.jjtGetChild(1) instanceof ASTAssignmentOperator) { - addViolation(data, node); - } - } - } - } - } - } - } - } - } - } - return super.visit(node, data); - } - - private boolean checkLocalVariableUsage(ASTMethodDeclaration node, String returnVariableName) { - List locals = node.findDescendantsOfType(ASTLocalVariableDeclaration.class); - ASTVariableInitializer initializer = null; - for (ASTLocalVariableDeclaration l : locals) { - ASTVariableDeclaratorId id = l.getFirstDescendantOfType(ASTVariableDeclaratorId.class); - if (id != null && id.hasImageEqualTo(returnVariableName)) { - initializer = l.getFirstDescendantOfType(ASTVariableInitializer.class); - break; - } - } - // the return variable name doesn't seem to be a local variable - if (initializer == null) { - return false; - } - - // verify the value with which the local variable is initialized - if (initializer.jjtGetNumChildren() > 0 && initializer.jjtGetChild(0) instanceof ASTExpression - && initializer.jjtGetChild(0).jjtGetNumChildren() > 0 - && initializer.jjtGetChild(0).jjtGetChild(0) instanceof ASTPrimaryExpression - && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() > 0 - && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTPrimaryPrefix - && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() > 0 - && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTName) { - ASTName name = (ASTName) initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); - if (name == null || !volatileFields.contains(name.getImage())) { - return false; - } - } else { - // not a simple assignment - return false; - } - - // now check every usage/assignment of the variable - List names = node.findDescendantsOfType(ASTName.class); - for (ASTName n : names) { - if (!n.hasImageEqualTo(returnVariableName)) { - continue; - } - - Node expression = n.getNthParent(3); - if (expression instanceof ASTEqualityExpression) { - continue; - } - if (expression instanceof ASTStatementExpression) { - if (expression.jjtGetNumChildren() > 2 && expression.jjtGetChild(1) instanceof ASTAssignmentOperator) { - ASTName value = expression.jjtGetChild(2).getFirstDescendantOfType(ASTName.class); - if (value == null || !volatileFields.contains(value.getImage())) { - return false; - } - } - } - } - - return true; - } - - private boolean ifVerify(ASTIfStatement is, String varname) { - List finder = is.findDescendantsOfType(ASTPrimaryExpression.class); - if (finder.size() > 1) { - ASTPrimaryExpression nullStmt = findNonVariableStmt(varname, finder.get(0), finder.get(1)); - if (nullStmt != null) { - if (nullStmt.jjtGetNumChildren() == 1 && nullStmt.jjtGetChild(0) instanceof ASTPrimaryPrefix) { - ASTPrimaryPrefix pp2 = (ASTPrimaryPrefix) nullStmt.jjtGetChild(0); - if (pp2.jjtGetNumChildren() == 1 && pp2.jjtGetChild(0) instanceof ASTLiteral) { - ASTLiteral lit = (ASTLiteral) pp2.jjtGetChild(0); - if (lit.jjtGetNumChildren() == 1 && lit.jjtGetChild(0) instanceof ASTNullLiteral) { - return true; - } - } - } - } - } - return false; - } - - /** - *

- * Sort out if apeLeft or apeRight are variable with the provided - * 'variableName'. - *

- * - * @param variableName - * @param apeLeft - * @param apeRight - * @return reference from either apeLeft or apeRight, if one of them match, - * or 'null', if none match. - */ - private ASTPrimaryExpression findNonVariableStmt(String variableName, ASTPrimaryExpression apeLeft, - ASTPrimaryExpression apeRight) { - if (matchName(apeLeft, variableName)) { - return apeRight; - } else if (matchName(apeRight, variableName)) { - return apeLeft; - } - return null; - } - - private boolean matchName(ASTPrimaryExpression ape, String name) { - if (ape.jjtGetNumChildren() == 1 && ape.jjtGetChild(0) instanceof ASTPrimaryPrefix) { - ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ape.jjtGetChild(0); - String name2 = getNameFromPrimaryPrefix(pp); - if (name2 != null && name2.equals(name)) { - return true; - } - } - return false; - } - - private String getNameFromPrimaryPrefix(ASTPrimaryPrefix pp) { - if (pp.jjtGetNumChildren() == 1 && pp.jjtGetChild(0) instanceof ASTName) { - return ((ASTName) pp.jjtGetChild(0)).getImage(); - } - return null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.basic; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; +import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +/** + *
+ * void method() {
+ *   if (x == null) {
+ *     synchronized(this){
+ *       if (x == null) {
+ *         x = new | method();
+ *       }
+ *     }
+ *   }
+ * }
+ * 
+ * + *

The error is when one uses the value assigned within a synchronized + * section, outside of a synchronized section.

+ * + *
+ * if (x == null) // is outside of synchronized section
+ *   x = new | method();
+ * 
+ * + *

Very very specific check for double checked locking.

+ * + * @author CL Gilbert (dnoyeb@users.sourceforge.net) + */ +public class DoubleCheckedLockingRule extends AbstractJavaRule { + + private List volatileFields; + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + return super.visit(node, data); + } + + @Override + public Object visit(ASTCompilationUnit compilationUnit, Object data) { + if (this.volatileFields == null) { + this.volatileFields = new ArrayList<>(0); + } else { + this.volatileFields.clear(); + } + return super.visit(compilationUnit, data); + } + + @Override + public Object visit(ASTFieldDeclaration fieldDeclaration, Object data) { + if (fieldDeclaration.isVolatile()) { + for (ASTVariableDeclaratorId declarator : fieldDeclaration + .findDescendantsOfType(ASTVariableDeclaratorId.class)) { + this.volatileFields.add(declarator.getImage()); + } + } + return super.visit(fieldDeclaration, data); + } + + @Override + public Object visit(ASTMethodDeclaration node, Object data) { + if (node.getResultType().isVoid()) { + return super.visit(node, data); + } + + ASTType typeNode = (ASTType) node.getResultType().jjtGetChild(0); + if (typeNode.jjtGetNumChildren() == 0 || !(typeNode.jjtGetChild(0) instanceof ASTReferenceType)) { + return super.visit(node, data); + } + + List rsl = node.findDescendantsOfType(ASTReturnStatement.class); + if (rsl.size() != 1) { + return super.visit(node, data); + } + ASTReturnStatement rs = rsl.get(0); + + List pel = rs.findDescendantsOfType(ASTPrimaryExpression.class); + ASTPrimaryExpression ape = pel.get(0); + Node lastChild = ape.jjtGetChild(ape.jjtGetNumChildren() - 1); + String returnVariableName = null; + if (lastChild instanceof ASTPrimaryPrefix) { + returnVariableName = getNameFromPrimaryPrefix((ASTPrimaryPrefix) lastChild); + } + // With Java5 and volatile keyword, DCL is no longer an issue + if (returnVariableName == null || this.volatileFields.contains(returnVariableName)) { + return super.visit(node, data); + } + // if the return variable is local and only written with the volatile + // field, then it's ok, too + if (checkLocalVariableUsage(node, returnVariableName)) { + return super.visit(node, data); + } + List isl = node.findDescendantsOfType(ASTIfStatement.class); + if (isl.size() == 2) { + ASTIfStatement is = isl.get(0); + if (ifVerify(is, returnVariableName)) { + // find synchronized + List ssl = is.findDescendantsOfType(ASTSynchronizedStatement.class); + if (ssl.size() == 1) { + ASTSynchronizedStatement ss = ssl.get(0); + isl = ss.findDescendantsOfType(ASTIfStatement.class); + if (isl.size() == 1) { + ASTIfStatement is2 = isl.get(0); + if (ifVerify(is2, returnVariableName)) { + List sel = is2.findDescendantsOfType(ASTStatementExpression.class); + if (sel.size() == 1) { + ASTStatementExpression se = sel.get(0); + if (se.jjtGetNumChildren() == 3) { + // primaryExpression, AssignmentOperator, Expression + if (se.jjtGetChild(0) instanceof ASTPrimaryExpression) { + ASTPrimaryExpression pe = (ASTPrimaryExpression) se.jjtGetChild(0); + if (matchName(pe, returnVariableName)) { + if (se.jjtGetChild(1) instanceof ASTAssignmentOperator) { + addViolation(data, node); + } + } + } + } + } + } + } + } + } + } + return super.visit(node, data); + } + + private boolean checkLocalVariableUsage(ASTMethodDeclaration node, String returnVariableName) { + List locals = node.findDescendantsOfType(ASTLocalVariableDeclaration.class); + ASTVariableInitializer initializer = null; + for (ASTLocalVariableDeclaration l : locals) { + ASTVariableDeclaratorId id = l.getFirstDescendantOfType(ASTVariableDeclaratorId.class); + if (id != null && id.hasImageEqualTo(returnVariableName)) { + initializer = l.getFirstDescendantOfType(ASTVariableInitializer.class); + break; + } + } + // the return variable name doesn't seem to be a local variable + if (initializer == null) { + return false; + } + + // verify the value with which the local variable is initialized + if (initializer.jjtGetNumChildren() > 0 && initializer.jjtGetChild(0) instanceof ASTExpression + && initializer.jjtGetChild(0).jjtGetNumChildren() > 0 + && initializer.jjtGetChild(0).jjtGetChild(0) instanceof ASTPrimaryExpression + && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() > 0 + && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTPrimaryPrefix + && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() > 0 + && initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTName) { + ASTName name = (ASTName) initializer.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); + if (name == null || !volatileFields.contains(name.getImage())) { + return false; + } + } else { + // not a simple assignment + return false; + } + + // now check every usage/assignment of the variable + List names = node.findDescendantsOfType(ASTName.class); + for (ASTName n : names) { + if (!n.hasImageEqualTo(returnVariableName)) { + continue; + } + + Node expression = n.getNthParent(3); + if (expression instanceof ASTEqualityExpression) { + continue; + } + if (expression instanceof ASTStatementExpression) { + if (expression.jjtGetNumChildren() > 2 && expression.jjtGetChild(1) instanceof ASTAssignmentOperator) { + ASTName value = expression.jjtGetChild(2).getFirstDescendantOfType(ASTName.class); + if (value == null || !volatileFields.contains(value.getImage())) { + return false; + } + } + } + } + + return true; + } + + private boolean ifVerify(ASTIfStatement is, String varname) { + List finder = is.findDescendantsOfType(ASTPrimaryExpression.class); + if (finder.size() > 1) { + ASTPrimaryExpression nullStmt = findNonVariableStmt(varname, finder.get(0), finder.get(1)); + if (nullStmt != null) { + if (nullStmt.jjtGetNumChildren() == 1 && nullStmt.jjtGetChild(0) instanceof ASTPrimaryPrefix) { + ASTPrimaryPrefix pp2 = (ASTPrimaryPrefix) nullStmt.jjtGetChild(0); + if (pp2.jjtGetNumChildren() == 1 && pp2.jjtGetChild(0) instanceof ASTLiteral) { + ASTLiteral lit = (ASTLiteral) pp2.jjtGetChild(0); + if (lit.jjtGetNumChildren() == 1 && lit.jjtGetChild(0) instanceof ASTNullLiteral) { + return true; + } + } + } + } + } + return false; + } + + /** + *

+ * Sort out if apeLeft or apeRight are variable with the provided + * 'variableName'. + *

+ * + * @param variableName + * @param apeLeft + * @param apeRight + * @return reference from either apeLeft or apeRight, if one of them match, + * or 'null', if none match. + */ + private ASTPrimaryExpression findNonVariableStmt(String variableName, ASTPrimaryExpression apeLeft, + ASTPrimaryExpression apeRight) { + if (matchName(apeLeft, variableName)) { + return apeRight; + } else if (matchName(apeRight, variableName)) { + return apeLeft; + } + return null; + } + + private boolean matchName(ASTPrimaryExpression ape, String name) { + if (ape.jjtGetNumChildren() == 1 && ape.jjtGetChild(0) instanceof ASTPrimaryPrefix) { + ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ape.jjtGetChild(0); + String name2 = getNameFromPrimaryPrefix(pp); + if (name2 != null && name2.equals(name)) { + return true; + } + } + return false; + } + + private String getNameFromPrimaryPrefix(ASTPrimaryPrefix pp) { + if (pp.jjtGetNumChildren() == 1 && pp.jjtGetChild(0) instanceof ASTName) { + return ((ASTName) pp.jjtGetChild(0)).getImage(); + } + return null; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/OverrideBothEqualsAndHashcodeRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/OverrideBothEqualsAndHashcodeRule.java index a3720e7c7d..857c24d2ef 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/OverrideBothEqualsAndHashcodeRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/basic/OverrideBothEqualsAndHashcodeRule.java @@ -1,96 +1,96 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.basic; - -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; -import net.sourceforge.pmd.lang.java.ast.ASTImplementsList; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule { - - private boolean implementsComparable = false; - - private boolean containsEquals = false; - - private boolean containsHashCode = false; - - private Node nodeFound = null; - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - super.visit(node, data); - if (!implementsComparable && containsEquals ^ containsHashCode) { - if (nodeFound == null) { - nodeFound = node; - } - addViolation(data, nodeFound); - } - implementsComparable = false; - containsEquals = false; - containsHashCode = false; - nodeFound = null; - return data; - } - - @Override - public Object visit(ASTImplementsList node, Object data) { - for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) { - if (node.jjtGetChild(ix) instanceof ASTClassOrInterfaceType) { - ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.jjtGetChild(ix); - Class clazz = cit.getType(); - if (clazz != null && node.jjtGetChild(ix).hasImageEqualTo("Comparable")) { - implementsComparable = true; - return data; - } - } - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTMethodDeclarator node, Object data) { - if (implementsComparable) { - return data; - } - - int iFormalParams = 0; - String paramName = null; - for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) { - Node sn = node.jjtGetChild(ix); - if (sn instanceof ASTFormalParameters) { - List allParams = ((ASTFormalParameters) sn) - .findChildrenOfType(ASTFormalParameter.class); - for (ASTFormalParameter formalParam : allParams) { - iFormalParams++; - ASTClassOrInterfaceType param = formalParam.getFirstDescendantOfType(ASTClassOrInterfaceType.class); - if (param != null) { - paramName = param.getImage(); - } - } - } - } - - if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) { - containsHashCode = true; - nodeFound = node; - } else if (iFormalParams == 1 && node.hasImageEqualTo("equals") - && ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) { - containsEquals = true; - nodeFound = node; - } - return super.visit(node, data); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.basic; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; +import net.sourceforge.pmd.lang.java.ast.ASTImplementsList; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule { + + private boolean implementsComparable = false; + + private boolean containsEquals = false; + + private boolean containsHashCode = false; + + private Node nodeFound = null; + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + super.visit(node, data); + if (!implementsComparable && containsEquals ^ containsHashCode) { + if (nodeFound == null) { + nodeFound = node; + } + addViolation(data, nodeFound); + } + implementsComparable = false; + containsEquals = false; + containsHashCode = false; + nodeFound = null; + return data; + } + + @Override + public Object visit(ASTImplementsList node, Object data) { + for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) { + if (node.jjtGetChild(ix) instanceof ASTClassOrInterfaceType) { + ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.jjtGetChild(ix); + Class clazz = cit.getType(); + if (clazz != null && node.jjtGetChild(ix).hasImageEqualTo("Comparable")) { + implementsComparable = true; + return data; + } + } + } + return super.visit(node, data); + } + + @Override + public Object visit(ASTMethodDeclarator node, Object data) { + if (implementsComparable) { + return data; + } + + int iFormalParams = 0; + String paramName = null; + for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) { + Node sn = node.jjtGetChild(ix); + if (sn instanceof ASTFormalParameters) { + List allParams = ((ASTFormalParameters) sn) + .findChildrenOfType(ASTFormalParameter.class); + for (ASTFormalParameter formalParam : allParams) { + iFormalParams++; + ASTClassOrInterfaceType param = formalParam.getFirstDescendantOfType(ASTClassOrInterfaceType.class); + if (param != null) { + paramName = param.getImage(); + } + } + } + } + + if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) { + containsHashCode = true; + nodeFound = node; + } else if (iFormalParams == 1 && node.hasImageEqualTo("equals") + && ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) { + containsEquals = true; + nodeFound = node; + } + return super.visit(node, data); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/CyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/CyclomaticComplexityRule.java index 6131e298b4..63d521b93a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/CyclomaticComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/CyclomaticComplexityRule.java @@ -1,81 +1,81 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; -import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; - -/** - * @author Donald A. Leckie, - * - * @version $Revision: 5956 $, $Date: 2008-04-04 04:59:25 -0500 (Fri, 04 Apr - * 2008) $ - * @since January 14, 2003 - */ -public class CyclomaticComplexityRule extends StdCyclomaticComplexityRule { - - @Override - public Object visit(ASTIfStatement node, Object data) { - super.visit(node, data); - - int boolCompIf = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - entryStack.peek().bumpDecisionPoints(boolCompIf); - return data; - } - - @Override - public Object visit(ASTForStatement node, Object data) { - super.visit(node, data); - - int boolCompFor = NPathComplexityRule - .sumExpressionComplexity(node.getFirstDescendantOfType(ASTExpression.class)); - entryStack.peek().bumpDecisionPoints(boolCompFor); - return data; - } - - @Override - public Object visit(ASTDoStatement node, Object data) { - super.visit(node, data); - - int boolCompDo = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - entryStack.peek().bumpDecisionPoints(boolCompDo); - return data; - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - super.visit(node, data); - - int boolCompSwitch = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - entryStack.peek().bumpDecisionPoints(boolCompSwitch); - return data; - } - - @Override - public Object visit(ASTWhileStatement node, Object data) { - super.visit(node, data); - - int boolCompWhile = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - entryStack.peek().bumpDecisionPoints(boolCompWhile); - return data; - } - - @Override - public Object visit(ASTConditionalExpression node, Object data) { - super.visit(node, data); - - if (node.isTernary()) { - int boolCompTern = NPathComplexityRule - .sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - entryStack.peek().bumpDecisionPoints(boolCompTern); - } - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; +import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; + +/** + * @author Donald A. Leckie, + * + * @version $Revision: 5956 $, $Date: 2008-04-04 04:59:25 -0500 (Fri, 04 Apr + * 2008) $ + * @since January 14, 2003 + */ +public class CyclomaticComplexityRule extends StdCyclomaticComplexityRule { + + @Override + public Object visit(ASTIfStatement node, Object data) { + super.visit(node, data); + + int boolCompIf = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + entryStack.peek().bumpDecisionPoints(boolCompIf); + return data; + } + + @Override + public Object visit(ASTForStatement node, Object data) { + super.visit(node, data); + + int boolCompFor = NPathComplexityRule + .sumExpressionComplexity(node.getFirstDescendantOfType(ASTExpression.class)); + entryStack.peek().bumpDecisionPoints(boolCompFor); + return data; + } + + @Override + public Object visit(ASTDoStatement node, Object data) { + super.visit(node, data); + + int boolCompDo = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + entryStack.peek().bumpDecisionPoints(boolCompDo); + return data; + } + + @Override + public Object visit(ASTSwitchStatement node, Object data) { + super.visit(node, data); + + int boolCompSwitch = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + entryStack.peek().bumpDecisionPoints(boolCompSwitch); + return data; + } + + @Override + public Object visit(ASTWhileStatement node, Object data) { + super.visit(node, data); + + int boolCompWhile = NPathComplexityRule.sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + entryStack.peek().bumpDecisionPoints(boolCompWhile); + return data; + } + + @Override + public Object visit(ASTConditionalExpression node, Object data) { + super.visit(node, data); + + if (node.isTernary()) { + int boolCompTern = NPathComplexityRule + .sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + entryStack.peek().bumpDecisionPoints(boolCompTern); + } + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveClassLengthRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveClassLengthRule.java index 46d191ad2f..d5861074a1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveClassLengthRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveClassLengthRule.java @@ -1,19 +1,19 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.rule.design.ExcessiveLengthRule; - -/** - * This rule detects when a class exceeds a certain threshold. i.e. if a class - * has more than 1000 lines of code. - */ -public class ExcessiveClassLengthRule extends ExcessiveLengthRule { - public ExcessiveClassLengthRule() { - super(ASTClassOrInterfaceDeclaration.class); - setProperty(MINIMUM_DESCRIPTOR, 1000d); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.rule.design.ExcessiveLengthRule; + +/** + * This rule detects when a class exceeds a certain threshold. i.e. if a class + * has more than 1000 lines of code. + */ +public class ExcessiveClassLengthRule extends ExcessiveLengthRule { + public ExcessiveClassLengthRule() { + super(ASTClassOrInterfaceDeclaration.class); + setProperty(MINIMUM_DESCRIPTOR, 1000d); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveMethodLengthRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveMethodLengthRule.java index 355bd91fd6..fbfad1d8c3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveMethodLengthRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveMethodLengthRule.java @@ -1,19 +1,19 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.rule.design.ExcessiveLengthRule; - -/** - * This rule detects when a method exceeds a certain threshold. i.e. if a method - * has more than x lines of code. - */ -public class ExcessiveMethodLengthRule extends ExcessiveLengthRule { - public ExcessiveMethodLengthRule() { - super(ASTMethodDeclaration.class); - setProperty(MINIMUM_DESCRIPTOR, 100d); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.rule.design.ExcessiveLengthRule; + +/** + * This rule detects when a method exceeds a certain threshold. i.e. if a method + * has more than x lines of code. + */ +public class ExcessiveMethodLengthRule extends ExcessiveLengthRule { + public ExcessiveMethodLengthRule() { + super(ASTMethodDeclaration.class); + setProperty(MINIMUM_DESCRIPTOR, 100d); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveParameterListRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveParameterListRule.java index 2f18584144..acdbda3cf6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveParameterListRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessiveParameterListRule.java @@ -1,27 +1,27 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; -import net.sourceforge.pmd.lang.java.rule.design.ExcessiveNodeCountRule; -import net.sourceforge.pmd.util.NumericConstants; - -/** - * This rule detects an abnormally long parameter list. Note: This counts Nodes, - * and not necessarily parameters, so the numbers may not match up. (But - * topcount and sigma should work.) - */ -public class ExcessiveParameterListRule extends ExcessiveNodeCountRule { - public ExcessiveParameterListRule() { - super(ASTFormalParameters.class); - setProperty(MINIMUM_DESCRIPTOR, 10d); - } - - // Count these nodes, but no others. - public Object visit(ASTFormalParameter node, Object data) { - return NumericConstants.ONE; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; +import net.sourceforge.pmd.lang.java.rule.design.ExcessiveNodeCountRule; +import net.sourceforge.pmd.util.NumericConstants; + +/** + * This rule detects an abnormally long parameter list. Note: This counts Nodes, + * and not necessarily parameters, so the numbers may not match up. (But + * topcount and sigma should work.) + */ +public class ExcessiveParameterListRule extends ExcessiveNodeCountRule { + public ExcessiveParameterListRule() { + super(ASTFormalParameters.class); + setProperty(MINIMUM_DESCRIPTOR, 10d); + } + + // Count these nodes, but no others. + public Object visit(ASTFormalParameter node, Object data) { + return NumericConstants.ONE; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessivePublicCountRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessivePublicCountRule.java index 480f08f91d..7c09337d4e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessivePublicCountRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ExcessivePublicCountRule.java @@ -1,67 +1,67 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.AccessNode; -import net.sourceforge.pmd.lang.java.rule.design.ExcessiveNodeCountRule; -import net.sourceforge.pmd.util.NumericConstants; - -/** - * Rule attempts to count all public methods and public attributes - * defined in a class. - * - *

If a class has a high number of public operations, it might be wise - * to consider whether it would be appropriate to divide it into - * subclasses.

- * - *

A large proportion of public members and operations means the class - * has high potential to be affected by external classes. Futhermore, - * increased effort will be required to thoroughly test the class. - *

- * - * @author aglover - */ -public class ExcessivePublicCountRule extends ExcessiveNodeCountRule { - - public ExcessivePublicCountRule() { - super(ASTCompilationUnit.class); - setProperty(MINIMUM_DESCRIPTOR, 45d); - } - - /** - * Method counts ONLY public methods. - */ - public Object visit(ASTMethodDeclarator node, Object data) { - return this.getTallyOnAccessType((AccessNode) node.jjtGetParent()); - } - - /** - * Method counts ONLY public class attributes which are not PUBLIC and - * static- these usually represent constants.... - */ - public Object visit(ASTFieldDeclaration node, Object data) { - if (node.isFinal() && node.isStatic()) { - return NumericConstants.ZERO; - } - return this.getTallyOnAccessType(node); - } - - /** - * Method counts a node if it is public - * - * @param node - * The access node. - * @return Integer 1 if node is public 0 otherwise - */ - private Integer getTallyOnAccessType(AccessNode node) { - if (node.isPublic()) { - return NumericConstants.ONE; - } - return NumericConstants.ZERO; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.rule.design.ExcessiveNodeCountRule; +import net.sourceforge.pmd.util.NumericConstants; + +/** + * Rule attempts to count all public methods and public attributes + * defined in a class. + * + *

If a class has a high number of public operations, it might be wise + * to consider whether it would be appropriate to divide it into + * subclasses.

+ * + *

A large proportion of public members and operations means the class + * has high potential to be affected by external classes. Futhermore, + * increased effort will be required to thoroughly test the class. + *

+ * + * @author aglover + */ +public class ExcessivePublicCountRule extends ExcessiveNodeCountRule { + + public ExcessivePublicCountRule() { + super(ASTCompilationUnit.class); + setProperty(MINIMUM_DESCRIPTOR, 45d); + } + + /** + * Method counts ONLY public methods. + */ + public Object visit(ASTMethodDeclarator node, Object data) { + return this.getTallyOnAccessType((AccessNode) node.jjtGetParent()); + } + + /** + * Method counts ONLY public class attributes which are not PUBLIC and + * static- these usually represent constants.... + */ + public Object visit(ASTFieldDeclaration node, Object data) { + if (node.isFinal() && node.isStatic()) { + return NumericConstants.ZERO; + } + return this.getTallyOnAccessType(node); + } + + /** + * Method counts a node if it is public + * + * @param node + * The access node. + * @return Integer 1 if node is public 0 otherwise + */ + private Integer getTallyOnAccessType(AccessNode node) { + if (node.isPublic()) { + return NumericConstants.ONE; + } + return NumericConstants.ZERO; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ModifiedCyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ModifiedCyclomaticComplexityRule.java index 38f0975951..a04b198d71 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ModifiedCyclomaticComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/ModifiedCyclomaticComplexityRule.java @@ -1,29 +1,29 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.JavaNode; - -/** - * Implements the modified cyclomatic complexity rule - *

- * Modified rules: Same as standard cyclomatic complexity, but switch statement - * plus all cases count as 1. - * - * @author Alan Hohn, based on work by Donald A. Leckie - * - * @since June 18, 2014 - */ -public class ModifiedCyclomaticComplexityRule extends StdCyclomaticComplexityRule { - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - visit((JavaNode) node, data); - return data; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; +import net.sourceforge.pmd.lang.java.ast.JavaNode; + +/** + * Implements the modified cyclomatic complexity rule + *

+ * Modified rules: Same as standard cyclomatic complexity, but switch statement + * plus all cases count as 1. + * + * @author Alan Hohn, based on work by Donald A. Leckie + * + * @since June 18, 2014 + */ +public class ModifiedCyclomaticComplexityRule extends StdCyclomaticComplexityRule { + + @Override + public Object visit(ASTSwitchStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + visit((JavaNode) node, data); + return data; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/NPathComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/NPathComplexityRule.java index b06e901753..e18210cf74 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/NPathComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/NPathComplexityRule.java @@ -1,265 +1,265 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import java.util.ArrayList; -import java.util.List; - -import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression; -import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; -import net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression; -import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTStatement; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractStatisticalJavaRule; -import net.sourceforge.pmd.stat.DataPoint; -import net.sourceforge.pmd.util.NumericConstants; - -/** - * NPath complexity is a measurement of the acyclic execution paths through a - * function. See Nejmeh, Communications of the ACM Feb 1988 pp 188-200. - * - * @author Jason Bennett - */ -public class NPathComplexityRule extends AbstractStatisticalJavaRule { - - public NPathComplexityRule() { - super(); - setProperty(MINIMUM_DESCRIPTOR, 200d); - } - - private int complexityMultipleOf(JavaNode node, int npathStart, Object data) { - - int npath = npathStart; - JavaNode n; - - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - n = (JavaNode) node.jjtGetChild(i); - npath *= (Integer) n.jjtAccept(this, data); - } - - return npath; - } - - private int complexitySumOf(JavaNode node, int npathStart, Object data) { - - int npath = npathStart; - JavaNode n; - - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - n = (JavaNode) node.jjtGetChild(i); - npath += (Integer) n.jjtAccept(this, data); - } - - return npath; - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - int npath = complexityMultipleOf(node, 1, data); - - DataPoint point = new DataPoint(); - point.setNode(node); - point.setScore(1.0 * npath); - point.setMessage(getMessage()); - addDataPoint(point); - - return Integer.valueOf(npath); - } - - @Override - public Object visit(JavaNode node, Object data) { - int npath = complexityMultipleOf(node, 1, data); - return Integer.valueOf(npath); - } - - @Override - public Object visit(ASTIfStatement node, Object data) { - // (npath of if + npath of else (or 1) + bool_comp of if) * npath of - // next - - List statementChildren = new ArrayList<>(); - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - if (node.jjtGetChild(i).getClass() == ASTStatement.class) { - statementChildren.add((JavaNode) node.jjtGetChild(i)); - } - } - - if (statementChildren.isEmpty() || statementChildren.size() == 1 && node.hasElse() - || statementChildren.size() != 1 && !node.hasElse()) { - throw new IllegalStateException("If node has wrong number of children"); - } - - // add path for not taking if - int complexity = 0; - if (!node.hasElse()) { - complexity++; - } - - for (JavaNode element : statementChildren) { - complexity += (Integer) element.jjtAccept(this, data); - } - - int boolCompIf = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - return Integer.valueOf(boolCompIf + complexity); - } - - @Override - public Object visit(ASTWhileStatement node, Object data) { - // (npath of while + bool_comp of while + 1) * npath of next - - int boolCompWhile = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - - Integer nPathWhile = (Integer) ((JavaNode) node.getFirstChildOfType(ASTStatement.class)).jjtAccept(this, data); - - return Integer.valueOf(boolCompWhile + nPathWhile + 1); - } - - @Override - public Object visit(ASTDoStatement node, Object data) { - // (npath of do + bool_comp of do + 1) * npath of next - - int boolCompDo = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - - Integer nPathDo = (Integer) ((JavaNode) node.getFirstChildOfType(ASTStatement.class)).jjtAccept(this, data); - - return Integer.valueOf(boolCompDo + nPathDo + 1); - } - - @Override - public Object visit(ASTForStatement node, Object data) { - // (npath of for + bool_comp of for + 1) * npath of next - - int boolCompFor = sumExpressionComplexity(node.getFirstDescendantOfType(ASTExpression.class)); - - Integer nPathFor = (Integer) ((JavaNode) node.getFirstChildOfType(ASTStatement.class)).jjtAccept(this, data); - - return Integer.valueOf(boolCompFor + nPathFor + 1); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - // return statements are valued at 1, or the value of the boolean - // expression - - ASTExpression expr = node.getFirstChildOfType(ASTExpression.class); - - if (expr == null) { - return NumericConstants.ONE; - } - - int boolCompReturn = sumExpressionComplexity(expr); - int conditionalExpressionComplexity = complexityMultipleOf(expr, 1, data); - - if (conditionalExpressionComplexity > 1) { - boolCompReturn += conditionalExpressionComplexity; - } - - if (boolCompReturn > 0) { - return Integer.valueOf(boolCompReturn); - } - return NumericConstants.ONE; - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - // bool_comp of switch + sum(npath(case_range)) - - int boolCompSwitch = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); - - int npath = 0; - int caseRange = 0; - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - JavaNode n = (JavaNode) node.jjtGetChild(i); - - // Fall-through labels count as 1 for complexity - if (n instanceof ASTSwitchLabel) { - npath += caseRange; - caseRange = 1; - } else { - Integer complexity = (Integer) n.jjtAccept(this, data); - caseRange *= complexity; - } - } - // add in npath of last label - npath += caseRange; - return Integer.valueOf(boolCompSwitch + npath); - } - - @Override - public Object visit(ASTTryStatement node, Object data) { - /* - * This scenario was not addressed by the original paper. Based on the - * principles outlined in the paper, as well as the Checkstyle NPath - * implementation, this code will add the complexity of the try to the - * complexities of the catch and finally blocks. - */ - int npath = complexitySumOf(node, 0, data); - - return Integer.valueOf(npath); - - } - - @Override - public Object visit(ASTConditionalExpression node, Object data) { - if (node.isTernary()) { - int npath = complexitySumOf(node, 0, data); - - npath += 2; - return Integer.valueOf(npath); - } - return NumericConstants.ONE; - } - - /** - * Calculate the boolean complexity of the given expression. NPath boolean - * complexity is the sum of && and || tokens. This is calculated by summing - * the number of children of the &&'s (minus one) and the children of the - * ||'s (minus one). - * - *

Note that this calculation applies to Cyclomatic Complexity as well.

- * - * @param expr - * control structure expression - * @return complexity of the boolean expression - */ - public static int sumExpressionComplexity(ASTExpression expr) { - if (expr == null) { - return 0; - } - - List andNodes = expr.findDescendantsOfType(ASTConditionalAndExpression.class); - List orNodes = expr.findDescendantsOfType(ASTConditionalOrExpression.class); - - int children = 0; - - for (ASTConditionalOrExpression element : orNodes) { - children += element.jjtGetNumChildren(); - children--; - } - - for (ASTConditionalAndExpression element : andNodes) { - children += element.jjtGetNumChildren(); - children--; - } - - return children; - } - - @Override - public Object[] getViolationParameters(DataPoint point) { - return new String[] { ((ASTMethodDeclaration) point.getNode()).getMethodName(), - String.valueOf((int) point.getScore()), }; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression; +import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; +import net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression; +import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTStatement; +import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; +import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; +import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractStatisticalJavaRule; +import net.sourceforge.pmd.stat.DataPoint; +import net.sourceforge.pmd.util.NumericConstants; + +/** + * NPath complexity is a measurement of the acyclic execution paths through a + * function. See Nejmeh, Communications of the ACM Feb 1988 pp 188-200. + * + * @author Jason Bennett + */ +public class NPathComplexityRule extends AbstractStatisticalJavaRule { + + public NPathComplexityRule() { + super(); + setProperty(MINIMUM_DESCRIPTOR, 200d); + } + + private int complexityMultipleOf(JavaNode node, int npathStart, Object data) { + + int npath = npathStart; + JavaNode n; + + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + n = (JavaNode) node.jjtGetChild(i); + npath *= (Integer) n.jjtAccept(this, data); + } + + return npath; + } + + private int complexitySumOf(JavaNode node, int npathStart, Object data) { + + int npath = npathStart; + JavaNode n; + + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + n = (JavaNode) node.jjtGetChild(i); + npath += (Integer) n.jjtAccept(this, data); + } + + return npath; + } + + @Override + public Object visit(ASTMethodDeclaration node, Object data) { + int npath = complexityMultipleOf(node, 1, data); + + DataPoint point = new DataPoint(); + point.setNode(node); + point.setScore(1.0 * npath); + point.setMessage(getMessage()); + addDataPoint(point); + + return Integer.valueOf(npath); + } + + @Override + public Object visit(JavaNode node, Object data) { + int npath = complexityMultipleOf(node, 1, data); + return Integer.valueOf(npath); + } + + @Override + public Object visit(ASTIfStatement node, Object data) { + // (npath of if + npath of else (or 1) + bool_comp of if) * npath of + // next + + List statementChildren = new ArrayList<>(); + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + if (node.jjtGetChild(i).getClass() == ASTStatement.class) { + statementChildren.add((JavaNode) node.jjtGetChild(i)); + } + } + + if (statementChildren.isEmpty() || statementChildren.size() == 1 && node.hasElse() + || statementChildren.size() != 1 && !node.hasElse()) { + throw new IllegalStateException("If node has wrong number of children"); + } + + // add path for not taking if + int complexity = 0; + if (!node.hasElse()) { + complexity++; + } + + for (JavaNode element : statementChildren) { + complexity += (Integer) element.jjtAccept(this, data); + } + + int boolCompIf = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + return Integer.valueOf(boolCompIf + complexity); + } + + @Override + public Object visit(ASTWhileStatement node, Object data) { + // (npath of while + bool_comp of while + 1) * npath of next + + int boolCompWhile = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + + Integer nPathWhile = (Integer) ((JavaNode) node.getFirstChildOfType(ASTStatement.class)).jjtAccept(this, data); + + return Integer.valueOf(boolCompWhile + nPathWhile + 1); + } + + @Override + public Object visit(ASTDoStatement node, Object data) { + // (npath of do + bool_comp of do + 1) * npath of next + + int boolCompDo = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + + Integer nPathDo = (Integer) ((JavaNode) node.getFirstChildOfType(ASTStatement.class)).jjtAccept(this, data); + + return Integer.valueOf(boolCompDo + nPathDo + 1); + } + + @Override + public Object visit(ASTForStatement node, Object data) { + // (npath of for + bool_comp of for + 1) * npath of next + + int boolCompFor = sumExpressionComplexity(node.getFirstDescendantOfType(ASTExpression.class)); + + Integer nPathFor = (Integer) ((JavaNode) node.getFirstChildOfType(ASTStatement.class)).jjtAccept(this, data); + + return Integer.valueOf(boolCompFor + nPathFor + 1); + } + + @Override + public Object visit(ASTReturnStatement node, Object data) { + // return statements are valued at 1, or the value of the boolean + // expression + + ASTExpression expr = node.getFirstChildOfType(ASTExpression.class); + + if (expr == null) { + return NumericConstants.ONE; + } + + int boolCompReturn = sumExpressionComplexity(expr); + int conditionalExpressionComplexity = complexityMultipleOf(expr, 1, data); + + if (conditionalExpressionComplexity > 1) { + boolCompReturn += conditionalExpressionComplexity; + } + + if (boolCompReturn > 0) { + return Integer.valueOf(boolCompReturn); + } + return NumericConstants.ONE; + } + + @Override + public Object visit(ASTSwitchStatement node, Object data) { + // bool_comp of switch + sum(npath(case_range)) + + int boolCompSwitch = sumExpressionComplexity(node.getFirstChildOfType(ASTExpression.class)); + + int npath = 0; + int caseRange = 0; + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + JavaNode n = (JavaNode) node.jjtGetChild(i); + + // Fall-through labels count as 1 for complexity + if (n instanceof ASTSwitchLabel) { + npath += caseRange; + caseRange = 1; + } else { + Integer complexity = (Integer) n.jjtAccept(this, data); + caseRange *= complexity; + } + } + // add in npath of last label + npath += caseRange; + return Integer.valueOf(boolCompSwitch + npath); + } + + @Override + public Object visit(ASTTryStatement node, Object data) { + /* + * This scenario was not addressed by the original paper. Based on the + * principles outlined in the paper, as well as the Checkstyle NPath + * implementation, this code will add the complexity of the try to the + * complexities of the catch and finally blocks. + */ + int npath = complexitySumOf(node, 0, data); + + return Integer.valueOf(npath); + + } + + @Override + public Object visit(ASTConditionalExpression node, Object data) { + if (node.isTernary()) { + int npath = complexitySumOf(node, 0, data); + + npath += 2; + return Integer.valueOf(npath); + } + return NumericConstants.ONE; + } + + /** + * Calculate the boolean complexity of the given expression. NPath boolean + * complexity is the sum of && and || tokens. This is calculated by summing + * the number of children of the &&'s (minus one) and the children of the + * ||'s (minus one). + * + *

Note that this calculation applies to Cyclomatic Complexity as well.

+ * + * @param expr + * control structure expression + * @return complexity of the boolean expression + */ + public static int sumExpressionComplexity(ASTExpression expr) { + if (expr == null) { + return 0; + } + + List andNodes = expr.findDescendantsOfType(ASTConditionalAndExpression.class); + List orNodes = expr.findDescendantsOfType(ASTConditionalOrExpression.class); + + int children = 0; + + for (ASTConditionalOrExpression element : orNodes) { + children += element.jjtGetNumChildren(); + children--; + } + + for (ASTConditionalAndExpression element : andNodes) { + children += element.jjtGetNumChildren(); + children--; + } + + return children; + } + + @Override + public Object[] getViolationParameters(DataPoint point) { + return new String[] { ((ASTMethodDeclaration) point.getNode()).getMethodName(), + String.valueOf((int) point.getScore()), }; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/StdCyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/StdCyclomaticComplexityRule.java index 1c7282e1c6..1c4333a152 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/StdCyclomaticComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/StdCyclomaticComplexityRule.java @@ -1,246 +1,246 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import java.util.ArrayDeque; -import java.util.Deque; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -/** - * Implements the standard cyclomatic complexity rule - *

- * Standard rules: +1 for each decision point, including case statements but not - * including boolean operators unlike CyclomaticComplexityRule. - * - * @author Alan Hohn, based on work by Donald A. Leckie - * - * @since June 18, 2014 - */ -public class StdCyclomaticComplexityRule extends AbstractJavaRule { - - public static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty("reportLevel", - "Cyclomatic Complexity reporting threshold", 1, 30, 10, 1.0f); - - public static final BooleanProperty SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty( - "showClassesComplexity", "Add class average violations to the report", true, 2.0f); - - public static final BooleanProperty SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty( - "showMethodsComplexity", "Add method average violations to the report", true, 3.0f); - - private int reportLevel; - private boolean showClassesComplexity = true; - private boolean showMethodsComplexity = true; - - protected static class Entry { - private Node node; - private int decisionPoints = 1; - public int highestDecisionPoints; - public int methodCount; - - private Entry(Node node) { - this.node = node; - } - - public void bumpDecisionPoints() { - decisionPoints++; - } - - public void bumpDecisionPoints(int size) { - decisionPoints += size; - } - - public int getComplexityAverage() { - return (double) methodCount == 0 ? 1 : (int) Math.rint((double) decisionPoints / (double) methodCount); - } - } - - protected Deque entryStack = new ArrayDeque<>(); - - public StdCyclomaticComplexityRule() { - definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR); - definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); - showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTIfStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTCatchStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTForStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTDoStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - Entry entry = entryStack.peek(); - - int childCount = node.jjtGetNumChildren(); - int lastIndex = childCount - 1; - for (int n = 0; n < lastIndex; n++) { - Node childNode = node.jjtGetChild(n); - if (childNode instanceof ASTSwitchLabel) { - // default is generally not considered a decision (same as - // "else") - ASTSwitchLabel sl = (ASTSwitchLabel) childNode; - if (!sl.isDefault()) { - childNode = node.jjtGetChild(n + 1); - if (childNode instanceof ASTBlockStatement) { - entry.bumpDecisionPoints(); - } - } - } - } - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTWhileStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTConditionalExpression node, Object data) { - if (node.isTernary()) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - } - return data; - } - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (showClassesComplexity) { - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "class", node.getImage(), - classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); - } - } - return data; - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry methodEntry = entryStack.pop(); - if (!isSuppressed(node)) { - int methodDecisionPoints = methodEntry.decisionPoints; - Entry classEntry = entryStack.peek(); - classEntry.methodCount++; - classEntry.bumpDecisionPoints(methodDecisionPoints); - - if (methodDecisionPoints > classEntry.highestDecisionPoints) { - classEntry.highestDecisionPoints = methodDecisionPoints; - } - - ASTMethodDeclarator methodDeclarator = null; - for (int n = 0; n < node.jjtGetNumChildren(); n++) { - Node childNode = node.jjtGetChild(n); - if (childNode instanceof ASTMethodDeclarator) { - methodDeclarator = (ASTMethodDeclarator) childNode; - break; - } - } - - if (showMethodsComplexity && methodEntry.decisionPoints >= reportLevel) { - addViolation(data, node, - new String[] { "method", methodDeclarator == null ? "" : methodDeclarator.getImage(), - String.valueOf(methodEntry.decisionPoints), }); - } - } - return data; - } - - @Override - public Object visit(ASTEnumDeclaration node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "class", node.getImage(), - classEntry.getComplexityAverage() + "(Highest = " + classEntry.highestDecisionPoints + ')', }); - } - return data; - } - - @Override - public Object visit(ASTConstructorDeclaration node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry constructorEntry = entryStack.pop(); - if (!isSuppressed(node)) { - int constructorDecisionPointCount = constructorEntry.decisionPoints; - Entry classEntry = entryStack.peek(); - classEntry.methodCount++; - classEntry.decisionPoints += constructorDecisionPointCount; - if (constructorDecisionPointCount > classEntry.highestDecisionPoints) { - classEntry.highestDecisionPoints = constructorDecisionPointCount; - } - if (showMethodsComplexity && constructorEntry.decisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "constructor", classEntry.node.getImage(), - String.valueOf(constructorDecisionPointCount), }); - } - } - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import java.util.ArrayDeque; +import java.util.Deque; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; +import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; +import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +/** + * Implements the standard cyclomatic complexity rule + *

+ * Standard rules: +1 for each decision point, including case statements but not + * including boolean operators unlike CyclomaticComplexityRule. + * + * @author Alan Hohn, based on work by Donald A. Leckie + * + * @since June 18, 2014 + */ +public class StdCyclomaticComplexityRule extends AbstractJavaRule { + + public static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty("reportLevel", + "Cyclomatic Complexity reporting threshold", 1, 30, 10, 1.0f); + + public static final BooleanProperty SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty( + "showClassesComplexity", "Add class average violations to the report", true, 2.0f); + + public static final BooleanProperty SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty( + "showMethodsComplexity", "Add method average violations to the report", true, 3.0f); + + private int reportLevel; + private boolean showClassesComplexity = true; + private boolean showMethodsComplexity = true; + + protected static class Entry { + private Node node; + private int decisionPoints = 1; + public int highestDecisionPoints; + public int methodCount; + + private Entry(Node node) { + this.node = node; + } + + public void bumpDecisionPoints() { + decisionPoints++; + } + + public void bumpDecisionPoints(int size) { + decisionPoints += size; + } + + public int getComplexityAverage() { + return (double) methodCount == 0 ? 1 : (int) Math.rint((double) decisionPoints / (double) methodCount); + } + } + + protected Deque entryStack = new ArrayDeque<>(); + + public StdCyclomaticComplexityRule() { + definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR); + definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); + definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); + showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); + showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTIfStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTCatchStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTForStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTDoStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTSwitchStatement node, Object data) { + Entry entry = entryStack.peek(); + + int childCount = node.jjtGetNumChildren(); + int lastIndex = childCount - 1; + for (int n = 0; n < lastIndex; n++) { + Node childNode = node.jjtGetChild(n); + if (childNode instanceof ASTSwitchLabel) { + // default is generally not considered a decision (same as + // "else") + ASTSwitchLabel sl = (ASTSwitchLabel) childNode; + if (!sl.isDefault()) { + childNode = node.jjtGetChild(n + 1); + if (childNode instanceof ASTBlockStatement) { + entry.bumpDecisionPoints(); + } + } + } + } + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTWhileStatement node, Object data) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + return data; + } + + @Override + public Object visit(ASTConditionalExpression node, Object data) { + if (node.isTernary()) { + entryStack.peek().bumpDecisionPoints(); + super.visit(node, data); + } + return data; + } + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry classEntry = entryStack.pop(); + if (showClassesComplexity) { + if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "class", node.getImage(), + classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); + } + } + return data; + } + + @Override + public Object visit(ASTMethodDeclaration node, Object data) { + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry methodEntry = entryStack.pop(); + if (!isSuppressed(node)) { + int methodDecisionPoints = methodEntry.decisionPoints; + Entry classEntry = entryStack.peek(); + classEntry.methodCount++; + classEntry.bumpDecisionPoints(methodDecisionPoints); + + if (methodDecisionPoints > classEntry.highestDecisionPoints) { + classEntry.highestDecisionPoints = methodDecisionPoints; + } + + ASTMethodDeclarator methodDeclarator = null; + for (int n = 0; n < node.jjtGetNumChildren(); n++) { + Node childNode = node.jjtGetChild(n); + if (childNode instanceof ASTMethodDeclarator) { + methodDeclarator = (ASTMethodDeclarator) childNode; + break; + } + } + + if (showMethodsComplexity && methodEntry.decisionPoints >= reportLevel) { + addViolation(data, node, + new String[] { "method", methodDeclarator == null ? "" : methodDeclarator.getImage(), + String.valueOf(methodEntry.decisionPoints), }); + } + } + return data; + } + + @Override + public Object visit(ASTEnumDeclaration node, Object data) { + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry classEntry = entryStack.pop(); + if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "class", node.getImage(), + classEntry.getComplexityAverage() + "(Highest = " + classEntry.highestDecisionPoints + ')', }); + } + return data; + } + + @Override + public Object visit(ASTConstructorDeclaration node, Object data) { + entryStack.push(new Entry(node)); + super.visit(node, data); + Entry constructorEntry = entryStack.pop(); + if (!isSuppressed(node)) { + int constructorDecisionPointCount = constructorEntry.decisionPoints; + Entry classEntry = entryStack.peek(); + classEntry.methodCount++; + classEntry.decisionPoints += constructorDecisionPointCount; + if (constructorDecisionPointCount > classEntry.highestDecisionPoints) { + classEntry.highestDecisionPoints = constructorDecisionPointCount; + } + if (showMethodsComplexity && constructorEntry.decisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "constructor", classEntry.node.getImage(), + String.valueOf(constructorDecisionPointCount), }); + } + } + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/TooManyFieldsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/TooManyFieldsRule.java index 2d890444c1..a7514a9fff 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/TooManyFieldsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codesize/TooManyFieldsRule.java @@ -1,71 +1,71 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codesize; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; -import net.sourceforge.pmd.util.NumericConstants; - -public class TooManyFieldsRule extends AbstractJavaRule { - - private static final int DEFAULT_MAXFIELDS = 15; - - private Map stats; - private Map nodes; - - private static final IntegerProperty MAX_FIELDS_DESCRIPTOR = new IntegerProperty("maxfields", - "Max allowable fields", 1, 300, DEFAULT_MAXFIELDS, 1.0f); - - public TooManyFieldsRule() { - definePropertyDescriptor(MAX_FIELDS_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - - int maxFields = getProperty(MAX_FIELDS_DESCRIPTOR); - - stats = new HashMap<>(5); - nodes = new HashMap<>(5); - - List l = node.findDescendantsOfType(ASTFieldDeclaration.class); - - for (ASTFieldDeclaration fd : l) { - if (fd.isFinal() && fd.isStatic()) { - continue; - } - ASTClassOrInterfaceDeclaration clazz = fd.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); - if (clazz != null && !clazz.isInterface()) { - bumpCounterFor(clazz); - } - } - for (String k : stats.keySet()) { - int val = stats.get(k); - Node n = nodes.get(k); - if (val > maxFields) { - addViolation(data, n); - } - } - return data; - } - - private void bumpCounterFor(ASTClassOrInterfaceDeclaration clazz) { - String key = clazz.getImage(); - if (!stats.containsKey(key)) { - stats.put(key, NumericConstants.ZERO); - nodes.put(key, clazz); - } - Integer i = Integer.valueOf(stats.get(key) + 1); - stats.put(key, i); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codesize; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; +import net.sourceforge.pmd.util.NumericConstants; + +public class TooManyFieldsRule extends AbstractJavaRule { + + private static final int DEFAULT_MAXFIELDS = 15; + + private Map stats; + private Map nodes; + + private static final IntegerProperty MAX_FIELDS_DESCRIPTOR = new IntegerProperty("maxfields", + "Max allowable fields", 1, 300, DEFAULT_MAXFIELDS, 1.0f); + + public TooManyFieldsRule() { + definePropertyDescriptor(MAX_FIELDS_DESCRIPTOR); + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + + int maxFields = getProperty(MAX_FIELDS_DESCRIPTOR); + + stats = new HashMap<>(5); + nodes = new HashMap<>(5); + + List l = node.findDescendantsOfType(ASTFieldDeclaration.class); + + for (ASTFieldDeclaration fd : l) { + if (fd.isFinal() && fd.isStatic()) { + continue; + } + ASTClassOrInterfaceDeclaration clazz = fd.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); + if (clazz != null && !clazz.isInterface()) { + bumpCounterFor(clazz); + } + } + for (String k : stats.keySet()) { + int val = stats.get(k); + Node n = nodes.get(k); + if (val > maxFields) { + addViolation(data, n); + } + } + return data; + } + + private void bumpCounterFor(ASTClassOrInterfaceDeclaration clazz) { + String key = clazz.getImage(); + if (!stats.containsKey(key)) { + stats.put(key, NumericConstants.ZERO); + nodes.put(key, clazz); + } + Integer i = Integer.valueOf(stats.get(key) + 1); + stats.put(key, i); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/AssignmentInOperandRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/AssignmentInOperandRule.java index 46b3e3cc35..290d5f3d6d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/AssignmentInOperandRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/AssignmentInOperandRule.java @@ -1,77 +1,77 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.controversial; - -import net.sourceforge.pmd.PropertySource; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTPostfixExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; - -/** - * - * - */ -public class AssignmentInOperandRule extends AbstractJavaRule { - - private static final BooleanProperty ALLOW_IF_DESCRIPTOR = new BooleanProperty("allowIf", - "Allow assignment within the conditional expression of an if statement", false, 1.0f); - - private static final BooleanProperty ALLOW_FOR_DESCRIPTOR = new BooleanProperty("allowFor", - "Allow assignment within the conditional expression of a for statement", false, 2.0f); - - private static final BooleanProperty ALLOW_WHILE_DESCRIPTOR = new BooleanProperty("allowWhile", - "Allow assignment within the conditional expression of a while statement", false, 3.0f); - - private static final BooleanProperty ALLOW_INCREMENT_DECREMENT_DESCRIPTOR = new BooleanProperty( - "allowIncrementDecrement", - "Allow increment or decrement operators within the conditional expression of an if, for, or while statement", - false, 4.0f); - - public AssignmentInOperandRule() { - definePropertyDescriptor(ALLOW_IF_DESCRIPTOR); - definePropertyDescriptor(ALLOW_FOR_DESCRIPTOR); - definePropertyDescriptor(ALLOW_WHILE_DESCRIPTOR); - definePropertyDescriptor(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR); - } - - @Override - public Object visit(ASTExpression node, Object data) { - Node parent = node.jjtGetParent(); - if ((parent instanceof ASTIfStatement && !getProperty(ALLOW_IF_DESCRIPTOR) - || parent instanceof ASTWhileStatement && !getProperty(ALLOW_WHILE_DESCRIPTOR) - || parent instanceof ASTForStatement && parent.jjtGetChild(1) == node - && !getProperty(ALLOW_FOR_DESCRIPTOR)) - && (node.hasDescendantOfType(ASTAssignmentOperator.class) - || !getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR) - && (node.hasDecendantOfAnyType(ASTPreIncrementExpression.class, - ASTPreDecrementExpression.class, ASTPostfixExpression.class)))) { - - addViolation(data, node); - return data; - } - return super.visit(node, data); - } - - public boolean allowsAllAssignments() { - return getProperty(ALLOW_IF_DESCRIPTOR) && getProperty(ALLOW_FOR_DESCRIPTOR) - && getProperty(ALLOW_WHILE_DESCRIPTOR) && getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR); - } - - /** - * @see PropertySource#dysfunctionReason() - */ - @Override - public String dysfunctionReason() { - return allowsAllAssignments() ? "All assignment types allowed, no checks performed" : null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.controversial; + +import net.sourceforge.pmd.PropertySource; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTForStatement; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTPostfixExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression; +import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; + +/** + * + * + */ +public class AssignmentInOperandRule extends AbstractJavaRule { + + private static final BooleanProperty ALLOW_IF_DESCRIPTOR = new BooleanProperty("allowIf", + "Allow assignment within the conditional expression of an if statement", false, 1.0f); + + private static final BooleanProperty ALLOW_FOR_DESCRIPTOR = new BooleanProperty("allowFor", + "Allow assignment within the conditional expression of a for statement", false, 2.0f); + + private static final BooleanProperty ALLOW_WHILE_DESCRIPTOR = new BooleanProperty("allowWhile", + "Allow assignment within the conditional expression of a while statement", false, 3.0f); + + private static final BooleanProperty ALLOW_INCREMENT_DECREMENT_DESCRIPTOR = new BooleanProperty( + "allowIncrementDecrement", + "Allow increment or decrement operators within the conditional expression of an if, for, or while statement", + false, 4.0f); + + public AssignmentInOperandRule() { + definePropertyDescriptor(ALLOW_IF_DESCRIPTOR); + definePropertyDescriptor(ALLOW_FOR_DESCRIPTOR); + definePropertyDescriptor(ALLOW_WHILE_DESCRIPTOR); + definePropertyDescriptor(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR); + } + + @Override + public Object visit(ASTExpression node, Object data) { + Node parent = node.jjtGetParent(); + if ((parent instanceof ASTIfStatement && !getProperty(ALLOW_IF_DESCRIPTOR) + || parent instanceof ASTWhileStatement && !getProperty(ALLOW_WHILE_DESCRIPTOR) + || parent instanceof ASTForStatement && parent.jjtGetChild(1) == node + && !getProperty(ALLOW_FOR_DESCRIPTOR)) + && (node.hasDescendantOfType(ASTAssignmentOperator.class) + || !getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR) + && (node.hasDecendantOfAnyType(ASTPreIncrementExpression.class, + ASTPreDecrementExpression.class, ASTPostfixExpression.class)))) { + + addViolation(data, node); + return data; + } + return super.visit(node, data); + } + + public boolean allowsAllAssignments() { + return getProperty(ALLOW_IF_DESCRIPTOR) && getProperty(ALLOW_FOR_DESCRIPTOR) + && getProperty(ALLOW_WHILE_DESCRIPTOR) && getProperty(ALLOW_INCREMENT_DECREMENT_DESCRIPTOR); + } + + /** + * @see PropertySource#dysfunctionReason() + */ + @Override + public String dysfunctionReason() { + return allowsAllAssignments() ? "All assignment types allowed, no checks performed" : null; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DataflowAnomalyAnalysisRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DataflowAnomalyAnalysisRule.java index a5ee8f1163..16e1f5e661 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DataflowAnomalyAnalysisRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DataflowAnomalyAnalysisRule.java @@ -1,177 +1,177 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.controversial; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.dfa.DataFlowNode; -import net.sourceforge.pmd.lang.dfa.VariableAccess; -import net.sourceforge.pmd.lang.dfa.pathfinder.CurrentPath; -import net.sourceforge.pmd.lang.dfa.pathfinder.DAAPathFinder; -import net.sourceforge.pmd.lang.dfa.pathfinder.Executable; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -/** - * Starts path search for each method and runs code if found. - * - * @author raik - * @author Sven Jacob - */ -public class DataflowAnomalyAnalysisRule extends AbstractJavaRule implements Executable { - private RuleContext rc; - private List daaRuleViolations; - private int maxRuleViolations; - private int currentRuleViolationCount; - - private static final IntegerProperty MAX_PATH_DESCRIPTOR = new IntegerProperty("maxPaths", - "Maximum number of checked paths per method. A lower value will increase the performance of the rule but may decrease anomalies found.", - 100, 8000, 1000, 1.0f); - - private static final IntegerProperty MAX_VIOLATIONS_DESCRIPTOR = new IntegerProperty("maxViolations", - "Maximum number of anomalies per class", 1, 2000, 100, 2.0f); - - private static class Usage { - public int accessType; - public DataFlowNode node; - - Usage(int accessType, DataFlowNode node) { - this.accessType = accessType; - this.node = node; - } - - public String toString() { - return "accessType = " + accessType + ", line = " + node.getLine(); - } - } - - public DataflowAnomalyAnalysisRule() { - definePropertyDescriptor(MAX_PATH_DESCRIPTOR); - definePropertyDescriptor(MAX_VIOLATIONS_DESCRIPTOR); - } - - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - maxRuleViolations = getProperty(MAX_VIOLATIONS_DESCRIPTOR); - currentRuleViolationCount = 0; - return super.visit(node, data); - } - - public Object visit(ASTMethodDeclaration methodDeclaration, Object data) { - rc = (RuleContext) data; - daaRuleViolations = new ArrayList<>(); - - final DataFlowNode node = methodDeclaration.getDataFlowNode().getFlow().get(0); - - final DAAPathFinder pathFinder = new DAAPathFinder(node, this, getProperty(MAX_PATH_DESCRIPTOR)); - pathFinder.run(); - - super.visit(methodDeclaration, data); - return data; - } - - public void execute(CurrentPath path) { - - if (maxNumberOfViolationsReached()) { - return; - } - - Map usagesByVarName = new HashMap<>(); - - Iterator pathIterator = path.iterator(); - while (pathIterator.hasNext()) { - // iterate all nodes in this path - DataFlowNode inode = pathIterator.next(); - if (inode.getVariableAccess() != null) { - // iterate all variables of this node - for (VariableAccess va : inode.getVariableAccess()) { - - // get the last usage of the current variable - Usage lastUsage = usagesByVarName.get(va.getVariableName()); - if (lastUsage != null) { - // there was a usage to this variable before - checkVariableAccess(inode, va, lastUsage); - } - - Usage newUsage = new Usage(va.getAccessType(), inode); - // put the new usage for the variable - usagesByVarName.put(va.getVariableName(), newUsage); - } - } - } - } - - private void checkVariableAccess(DataFlowNode inode, VariableAccess va, final Usage u) { - // get the start and end line - int startLine = u.node.getLine(); - int endLine = inode.getLine(); - - Node lastNode = inode.getNode(); - Node firstNode = u.node.getNode(); - - if (va.accessTypeMatches(u.accessType) && va.isDefinition()) { // DD - addDaaViolation(rc, lastNode, "DD", va.getVariableName(), startLine, endLine); - } else if (u.accessType == VariableAccess.UNDEFINITION && va.isReference()) { // UR - addDaaViolation(rc, lastNode, "UR", va.getVariableName(), startLine, endLine); - } else if (u.accessType == VariableAccess.DEFINITION && va.isUndefinition()) { // DU - addDaaViolation(rc, firstNode, "DU", va.getVariableName(), startLine, endLine); - } - } - - /** - * Adds a daa violation to the report. - */ - private void addDaaViolation(Object data, Node node, String type, String var, int startLine, int endLine) { - if (!maxNumberOfViolationsReached() && !violationAlreadyExists(type, var, startLine, endLine) && node != null) { - RuleContext ctx = (RuleContext) data; - String msg = type; - if (getMessage() != null) { - msg = MessageFormat.format(getMessage(), type, var, startLine, endLine); - } - DaaRuleViolation violation = new DaaRuleViolation(this, ctx, node, type, msg, var, startLine, endLine); - ctx.getReport().addRuleViolation(violation); - daaRuleViolations.add(violation); - currentRuleViolationCount++; - } - } - - /** - * Maximum number of violations was already reached? - * - * @return true if the maximum number of violations was - * reached, false otherwise. - */ - private boolean maxNumberOfViolationsReached() { - return currentRuleViolationCount >= maxRuleViolations; - } - - /** - * Checks if a violation already exists. This is needed because on the - * different paths same anomalies can occur. - * - * @param type - * @param var - * @param startLine - * @param endLine - * @return true if the violation already was added to the report - */ - private boolean violationAlreadyExists(String type, String var, int startLine, int endLine) { - for (DaaRuleViolation violation : daaRuleViolations) { - if (violation.getBeginLine() == startLine && violation.getEndLine() == endLine - && violation.getType().equals(type) && violation.getVariableName().equals(var)) { - return true; - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.controversial; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.dfa.DataFlowNode; +import net.sourceforge.pmd.lang.dfa.VariableAccess; +import net.sourceforge.pmd.lang.dfa.pathfinder.CurrentPath; +import net.sourceforge.pmd.lang.dfa.pathfinder.DAAPathFinder; +import net.sourceforge.pmd.lang.dfa.pathfinder.Executable; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +/** + * Starts path search for each method and runs code if found. + * + * @author raik + * @author Sven Jacob + */ +public class DataflowAnomalyAnalysisRule extends AbstractJavaRule implements Executable { + private RuleContext rc; + private List daaRuleViolations; + private int maxRuleViolations; + private int currentRuleViolationCount; + + private static final IntegerProperty MAX_PATH_DESCRIPTOR = new IntegerProperty("maxPaths", + "Maximum number of checked paths per method. A lower value will increase the performance of the rule but may decrease anomalies found.", + 100, 8000, 1000, 1.0f); + + private static final IntegerProperty MAX_VIOLATIONS_DESCRIPTOR = new IntegerProperty("maxViolations", + "Maximum number of anomalies per class", 1, 2000, 100, 2.0f); + + private static class Usage { + public int accessType; + public DataFlowNode node; + + Usage(int accessType, DataFlowNode node) { + this.accessType = accessType; + this.node = node; + } + + public String toString() { + return "accessType = " + accessType + ", line = " + node.getLine(); + } + } + + public DataflowAnomalyAnalysisRule() { + definePropertyDescriptor(MAX_PATH_DESCRIPTOR); + definePropertyDescriptor(MAX_VIOLATIONS_DESCRIPTOR); + } + + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + maxRuleViolations = getProperty(MAX_VIOLATIONS_DESCRIPTOR); + currentRuleViolationCount = 0; + return super.visit(node, data); + } + + public Object visit(ASTMethodDeclaration methodDeclaration, Object data) { + rc = (RuleContext) data; + daaRuleViolations = new ArrayList<>(); + + final DataFlowNode node = methodDeclaration.getDataFlowNode().getFlow().get(0); + + final DAAPathFinder pathFinder = new DAAPathFinder(node, this, getProperty(MAX_PATH_DESCRIPTOR)); + pathFinder.run(); + + super.visit(methodDeclaration, data); + return data; + } + + public void execute(CurrentPath path) { + + if (maxNumberOfViolationsReached()) { + return; + } + + Map usagesByVarName = new HashMap<>(); + + Iterator pathIterator = path.iterator(); + while (pathIterator.hasNext()) { + // iterate all nodes in this path + DataFlowNode inode = pathIterator.next(); + if (inode.getVariableAccess() != null) { + // iterate all variables of this node + for (VariableAccess va : inode.getVariableAccess()) { + + // get the last usage of the current variable + Usage lastUsage = usagesByVarName.get(va.getVariableName()); + if (lastUsage != null) { + // there was a usage to this variable before + checkVariableAccess(inode, va, lastUsage); + } + + Usage newUsage = new Usage(va.getAccessType(), inode); + // put the new usage for the variable + usagesByVarName.put(va.getVariableName(), newUsage); + } + } + } + } + + private void checkVariableAccess(DataFlowNode inode, VariableAccess va, final Usage u) { + // get the start and end line + int startLine = u.node.getLine(); + int endLine = inode.getLine(); + + Node lastNode = inode.getNode(); + Node firstNode = u.node.getNode(); + + if (va.accessTypeMatches(u.accessType) && va.isDefinition()) { // DD + addDaaViolation(rc, lastNode, "DD", va.getVariableName(), startLine, endLine); + } else if (u.accessType == VariableAccess.UNDEFINITION && va.isReference()) { // UR + addDaaViolation(rc, lastNode, "UR", va.getVariableName(), startLine, endLine); + } else if (u.accessType == VariableAccess.DEFINITION && va.isUndefinition()) { // DU + addDaaViolation(rc, firstNode, "DU", va.getVariableName(), startLine, endLine); + } + } + + /** + * Adds a daa violation to the report. + */ + private void addDaaViolation(Object data, Node node, String type, String var, int startLine, int endLine) { + if (!maxNumberOfViolationsReached() && !violationAlreadyExists(type, var, startLine, endLine) && node != null) { + RuleContext ctx = (RuleContext) data; + String msg = type; + if (getMessage() != null) { + msg = MessageFormat.format(getMessage(), type, var, startLine, endLine); + } + DaaRuleViolation violation = new DaaRuleViolation(this, ctx, node, type, msg, var, startLine, endLine); + ctx.getReport().addRuleViolation(violation); + daaRuleViolations.add(violation); + currentRuleViolationCount++; + } + } + + /** + * Maximum number of violations was already reached? + * + * @return true if the maximum number of violations was + * reached, false otherwise. + */ + private boolean maxNumberOfViolationsReached() { + return currentRuleViolationCount >= maxRuleViolations; + } + + /** + * Checks if a violation already exists. This is needed because on the + * different paths same anomalies can occur. + * + * @param type + * @param var + * @param startLine + * @param endLine + * @return true if the violation already was added to the report + */ + private boolean violationAlreadyExists(String type, String var, int startLine, int endLine) { + for (DaaRuleViolation violation : daaRuleViolations) { + if (violation.getBeginLine() == startLine && violation.getEndLine() == endLine + && violation.getType().equals(type) && violation.getVariableName().equals(var)) { + return true; + } + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DontImportSunRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DontImportSunRule.java index 841f74aa08..98117e7cc5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DontImportSunRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/DontImportSunRule.java @@ -1,20 +1,20 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.controversial; - -import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class DontImportSunRule extends AbstractJavaRule { - - public Object visit(ASTImportDeclaration node, Object data) { - String img = node.jjtGetChild(0).getImage(); - if (img.startsWith("sun.") && !img.startsWith("sun.misc.Signal")) { - addViolation(data, node); - } - return data; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.controversial; + +import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class DontImportSunRule extends AbstractJavaRule { + + public Object visit(ASTImportDeclaration node, Object data) { + String img = node.jjtGetChild(0).getImage(); + if (img.startsWith("sun.") && !img.startsWith("sun.misc.Signal")) { + addViolation(data, node); + } + return data; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/SuspiciousOctalEscapeRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/SuspiciousOctalEscapeRule.java index 5fe9e825a7..3ac5b21bb4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/SuspiciousOctalEscapeRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/controversial/SuspiciousOctalEscapeRule.java @@ -1,90 +1,90 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.controversial; - -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class SuspiciousOctalEscapeRule extends AbstractJavaRule { - - @Override - public Object visit(ASTLiteral node, Object data) { - if (node.isStringLiteral()) { - String image = node.getImage(); - // trim quotes - String s = image.substring(1, image.length() - 1); - - // process escape sequences - int offset = 0; - for (int slash = s.indexOf('\\', offset); slash != -1 - && slash < s.length() - 1; slash = s.indexOf('\\', offset)) { - String escapeSequence = s.substring(slash + 1); - char first = escapeSequence.charAt(0); - offset = slash + 1; // next offset - after slash - - if (isOctal(first)) { - if (escapeSequence.length() > 1) { - char second = escapeSequence.charAt(1); - if (isOctal(second)) { - if (escapeSequence.length() > 2) { - char third = escapeSequence.charAt(2); - if (isOctal(third)) { - // this is either a three digit octal escape - // or a two-digit - // octal escape followed by an octal digit. - // the value of - // the first digit in the sequence - // determines which is the - // case - if (first != '0' && first != '1' && first != '2' && first != '3') { - // VIOLATION: it's a two-digit octal - // escape followed by - // an octal digit -- legal but very - // confusing! - addViolation(data, node); - } else { - // if there is a 4th decimal digit, it - // could never be part of - // the escape sequence, which is - // confusing - if (escapeSequence.length() > 3) { - char fourth = escapeSequence.charAt(3); - if (isDecimal(fourth)) { - addViolation(data, node); - } - } - } - - } else if (isDecimal(third)) { - // this is a two-digit octal escape followed - // by a decimal digit - // legal but very confusing - addViolation(data, node); - } - } - } else if (isDecimal(second)) { - // this is a one-digit octal escape followed by a - // decimal digit - // legal but very confusing - addViolation(data, node); - } - } - } else if (first == '\\') { - offset++; - } - } - } - - return super.visit(node, data); - } - - private boolean isOctal(char c) { - return c >= '0' && c <= '7'; - } - - private boolean isDecimal(char c) { - return c >= '0' && c <= '9'; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.controversial; + +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class SuspiciousOctalEscapeRule extends AbstractJavaRule { + + @Override + public Object visit(ASTLiteral node, Object data) { + if (node.isStringLiteral()) { + String image = node.getImage(); + // trim quotes + String s = image.substring(1, image.length() - 1); + + // process escape sequences + int offset = 0; + for (int slash = s.indexOf('\\', offset); slash != -1 + && slash < s.length() - 1; slash = s.indexOf('\\', offset)) { + String escapeSequence = s.substring(slash + 1); + char first = escapeSequence.charAt(0); + offset = slash + 1; // next offset - after slash + + if (isOctal(first)) { + if (escapeSequence.length() > 1) { + char second = escapeSequence.charAt(1); + if (isOctal(second)) { + if (escapeSequence.length() > 2) { + char third = escapeSequence.charAt(2); + if (isOctal(third)) { + // this is either a three digit octal escape + // or a two-digit + // octal escape followed by an octal digit. + // the value of + // the first digit in the sequence + // determines which is the + // case + if (first != '0' && first != '1' && first != '2' && first != '3') { + // VIOLATION: it's a two-digit octal + // escape followed by + // an octal digit -- legal but very + // confusing! + addViolation(data, node); + } else { + // if there is a 4th decimal digit, it + // could never be part of + // the escape sequence, which is + // confusing + if (escapeSequence.length() > 3) { + char fourth = escapeSequence.charAt(3); + if (isDecimal(fourth)) { + addViolation(data, node); + } + } + } + + } else if (isDecimal(third)) { + // this is a two-digit octal escape followed + // by a decimal digit + // legal but very confusing + addViolation(data, node); + } + } + } else if (isDecimal(second)) { + // this is a one-digit octal escape followed by a + // decimal digit + // legal but very confusing + addViolation(data, node); + } + } + } else if (first == '\\') { + offset++; + } + } + } + + return super.visit(node, data); + } + + private boolean isOctal(char c) { + return c >= '0' && c <= '7'; + } + + private boolean isDecimal(char c) { + return c >= '0' && c <= '9'; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/CouplingBetweenObjectsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/CouplingBetweenObjectsRule.java index fc95310326..9b6996ae87 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/CouplingBetweenObjectsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/CouplingBetweenObjectsRule.java @@ -1,174 +1,174 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.coupling; - -import java.util.HashSet; -import java.util.Set; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.ClassScope; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -/** - * CouplingBetweenObjects attempts to capture all unique Class attributes, local - * variables, and return types to determine how many objects a class is coupled - * to. This is only a gauge and isn't a hard and fast rule. The threshold value - * is configurable and should be determined accordingly - * - * @author aglover - * @since Feb 20, 2003 - */ -public class CouplingBetweenObjectsRule extends AbstractJavaRule { - - private int couplingCount; - private Set typesFoundSoFar; - - private static final IntegerProperty THRESHOLD_DESCRIPTOR = new IntegerProperty("threshold", - "Unique type reporting threshold", 2, 100, 20, 1.0f); - - public CouplingBetweenObjectsRule() { - definePropertyDescriptor(THRESHOLD_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit cu, Object data) { - typesFoundSoFar = new HashSet<>(); - couplingCount = 0; - - Object returnObj = cu.childrenAccept(this, data); - - if (couplingCount > getProperty(THRESHOLD_DESCRIPTOR)) { - addViolation(data, cu, - "A value of " + couplingCount + " may denote a high amount of coupling within the class"); - } - - return returnObj; - } - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTResultType node, Object data) { - for (int x = 0; x < node.jjtGetNumChildren(); x++) { - Node tNode = node.jjtGetChild(x); - if (tNode instanceof ASTType) { - Node reftypeNode = tNode.jjtGetChild(0); - if (reftypeNode instanceof ASTReferenceType) { - Node classOrIntType = reftypeNode.jjtGetChild(0); - if (classOrIntType instanceof ASTClassOrInterfaceType) { - Node nameNode = classOrIntType; - this.checkVariableType(nameNode, nameNode.getImage()); - } - } - } - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTLocalVariableDeclaration node, Object data) { - handleASTTypeChildren(node); - return super.visit(node, data); - } - - @Override - public Object visit(ASTFormalParameter node, Object data) { - handleASTTypeChildren(node); - return super.visit(node, data); - } - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - for (int x = 0; x < node.jjtGetNumChildren(); ++x) { - Node firstStmt = node.jjtGetChild(x); - if (firstStmt instanceof ASTType) { - ASTType tp = (ASTType) firstStmt; - Node nd = tp.jjtGetChild(0); - checkVariableType(nd, nd.getImage()); - } - } - - return super.visit(node, data); - } - - /** - * convience method to handle hierarchy. This is probably too much work and - * will go away once I figure out the framework - */ - private void handleASTTypeChildren(Node node) { - for (int x = 0; x < node.jjtGetNumChildren(); x++) { - Node sNode = node.jjtGetChild(x); - if (sNode instanceof ASTType) { - Node nameNode = sNode.jjtGetChild(0); - checkVariableType(nameNode, nameNode.getImage()); - } - } - } - - /** - * performs a check on the variable and updates the counter. Counter is - * instance for a class and is reset upon new class scan. - * - * @param variableType - * The variable type. - */ - private void checkVariableType(Node nameNode, String variableType) { - // TODO - move this into the symbol table somehow? - if (nameNode.getParentsOfType(ASTClassOrInterfaceDeclaration.class).isEmpty()) { - return; - } - // if the field is of any type other than the class type - // increment the count - ClassScope clzScope = ((JavaNode) nameNode).getScope().getEnclosingScope(ClassScope.class); - if (!clzScope.getClassName().equals(variableType) && !this.filterTypes(variableType) - && !this.typesFoundSoFar.contains(variableType)) { - couplingCount++; - typesFoundSoFar.add(variableType); - } - } - - /** - * Filters variable type - we don't want primitives, wrappers, strings, etc. - * This needs more work. I'd like to filter out super types and perhaps - * interfaces - * - * @param variableType - * The variable type. - * @return boolean true if variableType is not what we care about - */ - private boolean filterTypes(String variableType) { - return variableType != null && (variableType.startsWith("java.lang.") || "String".equals(variableType) - || filterPrimitivesAndWrappers(variableType)); - } - - /** - * @param variableType - * The variable type. - * @return boolean true if variableType is a primitive or wrapper - */ - private boolean filterPrimitivesAndWrappers(String variableType) { - return "int".equals(variableType) || "Integer".equals(variableType) || "char".equals(variableType) - || "Character".equals(variableType) || "double".equals(variableType) || "long".equals(variableType) - || "short".equals(variableType) || "float".equals(variableType) || "byte".equals(variableType) - || "boolean".equals(variableType); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.coupling; + +import java.util.HashSet; +import java.util.Set; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTResultType; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.ClassScope; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +/** + * CouplingBetweenObjects attempts to capture all unique Class attributes, local + * variables, and return types to determine how many objects a class is coupled + * to. This is only a gauge and isn't a hard and fast rule. The threshold value + * is configurable and should be determined accordingly + * + * @author aglover + * @since Feb 20, 2003 + */ +public class CouplingBetweenObjectsRule extends AbstractJavaRule { + + private int couplingCount; + private Set typesFoundSoFar; + + private static final IntegerProperty THRESHOLD_DESCRIPTOR = new IntegerProperty("threshold", + "Unique type reporting threshold", 2, 100, 20, 1.0f); + + public CouplingBetweenObjectsRule() { + definePropertyDescriptor(THRESHOLD_DESCRIPTOR); + } + + @Override + public Object visit(ASTCompilationUnit cu, Object data) { + typesFoundSoFar = new HashSet<>(); + couplingCount = 0; + + Object returnObj = cu.childrenAccept(this, data); + + if (couplingCount > getProperty(THRESHOLD_DESCRIPTOR)) { + addViolation(data, cu, + "A value of " + couplingCount + " may denote a high amount of coupling within the class"); + } + + return returnObj; + } + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + return super.visit(node, data); + } + + @Override + public Object visit(ASTResultType node, Object data) { + for (int x = 0; x < node.jjtGetNumChildren(); x++) { + Node tNode = node.jjtGetChild(x); + if (tNode instanceof ASTType) { + Node reftypeNode = tNode.jjtGetChild(0); + if (reftypeNode instanceof ASTReferenceType) { + Node classOrIntType = reftypeNode.jjtGetChild(0); + if (classOrIntType instanceof ASTClassOrInterfaceType) { + Node nameNode = classOrIntType; + this.checkVariableType(nameNode, nameNode.getImage()); + } + } + } + } + return super.visit(node, data); + } + + @Override + public Object visit(ASTLocalVariableDeclaration node, Object data) { + handleASTTypeChildren(node); + return super.visit(node, data); + } + + @Override + public Object visit(ASTFormalParameter node, Object data) { + handleASTTypeChildren(node); + return super.visit(node, data); + } + + @Override + public Object visit(ASTFieldDeclaration node, Object data) { + for (int x = 0; x < node.jjtGetNumChildren(); ++x) { + Node firstStmt = node.jjtGetChild(x); + if (firstStmt instanceof ASTType) { + ASTType tp = (ASTType) firstStmt; + Node nd = tp.jjtGetChild(0); + checkVariableType(nd, nd.getImage()); + } + } + + return super.visit(node, data); + } + + /** + * convience method to handle hierarchy. This is probably too much work and + * will go away once I figure out the framework + */ + private void handleASTTypeChildren(Node node) { + for (int x = 0; x < node.jjtGetNumChildren(); x++) { + Node sNode = node.jjtGetChild(x); + if (sNode instanceof ASTType) { + Node nameNode = sNode.jjtGetChild(0); + checkVariableType(nameNode, nameNode.getImage()); + } + } + } + + /** + * performs a check on the variable and updates the counter. Counter is + * instance for a class and is reset upon new class scan. + * + * @param variableType + * The variable type. + */ + private void checkVariableType(Node nameNode, String variableType) { + // TODO - move this into the symbol table somehow? + if (nameNode.getParentsOfType(ASTClassOrInterfaceDeclaration.class).isEmpty()) { + return; + } + // if the field is of any type other than the class type + // increment the count + ClassScope clzScope = ((JavaNode) nameNode).getScope().getEnclosingScope(ClassScope.class); + if (!clzScope.getClassName().equals(variableType) && !this.filterTypes(variableType) + && !this.typesFoundSoFar.contains(variableType)) { + couplingCount++; + typesFoundSoFar.add(variableType); + } + } + + /** + * Filters variable type - we don't want primitives, wrappers, strings, etc. + * This needs more work. I'd like to filter out super types and perhaps + * interfaces + * + * @param variableType + * The variable type. + * @return boolean true if variableType is not what we care about + */ + private boolean filterTypes(String variableType) { + return variableType != null && (variableType.startsWith("java.lang.") || "String".equals(variableType) + || filterPrimitivesAndWrappers(variableType)); + } + + /** + * @param variableType + * The variable type. + * @return boolean true if variableType is a primitive or wrapper + */ + private boolean filterPrimitivesAndWrappers(String variableType) { + return "int".equals(variableType) || "Integer".equals(variableType) || "char".equals(variableType) + || "Character".equals(variableType) || "double".equals(variableType) || "long".equals(variableType) + || "short".equals(variableType) || "float".equals(variableType) || "byte".equals(variableType) + || "boolean".equals(variableType); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/ExcessiveImportsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/ExcessiveImportsRule.java index 0674530384..02c995bf81 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/ExcessiveImportsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/ExcessiveImportsRule.java @@ -1,38 +1,38 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.coupling; - -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; -import net.sourceforge.pmd.lang.java.rule.design.ExcessiveNodeCountRule; -import net.sourceforge.pmd.util.NumericConstants; - -/** - * ExcessiveImports attempts to count all unique imports a class contains. This - * rule will count a "import com.something.*;" as a single import. This is a - * unqiue situation and I'd like to create an audit type rule that captures - * those. - * - * @author aglover - * @since Feb 21, 2003 - */ -public class ExcessiveImportsRule extends ExcessiveNodeCountRule { - - public ExcessiveImportsRule() { - super(ASTCompilationUnit.class); - setProperty(MINIMUM_DESCRIPTOR, 30d); - } - - /** - * Hook method to count imports. This is a user defined value. - * - * @param node - * @param data - * @return Object - */ - public Object visit(ASTImportDeclaration node, Object data) { - return NumericConstants.ONE; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.coupling; + +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.rule.design.ExcessiveNodeCountRule; +import net.sourceforge.pmd.util.NumericConstants; + +/** + * ExcessiveImports attempts to count all unique imports a class contains. This + * rule will count a "import com.something.*;" as a single import. This is a + * unqiue situation and I'd like to create an audit type rule that captures + * those. + * + * @author aglover + * @since Feb 21, 2003 + */ +public class ExcessiveImportsRule extends ExcessiveNodeCountRule { + + public ExcessiveImportsRule() { + super(ASTCompilationUnit.class); + setProperty(MINIMUM_DESCRIPTOR, 30d); + } + + /** + * Hook method to count imports. This is a user defined value. + * + * @param node + * @param data + * @return Object + */ + public Object visit(ASTImportDeclaration node, Object data) { + return NumericConstants.ONE; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LooseCouplingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LooseCouplingRule.java index 0c96ced0bb..5000de0f74 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LooseCouplingRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LooseCouplingRule.java @@ -1,58 +1,58 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.coupling; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.util.CollectionUtil; - -public class LooseCouplingRule extends AbstractJavaRule { - - // TODO - these should be brought in via external properties - // private static final Set implClassNames = CollectionUtil.asSet( new - // Object[] { - // "ArrayList", "HashSet", "HashMap", "LinkedHashMap", "LinkedHashSet", - // "TreeSet", "TreeMap", "Vector", - // "java.util.ArrayList", "java.util.HashSet", "java.util.HashMap", - // "java.util.LinkedHashMap", "java.util.LinkedHashSet", - // "java.util.TreeSet", - // "java.util.TreeMap", "java.util.Vector" - // }); - - public Object visit(ASTClassOrInterfaceType node, Object data) { - if (methodHasOverride(node)) { - return data; - } - Node parent = node.getNthParent(3); - String typeName = node.getImage(); - if (CollectionUtil.isCollectionType(typeName, false) && (parent instanceof ASTFieldDeclaration - || parent instanceof ASTFormalParameter || parent instanceof ASTResultType)) { - addViolation(data, node, typeName); - } - return data; - } - - private boolean methodHasOverride(Node node) { - ASTClassOrInterfaceBodyDeclaration method = node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class); - if (method != null && method.jjtGetNumChildren() > 0 && method.jjtGetChild(0) instanceof ASTAnnotation) { - ASTMarkerAnnotation marker = method.getFirstDescendantOfType(ASTMarkerAnnotation.class); - if (marker != null && marker.getFirstChildOfType(ASTName.class) != null) { - ASTName name = marker.getFirstChildOfType(ASTName.class); - if ("Override".equals(name.getImage())) { - return true; - } - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.coupling; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTResultType; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.util.CollectionUtil; + +public class LooseCouplingRule extends AbstractJavaRule { + + // TODO - these should be brought in via external properties + // private static final Set implClassNames = CollectionUtil.asSet( new + // Object[] { + // "ArrayList", "HashSet", "HashMap", "LinkedHashMap", "LinkedHashSet", + // "TreeSet", "TreeMap", "Vector", + // "java.util.ArrayList", "java.util.HashSet", "java.util.HashMap", + // "java.util.LinkedHashMap", "java.util.LinkedHashSet", + // "java.util.TreeSet", + // "java.util.TreeMap", "java.util.Vector" + // }); + + public Object visit(ASTClassOrInterfaceType node, Object data) { + if (methodHasOverride(node)) { + return data; + } + Node parent = node.getNthParent(3); + String typeName = node.getImage(); + if (CollectionUtil.isCollectionType(typeName, false) && (parent instanceof ASTFieldDeclaration + || parent instanceof ASTFormalParameter || parent instanceof ASTResultType)) { + addViolation(data, node, typeName); + } + return data; + } + + private boolean methodHasOverride(Node node) { + ASTClassOrInterfaceBodyDeclaration method = node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class); + if (method != null && method.jjtGetNumChildren() > 0 && method.jjtGetChild(0) instanceof ASTAnnotation) { + ASTMarkerAnnotation marker = method.getFirstDescendantOfType(ASTMarkerAnnotation.class); + if (marker != null && marker.getFirstChildOfType(ASTName.class) != null) { + ASTName name = marker.getFirstChildOfType(ASTName.class); + if ("Override".equals(name.getImage())) { + return true; + } + } + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LoosePackageCouplingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LoosePackageCouplingRule.java index ef6943d34a..b7c9bac329 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LoosePackageCouplingRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/coupling/LoosePackageCouplingRule.java @@ -1,146 +1,146 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.coupling; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import net.sourceforge.pmd.PropertySource; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; -import net.sourceforge.pmd.util.CollectionUtil; - -/** - * The loose package coupling Rule can be used to ensure coupling outside of a - * package hierarchy is minimized to all but an allowed set of classes from - * within the package hierarchy. - *

- * For example, supposed you have the following package hierarchy: - *

    - *
  • org.sample
  • - *
  • org.sample.impl
  • - *
  • org.sample.util
  • - *
- * And the allowed class org.sample.SampleInterface. - *

- * This rule can be used to ensure that all classes within the - * org.sample package and its sub-packages are not used outside of - * the org.sample package hierarchy. Further, the only allowed - * usage outside of a class in the org.sample hierarchy would be - * via org.sample.SampleInterface. - */ -public class LoosePackageCouplingRule extends AbstractJavaRule { - - public static final StringMultiProperty PACKAGES_DESCRIPTOR = new StringMultiProperty("packages", - "Restricted packages", new String[] {}, 1.0f, ','); - - public static final StringMultiProperty CLASSES_DESCRIPTOR = new StringMultiProperty("classes", "Allowed classes", - new String[] {}, 2.0f, ','); - - // The package of this source file - private String thisPackage; - - // The restricted packages - private List restrictedPackages; - - public LoosePackageCouplingRule() { - definePropertyDescriptor(PACKAGES_DESCRIPTOR); - definePropertyDescriptor(CLASSES_DESCRIPTOR); - - addRuleChainVisit(ASTCompilationUnit.class); - addRuleChainVisit(ASTPackageDeclaration.class); - addRuleChainVisit(ASTImportDeclaration.class); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - this.thisPackage = ""; - - // Sort the restricted packages in reverse order. This will ensure the - // child packages are in the list before their parent packages. - this.restrictedPackages = new ArrayList<>(Arrays.asList(super.getProperty(PACKAGES_DESCRIPTOR))); - Collections.sort(restrictedPackages, Collections.reverseOrder()); - - return data; - } - - @Override - public Object visit(ASTPackageDeclaration node, Object data) { - this.thisPackage = node.getPackageNameImage(); - return data; - } - - @Override - public Object visit(ASTImportDeclaration node, Object data) { - - String importPackage = node.getPackageName(); - - // Check each restricted package - for (String pkg : getRestrictedPackages()) { - // Is this import restricted? Use the deepest sub-package which - // restricts this import. - if (isContainingPackage(pkg, importPackage)) { - // Is this source in a sub-package of restricted package? - if (pkg.equals(thisPackage) || isContainingPackage(pkg, thisPackage)) { - // Valid usage - break; - } else { - // On demand imports automatically fail because they include - // everything - if (node.isImportOnDemand()) { - addViolation(data, node, new Object[] { node.getImportedName(), pkg }); - break; - } else { - if (!isAllowedClass(node)) { - addViolation(data, node, new Object[] { node.getImportedName(), pkg }); - break; - } - } - } - } - } - return data; - } - - protected List getRestrictedPackages() { - return restrictedPackages; - } - - // Is 1st package a containing package of the 2nd package? - protected boolean isContainingPackage(String pkg1, String pkg2) { - return pkg1.equals(pkg2) - || pkg1.length() < pkg2.length() && pkg2.startsWith(pkg1) && pkg2.charAt(pkg1.length()) == '.'; - } - - protected boolean isAllowedClass(ASTImportDeclaration node) { - String importedName = node.getImportedName(); - for (String clazz : getProperty(CLASSES_DESCRIPTOR)) { - if (importedName.equals(clazz)) { - return true; - } - - } - return false; - } - - public boolean checksNothing() { - - return CollectionUtil.isEmpty(getProperty(PACKAGES_DESCRIPTOR)) - && CollectionUtil.isEmpty(getProperty(CLASSES_DESCRIPTOR)); - } - - /** - * @see PropertySource#dysfunctionReason() - */ - @Override - public String dysfunctionReason() { - return checksNothing() ? "No packages or classes specified" : null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.coupling; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.PropertySource; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; +import net.sourceforge.pmd.util.CollectionUtil; + +/** + * The loose package coupling Rule can be used to ensure coupling outside of a + * package hierarchy is minimized to all but an allowed set of classes from + * within the package hierarchy. + *

+ * For example, supposed you have the following package hierarchy: + *

    + *
  • org.sample
  • + *
  • org.sample.impl
  • + *
  • org.sample.util
  • + *
+ * And the allowed class org.sample.SampleInterface. + *

+ * This rule can be used to ensure that all classes within the + * org.sample package and its sub-packages are not used outside of + * the org.sample package hierarchy. Further, the only allowed + * usage outside of a class in the org.sample hierarchy would be + * via org.sample.SampleInterface. + */ +public class LoosePackageCouplingRule extends AbstractJavaRule { + + public static final StringMultiProperty PACKAGES_DESCRIPTOR = new StringMultiProperty("packages", + "Restricted packages", new String[] {}, 1.0f, ','); + + public static final StringMultiProperty CLASSES_DESCRIPTOR = new StringMultiProperty("classes", "Allowed classes", + new String[] {}, 2.0f, ','); + + // The package of this source file + private String thisPackage; + + // The restricted packages + private List restrictedPackages; + + public LoosePackageCouplingRule() { + definePropertyDescriptor(PACKAGES_DESCRIPTOR); + definePropertyDescriptor(CLASSES_DESCRIPTOR); + + addRuleChainVisit(ASTCompilationUnit.class); + addRuleChainVisit(ASTPackageDeclaration.class); + addRuleChainVisit(ASTImportDeclaration.class); + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + this.thisPackage = ""; + + // Sort the restricted packages in reverse order. This will ensure the + // child packages are in the list before their parent packages. + this.restrictedPackages = new ArrayList<>(Arrays.asList(super.getProperty(PACKAGES_DESCRIPTOR))); + Collections.sort(restrictedPackages, Collections.reverseOrder()); + + return data; + } + + @Override + public Object visit(ASTPackageDeclaration node, Object data) { + this.thisPackage = node.getPackageNameImage(); + return data; + } + + @Override + public Object visit(ASTImportDeclaration node, Object data) { + + String importPackage = node.getPackageName(); + + // Check each restricted package + for (String pkg : getRestrictedPackages()) { + // Is this import restricted? Use the deepest sub-package which + // restricts this import. + if (isContainingPackage(pkg, importPackage)) { + // Is this source in a sub-package of restricted package? + if (pkg.equals(thisPackage) || isContainingPackage(pkg, thisPackage)) { + // Valid usage + break; + } else { + // On demand imports automatically fail because they include + // everything + if (node.isImportOnDemand()) { + addViolation(data, node, new Object[] { node.getImportedName(), pkg }); + break; + } else { + if (!isAllowedClass(node)) { + addViolation(data, node, new Object[] { node.getImportedName(), pkg }); + break; + } + } + } + } + } + return data; + } + + protected List getRestrictedPackages() { + return restrictedPackages; + } + + // Is 1st package a containing package of the 2nd package? + protected boolean isContainingPackage(String pkg1, String pkg2) { + return pkg1.equals(pkg2) + || pkg1.length() < pkg2.length() && pkg2.startsWith(pkg1) && pkg2.charAt(pkg1.length()) == '.'; + } + + protected boolean isAllowedClass(ASTImportDeclaration node) { + String importedName = node.getImportedName(); + for (String clazz : getProperty(CLASSES_DESCRIPTOR)) { + if (importedName.equals(clazz)) { + return true; + } + + } + return false; + } + + public boolean checksNothing() { + + return CollectionUtil.isEmpty(getProperty(PACKAGES_DESCRIPTOR)) + && CollectionUtil.isEmpty(getProperty(CLASSES_DESCRIPTOR)); + } + + /** + * @see PropertySource#dysfunctionReason() + */ + @Override + public String dysfunctionReason() { + return checksNothing() ? "No packages or classes specified" : null; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AccessorClassGenerationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AccessorClassGenerationRule.java index 819d28f1f1..e53754c53b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AccessorClassGenerationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AccessorClassGenerationRule.java @@ -1,319 +1,319 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTArguments; -import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessTypeNode; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope; - -/** - * 1. Note all private constructors. 2. Note all instantiations from outside of - * the class by way of the private constructor. 3. Flag instantiations. - * - *

Parameter types can not be matched because they can come as exposed members - * of classes. In this case we have no way to know what the type is. We can make - * a best effort though which can filter some?

- * - * @author CL Gilbert (dnoyeb@users.sourceforge.net) - * @author David Konecny (david.konecny@) - * @author Romain PELISSE, belaran@gmail.com, patch bug#1807370 - */ -public class AccessorClassGenerationRule extends AbstractJavaRule { - - private List classDataList = new ArrayList<>(); - private int classID = -1; - private String packageName; - - public Object visit(ASTEnumDeclaration node, Object data) { - return data; // just skip Enums - } - - public Object visit(ASTCompilationUnit node, Object data) { - classDataList.clear(); - packageName = node.getScope().getEnclosingScope(SourceFileScope.class).getPackageName(); - return super.visit(node, data); - } - - private static class ClassData { - private String className; - private List privateConstructors; - private List instantiations; - /** - * List of outer class names that exist above this class - */ - private List classQualifyingNames; - - ClassData(String className) { - this.className = className; - this.privateConstructors = new ArrayList<>(); - this.instantiations = new ArrayList<>(); - this.classQualifyingNames = new ArrayList<>(); - } - - public void addInstantiation(AllocData ad) { - instantiations.add(ad); - } - - public Iterator getInstantiationIterator() { - return instantiations.iterator(); - } - - public void addConstructor(ASTConstructorDeclaration cd) { - privateConstructors.add(cd); - } - - public Iterator getPrivateConstructorIterator() { - return privateConstructors.iterator(); - } - - public String getClassName() { - return className; - } - - public void addClassQualifyingName(String name) { - classQualifyingNames.add(name); - } - - public List getClassQualifyingNamesList() { - return classQualifyingNames; - } - } - - private static class AllocData { - private String name; - private int argumentCount; - private ASTAllocationExpression allocationExpression; - private boolean isArray; - - AllocData(ASTAllocationExpression node, String aPackageName, List classQualifyingNames) { - if (node.jjtGetChild(1) instanceof ASTArguments) { - ASTArguments aa = (ASTArguments) node.jjtGetChild(1); - argumentCount = aa.getArgumentCount(); - // Get name and strip off all superfluous data - // strip off package name if it is current package - if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) { - throw new RuntimeException( - "BUG: Expected a ASTClassOrInterfaceType, got a " + node.jjtGetChild(0).getClass()); - } - ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) node.jjtGetChild(0); - name = stripString(aPackageName + '.', an.getImage()); - - // strip off outer class names - // try OuterClass, then try OuterClass.InnerClass, then try - // OuterClass.InnerClass.InnerClass2, etc... - String findName = ""; - for (ListIterator li = classQualifyingNames.listIterator(classQualifyingNames.size()); li - .hasPrevious();) { - String aName = li.previous(); - findName = aName + '.' + findName; - if (name.startsWith(findName)) { - // strip off name and exit - name = name.substring(findName.length()); - break; - } - } - } else if (node.jjtGetChild(1) instanceof ASTArrayDimsAndInits) { - // this is incomplete because I dont need it. - // child 0 could be primitive or object (ASTName or - // ASTPrimitiveType) - isArray = true; - } - allocationExpression = node; - } - - public String getName() { - return name; - } - - public int getArgumentCount() { - return argumentCount; - } - - public ASTAllocationExpression getASTAllocationExpression() { - return allocationExpression; - } - - public boolean isArray() { - return isArray; - } - } - - private boolean isToplevelType(JavaNode node) { - return node.jjtGetParent().jjtGetParent() instanceof ASTCompilationUnit; - } - - /** - * Outer interface visitation - */ - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return visitInterface(node, data); - } - - if (!isToplevelType(node)) { - return handleInnerType(node, data); - } - return handleToplevelType(node, data); - } - - private Object visitInterface(ASTClassOrInterfaceDeclaration node, Object data) { - if (!isToplevelType(node)) { - return handleInnerType(node, data); - } - return handleToplevelType(node, data); - } - - @Override - public Object visit(ASTAnnotationTypeDeclaration node, Object data) { - if (!isToplevelType(node)) { - return handleInnerType(node, data); - } - return handleToplevelType(node, data); - } - - private Object handleToplevelType(AbstractJavaAccessTypeNode node, Object data) { - if (!node.isStatic()) { // See bug# 1807370 - String typeName = node.getImage(); - classDataList.clear(); - setClassID(0); // first class - classDataList.add(getClassID(), new ClassData(typeName)); - } - Object o = super.visit(node, data); - if (o != null && !node.isStatic()) { // See bug# 1807370 - processRule(o); - } else { - processRule(data); - } - setClassID(-1); - return o; - } - - private Object handleInnerType(AbstractJavaAccessTypeNode node, Object data) { - String typeName = node.getImage(); - int formerID = getClassID(); - setClassID(classDataList.size()); - ClassData newClassData = new ClassData(typeName); - // store the names of any outer classes of this class in the - // classQualifyingName List - ClassData formerClassData = classDataList.get(formerID); - newClassData.addClassQualifyingName(formerClassData.getClassName()); - classDataList.add(getClassID(), newClassData); - Object o = super.visit(node, data); - setClassID(formerID); - return o; - } - - /** - * Store all target constructors - */ - public Object visit(ASTConstructorDeclaration node, Object data) { - if (node.isPrivate()) { - getCurrentClassData().addConstructor(node); - } - return super.visit(node, data); - } - - public Object visit(ASTAllocationExpression node, Object data) { - // TODO - // this is a hack to bail out here - // but I'm not sure why this is happening - // TODO - if (classID == -1 || getCurrentClassData() == null) { - return data; - } - AllocData ad = new AllocData(node, packageName, getCurrentClassData().getClassQualifyingNamesList()); - if (!ad.isArray()) { - getCurrentClassData().addInstantiation(ad); - } - return super.visit(node, data); - } - - private void processRule(Object ctx) { - // check constructors of outerIterator against allocations of - // innerIterator - for (ClassData outerDataSet : classDataList) { - for (Iterator constructors = outerDataSet - .getPrivateConstructorIterator(); constructors.hasNext();) { - ASTConstructorDeclaration cd = constructors.next(); - - for (ClassData innerDataSet : classDataList) { - if (outerDataSet.equals(innerDataSet)) { - continue; - } - for (Iterator allocations = innerDataSet.getInstantiationIterator(); allocations - .hasNext();) { - AllocData ad = allocations.next(); - // if the constructor matches the instantiation - // flag the instantiation as a generator of an extra - // class - if (outerDataSet.getClassName().equals(ad.getName()) - && cd.getParameterCount() == ad.getArgumentCount()) { - addViolation(ctx, ad.getASTAllocationExpression()); - } - } - } - } - } - } - - private ClassData getCurrentClassData() { - // TODO - // this is a hack to bail out here - // but I'm not sure why this is happening - // TODO - if (classID >= classDataList.size()) { - return null; - } - return classDataList.get(classID); - } - - private void setClassID(int id) { - classID = id; - } - - private int getClassID() { - return classID; - } - - // remove = Fire. - // value = someFire.Fighter - // 0123456789012345 - // index = 4 - // remove.size() = 5 - // value.substring(0,4) = some - // value.substring(4 + remove.size()) = Fighter - // return "someFighter" - - // TODO move this into StringUtil - private static String stripString(String remove, String value) { - String returnValue; - int index = value.indexOf(remove); - if (index != -1) { - // if the package name can start anywhere but 0 - // please inform the author because this will break - returnValue = value.substring(0, index) + value.substring(index + remove.length()); - } else { - returnValue = value; - } - return returnValue; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTArguments; +import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessTypeNode; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope; + +/** + * 1. Note all private constructors. 2. Note all instantiations from outside of + * the class by way of the private constructor. 3. Flag instantiations. + * + *

Parameter types can not be matched because they can come as exposed members + * of classes. In this case we have no way to know what the type is. We can make + * a best effort though which can filter some?

+ * + * @author CL Gilbert (dnoyeb@users.sourceforge.net) + * @author David Konecny (david.konecny@) + * @author Romain PELISSE, belaran@gmail.com, patch bug#1807370 + */ +public class AccessorClassGenerationRule extends AbstractJavaRule { + + private List classDataList = new ArrayList<>(); + private int classID = -1; + private String packageName; + + public Object visit(ASTEnumDeclaration node, Object data) { + return data; // just skip Enums + } + + public Object visit(ASTCompilationUnit node, Object data) { + classDataList.clear(); + packageName = node.getScope().getEnclosingScope(SourceFileScope.class).getPackageName(); + return super.visit(node, data); + } + + private static class ClassData { + private String className; + private List privateConstructors; + private List instantiations; + /** + * List of outer class names that exist above this class + */ + private List classQualifyingNames; + + ClassData(String className) { + this.className = className; + this.privateConstructors = new ArrayList<>(); + this.instantiations = new ArrayList<>(); + this.classQualifyingNames = new ArrayList<>(); + } + + public void addInstantiation(AllocData ad) { + instantiations.add(ad); + } + + public Iterator getInstantiationIterator() { + return instantiations.iterator(); + } + + public void addConstructor(ASTConstructorDeclaration cd) { + privateConstructors.add(cd); + } + + public Iterator getPrivateConstructorIterator() { + return privateConstructors.iterator(); + } + + public String getClassName() { + return className; + } + + public void addClassQualifyingName(String name) { + classQualifyingNames.add(name); + } + + public List getClassQualifyingNamesList() { + return classQualifyingNames; + } + } + + private static class AllocData { + private String name; + private int argumentCount; + private ASTAllocationExpression allocationExpression; + private boolean isArray; + + AllocData(ASTAllocationExpression node, String aPackageName, List classQualifyingNames) { + if (node.jjtGetChild(1) instanceof ASTArguments) { + ASTArguments aa = (ASTArguments) node.jjtGetChild(1); + argumentCount = aa.getArgumentCount(); + // Get name and strip off all superfluous data + // strip off package name if it is current package + if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) { + throw new RuntimeException( + "BUG: Expected a ASTClassOrInterfaceType, got a " + node.jjtGetChild(0).getClass()); + } + ASTClassOrInterfaceType an = (ASTClassOrInterfaceType) node.jjtGetChild(0); + name = stripString(aPackageName + '.', an.getImage()); + + // strip off outer class names + // try OuterClass, then try OuterClass.InnerClass, then try + // OuterClass.InnerClass.InnerClass2, etc... + String findName = ""; + for (ListIterator li = classQualifyingNames.listIterator(classQualifyingNames.size()); li + .hasPrevious();) { + String aName = li.previous(); + findName = aName + '.' + findName; + if (name.startsWith(findName)) { + // strip off name and exit + name = name.substring(findName.length()); + break; + } + } + } else if (node.jjtGetChild(1) instanceof ASTArrayDimsAndInits) { + // this is incomplete because I dont need it. + // child 0 could be primitive or object (ASTName or + // ASTPrimitiveType) + isArray = true; + } + allocationExpression = node; + } + + public String getName() { + return name; + } + + public int getArgumentCount() { + return argumentCount; + } + + public ASTAllocationExpression getASTAllocationExpression() { + return allocationExpression; + } + + public boolean isArray() { + return isArray; + } + } + + private boolean isToplevelType(JavaNode node) { + return node.jjtGetParent().jjtGetParent() instanceof ASTCompilationUnit; + } + + /** + * Outer interface visitation + */ + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return visitInterface(node, data); + } + + if (!isToplevelType(node)) { + return handleInnerType(node, data); + } + return handleToplevelType(node, data); + } + + private Object visitInterface(ASTClassOrInterfaceDeclaration node, Object data) { + if (!isToplevelType(node)) { + return handleInnerType(node, data); + } + return handleToplevelType(node, data); + } + + @Override + public Object visit(ASTAnnotationTypeDeclaration node, Object data) { + if (!isToplevelType(node)) { + return handleInnerType(node, data); + } + return handleToplevelType(node, data); + } + + private Object handleToplevelType(AbstractJavaAccessTypeNode node, Object data) { + if (!node.isStatic()) { // See bug# 1807370 + String typeName = node.getImage(); + classDataList.clear(); + setClassID(0); // first class + classDataList.add(getClassID(), new ClassData(typeName)); + } + Object o = super.visit(node, data); + if (o != null && !node.isStatic()) { // See bug# 1807370 + processRule(o); + } else { + processRule(data); + } + setClassID(-1); + return o; + } + + private Object handleInnerType(AbstractJavaAccessTypeNode node, Object data) { + String typeName = node.getImage(); + int formerID = getClassID(); + setClassID(classDataList.size()); + ClassData newClassData = new ClassData(typeName); + // store the names of any outer classes of this class in the + // classQualifyingName List + ClassData formerClassData = classDataList.get(formerID); + newClassData.addClassQualifyingName(formerClassData.getClassName()); + classDataList.add(getClassID(), newClassData); + Object o = super.visit(node, data); + setClassID(formerID); + return o; + } + + /** + * Store all target constructors + */ + public Object visit(ASTConstructorDeclaration node, Object data) { + if (node.isPrivate()) { + getCurrentClassData().addConstructor(node); + } + return super.visit(node, data); + } + + public Object visit(ASTAllocationExpression node, Object data) { + // TODO + // this is a hack to bail out here + // but I'm not sure why this is happening + // TODO + if (classID == -1 || getCurrentClassData() == null) { + return data; + } + AllocData ad = new AllocData(node, packageName, getCurrentClassData().getClassQualifyingNamesList()); + if (!ad.isArray()) { + getCurrentClassData().addInstantiation(ad); + } + return super.visit(node, data); + } + + private void processRule(Object ctx) { + // check constructors of outerIterator against allocations of + // innerIterator + for (ClassData outerDataSet : classDataList) { + for (Iterator constructors = outerDataSet + .getPrivateConstructorIterator(); constructors.hasNext();) { + ASTConstructorDeclaration cd = constructors.next(); + + for (ClassData innerDataSet : classDataList) { + if (outerDataSet.equals(innerDataSet)) { + continue; + } + for (Iterator allocations = innerDataSet.getInstantiationIterator(); allocations + .hasNext();) { + AllocData ad = allocations.next(); + // if the constructor matches the instantiation + // flag the instantiation as a generator of an extra + // class + if (outerDataSet.getClassName().equals(ad.getName()) + && cd.getParameterCount() == ad.getArgumentCount()) { + addViolation(ctx, ad.getASTAllocationExpression()); + } + } + } + } + } + } + + private ClassData getCurrentClassData() { + // TODO + // this is a hack to bail out here + // but I'm not sure why this is happening + // TODO + if (classID >= classDataList.size()) { + return null; + } + return classDataList.get(classID); + } + + private void setClassID(int id) { + classID = id; + } + + private int getClassID() { + return classID; + } + + // remove = Fire. + // value = someFire.Fighter + // 0123456789012345 + // index = 4 + // remove.size() = 5 + // value.substring(0,4) = some + // value.substring(4 + remove.size()) = Fighter + // return "someFighter" + + // TODO move this into StringUtil + private static String stripString(String remove, String value) { + String returnValue; + int index = value.indexOf(remove); + if (index != -1) { + // if the package name can start anywhere but 0 + // please inform the author because this will break + returnValue = value.substring(0, index) + value.substring(index + remove.length()); + } else { + returnValue = value; + } + return returnValue; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidDeeplyNestedIfStmtsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidDeeplyNestedIfStmtsRule.java index 2bc5ba9686..e9ea9ab08f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidDeeplyNestedIfStmtsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidDeeplyNestedIfStmtsRule.java @@ -1,41 +1,41 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; - -public class AvoidDeeplyNestedIfStmtsRule extends AbstractJavaRule { - - private int depth; - private int depthLimit; - - private static final IntegerProperty PROBLEM_DEPTH_DESCRIPTOR = new IntegerProperty("problemDepth", - "The if statement depth reporting threshold", 1, 25, 3, 1.0f); - - public AvoidDeeplyNestedIfStmtsRule() { - definePropertyDescriptor(PROBLEM_DEPTH_DESCRIPTOR); - } - - public Object visit(ASTCompilationUnit node, Object data) { - depth = 0; - depthLimit = getProperty(PROBLEM_DEPTH_DESCRIPTOR); - return super.visit(node, data); - } - - public Object visit(ASTIfStatement node, Object data) { - if (!node.hasElse()) { - depth++; - } - super.visit(node, data); - if (depth == depthLimit) { - addViolation(data, node); - } - depth--; - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.IntegerProperty; + +public class AvoidDeeplyNestedIfStmtsRule extends AbstractJavaRule { + + private int depth; + private int depthLimit; + + private static final IntegerProperty PROBLEM_DEPTH_DESCRIPTOR = new IntegerProperty("problemDepth", + "The if statement depth reporting threshold", 1, 25, 3, 1.0f); + + public AvoidDeeplyNestedIfStmtsRule() { + definePropertyDescriptor(PROBLEM_DEPTH_DESCRIPTOR); + } + + public Object visit(ASTCompilationUnit node, Object data) { + depth = 0; + depthLimit = getProperty(PROBLEM_DEPTH_DESCRIPTOR); + return super.visit(node, data); + } + + public Object visit(ASTIfStatement node, Object data) { + if (!node.hasElse()) { + depth++; + } + super.visit(node, data); + if (depth == depthLimit) { + addViolation(data, node); + } + depth--; + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidReassigningParametersRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidReassigningParametersRule.java index 9d9a6b9e84..21614ccd54 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidReassigningParametersRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/AvoidReassigningParametersRule.java @@ -1,52 +1,52 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -public class AvoidReassigningParametersRule extends AbstractJavaRule { - - @Override - public Object visit(ASTMethodDeclarator node, Object data) { - Map> params = node.getScope() - .getDeclarations(VariableNameDeclaration.class); - this.lookForViolation(params, data); - return super.visit(node, data); - } - - private void lookForViolation(Map> params, Object data) { - for (Map.Entry> entry : params.entrySet()) { - VariableNameDeclaration decl = entry.getKey(); - List usages = entry.getValue(); - for (NameOccurrence occ : usages) { - JavaNameOccurrence jocc = (JavaNameOccurrence) occ; - if ((jocc.isOnLeftHandSide() || jocc.isSelfAssignment()) - && jocc.getNameForWhichThisIsAQualifier() == null && !jocc.useThisOrSuper() && !decl.isVarargs() - && (!decl.isArray() - || jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetNumChildren() == 1)) { - // not an array or no primary suffix to access the array - // values - addViolation(data, decl.getNode(), decl.getImage()); - } - } - } - } - - @Override - public Object visit(ASTConstructorDeclaration node, Object data) { - Map> params = node.getScope() - .getDeclarations(VariableNameDeclaration.class); - this.lookForViolation(params, data); - return super.visit(node, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +public class AvoidReassigningParametersRule extends AbstractJavaRule { + + @Override + public Object visit(ASTMethodDeclarator node, Object data) { + Map> params = node.getScope() + .getDeclarations(VariableNameDeclaration.class); + this.lookForViolation(params, data); + return super.visit(node, data); + } + + private void lookForViolation(Map> params, Object data) { + for (Map.Entry> entry : params.entrySet()) { + VariableNameDeclaration decl = entry.getKey(); + List usages = entry.getValue(); + for (NameOccurrence occ : usages) { + JavaNameOccurrence jocc = (JavaNameOccurrence) occ; + if ((jocc.isOnLeftHandSide() || jocc.isSelfAssignment()) + && jocc.getNameForWhichThisIsAQualifier() == null && !jocc.useThisOrSuper() && !decl.isVarargs() + && (!decl.isArray() + || jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetNumChildren() == 1)) { + // not an array or no primary suffix to access the array + // values + addViolation(data, decl.getNode(), decl.getImage()); + } + } + } + } + + @Override + public Object visit(ASTConstructorDeclaration node, Object data) { + Map> params = node.getScope() + .getDeclarations(VariableNameDeclaration.class); + this.lookForViolation(params, data); + return super.visit(node, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CloseResourceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CloseResourceRule.java index 52ad1bbd18..887c55c9c7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CloseResourceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CloseResourceRule.java @@ -1,376 +1,376 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.jaxen.JaxenException; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; -import net.sourceforge.pmd.lang.java.ast.ASTBlock; -import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; -import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; -import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; - -/** - * Makes sure you close your database connections. It does this by looking for - * code patterned like this: - * - *
- *  Connection c = X;
- *  try {
- *   // do stuff, and maybe catch something
- *  } finally {
- *   c.close();
- *  }
- * 
- * - * @author original author unknown - * @author Contribution from Pierre Mathien - */ -public class CloseResourceRule extends AbstractJavaRule { - - private Set types = new HashSet<>(); - private Set simpleTypes = new HashSet<>(); - - private Set closeTargets = new HashSet<>(); - private static final StringMultiProperty CLOSE_TARGETS_DESCRIPTOR = new StringMultiProperty("closeTargets", - "Methods which may close this resource", new String[] {}, 1.0f, ','); - - private static final StringMultiProperty TYPES_DESCRIPTOR = new StringMultiProperty("types", "Affected types", - new String[] { "java.sql.Connection", "java.sql.Statement", "java.sql.ResultSet" }, 2.0f, ','); - - private static final BooleanProperty USE_CLOSE_AS_DEFAULT_TARGET = new BooleanProperty("closeAsDefaultTarget", - "Consider 'close' as a target by default", true, 3.0f); - - public CloseResourceRule() { - definePropertyDescriptor(CLOSE_TARGETS_DESCRIPTOR); - definePropertyDescriptor(TYPES_DESCRIPTOR); - definePropertyDescriptor(USE_CLOSE_AS_DEFAULT_TARGET); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - if (closeTargets.isEmpty() && getProperty(CLOSE_TARGETS_DESCRIPTOR) != null) { - closeTargets.addAll(Arrays.asList(getProperty(CLOSE_TARGETS_DESCRIPTOR))); - } - if (getProperty(USE_CLOSE_AS_DEFAULT_TARGET) && !closeTargets.contains("close")) { - closeTargets.add("close"); - } - if (types.isEmpty() && getProperty(TYPES_DESCRIPTOR) != null) { - types.addAll(Arrays.asList(getProperty(TYPES_DESCRIPTOR))); - } - if (simpleTypes.isEmpty() && getProperty(TYPES_DESCRIPTOR) != null) { - for (String type : getProperty(TYPES_DESCRIPTOR)) { - simpleTypes.add(toSimpleType(type)); - } - } - return super.visit(node, data); - } - - private static String toSimpleType(String fullyQualifiedClassName) { - int lastIndexOf = fullyQualifiedClassName.lastIndexOf('.'); - if (lastIndexOf > -1) { - return fullyQualifiedClassName.substring(lastIndexOf + 1); - } else { - return fullyQualifiedClassName; - } - } - - @Override - public Object visit(ASTConstructorDeclaration node, Object data) { - checkForResources(node, data); - return data; - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - checkForResources(node, data); - return data; - } - - private void checkForResources(Node node, Object data) { - List vars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class); - List ids = new ArrayList<>(); - - // find all variable references to Connection objects - for (ASTLocalVariableDeclaration var : vars) { - ASTType type = var.getTypeNode(); - - if (type.jjtGetChild(0) instanceof ASTReferenceType) { - ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0); - if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) { - ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); - - if (clazz.getType() != null && types.contains(clazz.getType().getName()) - || clazz.getType() == null && simpleTypes.contains(toSimpleType(clazz.getImage())) - && !clazz.isReferenceToClassSameCompilationUnit() - || types.contains(clazz.getImage()) && !clazz.isReferenceToClassSameCompilationUnit()) { - - ASTVariableDeclaratorId id = var.getFirstDescendantOfType(ASTVariableDeclaratorId.class); - ids.add(id); - } - } - } - } - - // if there are connections, ensure each is closed. - for (ASTVariableDeclaratorId x : ids) { - ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data); - } - } - - private boolean hasNullInitializer(ASTLocalVariableDeclaration var) { - ASTVariableInitializer init = var.getFirstDescendantOfType(ASTVariableInitializer.class); - if (init != null) { - try { - List nulls = init - .findChildNodesWithXPath("Expression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral"); - return !nulls.isEmpty(); - } catch (JaxenException e) { - return false; - } - } - return false; - } - - private void ensureClosed(ASTLocalVariableDeclaration var, ASTVariableDeclaratorId id, Object data) { - // What are the chances of a Connection being instantiated in a - // for-loop init block? Anyway, I'm lazy! - String variableToClose = id.getImage(); - Node n = var; - - while (!(n instanceof ASTBlock) && !(n instanceof ASTConstructorDeclaration)) { - n = n.jjtGetParent(); - } - - Node top = n; - - List tryblocks = top.findDescendantsOfType(ASTTryStatement.class); - - boolean closed = false; - - ASTBlockStatement parentBlock = id.getFirstParentOfType(ASTBlockStatement.class); - - // look for try blocks below the line the variable was - // introduced and make sure there is a .close call in a finally - // block. - for (ASTTryStatement t : tryblocks) { - - // verifies that there are no critical statements between the - // variable declaration and - // the beginning of the try block. - ASTBlockStatement tryBlock = t.getFirstParentOfType(ASTBlockStatement.class); - // no need to check for critical statements, if - // the variable has been initialized with null - if (!hasNullInitializer(var) && parentBlock.jjtGetParent() == tryBlock.jjtGetParent()) { - - List blocks = parentBlock.jjtGetParent().findChildrenOfType(ASTBlockStatement.class); - int parentBlockIndex = blocks.indexOf(parentBlock); - int tryBlockIndex = blocks.indexOf(tryBlock); - boolean criticalStatements = false; - - for (int i = parentBlockIndex + 1; i < tryBlockIndex; i++) { - // assume variable declarations are not critical - ASTLocalVariableDeclaration varDecl = blocks.get(i) - .getFirstDescendantOfType(ASTLocalVariableDeclaration.class); - if (varDecl == null) { - criticalStatements = true; - break; - } - } - if (criticalStatements) { - break; - } - } - - if (t.getBeginLine() > id.getBeginLine() && t.hasFinally()) { - ASTBlock f = (ASTBlock) t.getFinally().jjtGetChild(0); - List names = f.findDescendantsOfType(ASTName.class); - for (ASTName oName : names) { - String name = oName.getImage(); - if (name != null && name.contains(".")) { - String[] parts = name.split("\\."); - if (parts.length == 2) { - String methodName = parts[1]; - String varName = parts[0]; - if (varName.equals(variableToClose) && closeTargets.contains(methodName) - && nullCheckIfCondition(f, oName, varName)) { - closed = true; - break; - } - - } - } - } - if (closed) { - break; - } - - List exprs = new ArrayList<>(); - f.findDescendantsOfType(ASTStatementExpression.class, exprs, true); - for (ASTStatementExpression stmt : exprs) { - ASTPrimaryExpression expr = stmt.getFirstChildOfType(ASTPrimaryExpression.class); - if (expr != null) { - ASTPrimaryPrefix prefix = expr.getFirstChildOfType(ASTPrimaryPrefix.class); - ASTPrimarySuffix suffix = expr.getFirstChildOfType(ASTPrimarySuffix.class); - if (prefix != null && suffix != null) { - if (prefix.getImage() == null) { - ASTName prefixName = prefix.getFirstChildOfType(ASTName.class); - if (prefixName != null && closeTargets.contains(prefixName.getImage())) { - // Found a call to a "close target" that is - // a direct - // method call without a "ClassName." - // prefix. - closed = variableIsPassedToMethod(expr, variableToClose); - if (closed) { - break; - } - } - } else if (suffix.getImage() != null) { - String prefixPlusSuffix = prefix.getImage() + "." + suffix.getImage(); - if (closeTargets.contains(prefixPlusSuffix)) { - // Found a call to a "close target" that is - // a method call - // in the form "ClassName.methodName". - closed = variableIsPassedToMethod(expr, variableToClose); - if (closed) { - break; - } - } - } - // look for primary suffix containing the close - // Targets elements. - // If the .close is executed in another class - // accessed by a method - // this form : - // getProviderInstance().closeConnexion(connexion) - // For this use case, we assume the variable is - // correctly closed - // in the other class since there is no way to - // really check it. - if (!closed) { - List suffixes = new ArrayList<>(); - expr.findDescendantsOfType(ASTPrimarySuffix.class, suffixes, true); - for (ASTPrimarySuffix oSuffix : suffixes) { - String suff = oSuffix.getImage(); - if (closeTargets.contains(suff)) { - closed = variableIsPassedToMethod(expr, variableToClose); - if (closed) { - break; - } - } - - } - } - } - } - } - if (closed) { - break; - } - } - } - - if (!closed) { - // See if the variable is returned by the method, which means the - // method is a utility for creating the db resource, which means of - // course it can't be closed by the method, so it isn't an error. - List returns = new ArrayList<>(); - top.findDescendantsOfType(ASTReturnStatement.class, returns, true); - for (ASTReturnStatement returnStatement : returns) { - ASTName name = returnStatement.getFirstDescendantOfType(ASTName.class); - if (name != null && name.getImage().equals(variableToClose)) { - closed = true; - break; - } - } - } - - // if all is not well, complain - if (!closed) { - ASTType type = var.getFirstChildOfType(ASTType.class); - ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0); - ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); - addViolation(data, id, clazz.getImage()); - } - } - - private boolean variableIsPassedToMethod(ASTPrimaryExpression expr, String variable) { - List methodParams = new ArrayList<>(); - expr.findDescendantsOfType(ASTName.class, methodParams, true); - for (ASTName pName : methodParams) { - String paramName = pName.getImage(); - // also check if we've got the a parameter (i.e if it's an argument - // !) - ASTArgumentList parentParam = pName.getFirstParentOfType(ASTArgumentList.class); - if (paramName.equals(variable) && parentParam != null) { - return true; - } - } - return false; - } - - private ASTIfStatement findIfStatement(ASTBlock enclosingBlock, Node node) { - ASTIfStatement ifStatement = node.getFirstParentOfType(ASTIfStatement.class); - List allIfStatements = enclosingBlock.findDescendantsOfType(ASTIfStatement.class); - if (ifStatement != null && allIfStatements.contains(ifStatement)) { - return ifStatement; - } - return null; - } - - /** - * Checks, whether the given node is inside a if condition, and if so, - * whether this is a null check for the given varName. - * - * @param enclosingBlock - * where to search for if statements - * @param node - * the node, where the call for the close is done - * @param varName - * the variable, that is maybe null-checked - * @return true if no if condition is involved or if the if - * condition is a null-check. - */ - private boolean nullCheckIfCondition(ASTBlock enclosingBlock, Node node, String varName) { - ASTIfStatement ifStatement = findIfStatement(enclosingBlock, node); - if (ifStatement != null) { - try { - // find expressions like: varName != null or null != varName - List nodes = ifStatement.findChildNodesWithXPath("Expression/EqualityExpression[@Image='!=']" - + " [PrimaryExpression/PrimaryPrefix/Name[@Image='" + varName + "']]" - + " [PrimaryExpression/PrimaryPrefix/Literal/NullLiteral]"); - return !nodes.isEmpty(); - } catch (JaxenException e) { - // no boolean literals or other condition - } - } - return true; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jaxen.JaxenException; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; +import net.sourceforge.pmd.lang.java.ast.ASTBlock; +import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; +import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; + +/** + * Makes sure you close your database connections. It does this by looking for + * code patterned like this: + * + *
+ *  Connection c = X;
+ *  try {
+ *   // do stuff, and maybe catch something
+ *  } finally {
+ *   c.close();
+ *  }
+ * 
+ * + * @author original author unknown + * @author Contribution from Pierre Mathien + */ +public class CloseResourceRule extends AbstractJavaRule { + + private Set types = new HashSet<>(); + private Set simpleTypes = new HashSet<>(); + + private Set closeTargets = new HashSet<>(); + private static final StringMultiProperty CLOSE_TARGETS_DESCRIPTOR = new StringMultiProperty("closeTargets", + "Methods which may close this resource", new String[] {}, 1.0f, ','); + + private static final StringMultiProperty TYPES_DESCRIPTOR = new StringMultiProperty("types", "Affected types", + new String[] { "java.sql.Connection", "java.sql.Statement", "java.sql.ResultSet" }, 2.0f, ','); + + private static final BooleanProperty USE_CLOSE_AS_DEFAULT_TARGET = new BooleanProperty("closeAsDefaultTarget", + "Consider 'close' as a target by default", true, 3.0f); + + public CloseResourceRule() { + definePropertyDescriptor(CLOSE_TARGETS_DESCRIPTOR); + definePropertyDescriptor(TYPES_DESCRIPTOR); + definePropertyDescriptor(USE_CLOSE_AS_DEFAULT_TARGET); + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + if (closeTargets.isEmpty() && getProperty(CLOSE_TARGETS_DESCRIPTOR) != null) { + closeTargets.addAll(Arrays.asList(getProperty(CLOSE_TARGETS_DESCRIPTOR))); + } + if (getProperty(USE_CLOSE_AS_DEFAULT_TARGET) && !closeTargets.contains("close")) { + closeTargets.add("close"); + } + if (types.isEmpty() && getProperty(TYPES_DESCRIPTOR) != null) { + types.addAll(Arrays.asList(getProperty(TYPES_DESCRIPTOR))); + } + if (simpleTypes.isEmpty() && getProperty(TYPES_DESCRIPTOR) != null) { + for (String type : getProperty(TYPES_DESCRIPTOR)) { + simpleTypes.add(toSimpleType(type)); + } + } + return super.visit(node, data); + } + + private static String toSimpleType(String fullyQualifiedClassName) { + int lastIndexOf = fullyQualifiedClassName.lastIndexOf('.'); + if (lastIndexOf > -1) { + return fullyQualifiedClassName.substring(lastIndexOf + 1); + } else { + return fullyQualifiedClassName; + } + } + + @Override + public Object visit(ASTConstructorDeclaration node, Object data) { + checkForResources(node, data); + return data; + } + + @Override + public Object visit(ASTMethodDeclaration node, Object data) { + checkForResources(node, data); + return data; + } + + private void checkForResources(Node node, Object data) { + List vars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class); + List ids = new ArrayList<>(); + + // find all variable references to Connection objects + for (ASTLocalVariableDeclaration var : vars) { + ASTType type = var.getTypeNode(); + + if (type.jjtGetChild(0) instanceof ASTReferenceType) { + ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0); + if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) { + ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); + + if (clazz.getType() != null && types.contains(clazz.getType().getName()) + || clazz.getType() == null && simpleTypes.contains(toSimpleType(clazz.getImage())) + && !clazz.isReferenceToClassSameCompilationUnit() + || types.contains(clazz.getImage()) && !clazz.isReferenceToClassSameCompilationUnit()) { + + ASTVariableDeclaratorId id = var.getFirstDescendantOfType(ASTVariableDeclaratorId.class); + ids.add(id); + } + } + } + } + + // if there are connections, ensure each is closed. + for (ASTVariableDeclaratorId x : ids) { + ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data); + } + } + + private boolean hasNullInitializer(ASTLocalVariableDeclaration var) { + ASTVariableInitializer init = var.getFirstDescendantOfType(ASTVariableInitializer.class); + if (init != null) { + try { + List nulls = init + .findChildNodesWithXPath("Expression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral"); + return !nulls.isEmpty(); + } catch (JaxenException e) { + return false; + } + } + return false; + } + + private void ensureClosed(ASTLocalVariableDeclaration var, ASTVariableDeclaratorId id, Object data) { + // What are the chances of a Connection being instantiated in a + // for-loop init block? Anyway, I'm lazy! + String variableToClose = id.getImage(); + Node n = var; + + while (!(n instanceof ASTBlock) && !(n instanceof ASTConstructorDeclaration)) { + n = n.jjtGetParent(); + } + + Node top = n; + + List tryblocks = top.findDescendantsOfType(ASTTryStatement.class); + + boolean closed = false; + + ASTBlockStatement parentBlock = id.getFirstParentOfType(ASTBlockStatement.class); + + // look for try blocks below the line the variable was + // introduced and make sure there is a .close call in a finally + // block. + for (ASTTryStatement t : tryblocks) { + + // verifies that there are no critical statements between the + // variable declaration and + // the beginning of the try block. + ASTBlockStatement tryBlock = t.getFirstParentOfType(ASTBlockStatement.class); + // no need to check for critical statements, if + // the variable has been initialized with null + if (!hasNullInitializer(var) && parentBlock.jjtGetParent() == tryBlock.jjtGetParent()) { + + List blocks = parentBlock.jjtGetParent().findChildrenOfType(ASTBlockStatement.class); + int parentBlockIndex = blocks.indexOf(parentBlock); + int tryBlockIndex = blocks.indexOf(tryBlock); + boolean criticalStatements = false; + + for (int i = parentBlockIndex + 1; i < tryBlockIndex; i++) { + // assume variable declarations are not critical + ASTLocalVariableDeclaration varDecl = blocks.get(i) + .getFirstDescendantOfType(ASTLocalVariableDeclaration.class); + if (varDecl == null) { + criticalStatements = true; + break; + } + } + if (criticalStatements) { + break; + } + } + + if (t.getBeginLine() > id.getBeginLine() && t.hasFinally()) { + ASTBlock f = (ASTBlock) t.getFinally().jjtGetChild(0); + List names = f.findDescendantsOfType(ASTName.class); + for (ASTName oName : names) { + String name = oName.getImage(); + if (name != null && name.contains(".")) { + String[] parts = name.split("\\."); + if (parts.length == 2) { + String methodName = parts[1]; + String varName = parts[0]; + if (varName.equals(variableToClose) && closeTargets.contains(methodName) + && nullCheckIfCondition(f, oName, varName)) { + closed = true; + break; + } + + } + } + } + if (closed) { + break; + } + + List exprs = new ArrayList<>(); + f.findDescendantsOfType(ASTStatementExpression.class, exprs, true); + for (ASTStatementExpression stmt : exprs) { + ASTPrimaryExpression expr = stmt.getFirstChildOfType(ASTPrimaryExpression.class); + if (expr != null) { + ASTPrimaryPrefix prefix = expr.getFirstChildOfType(ASTPrimaryPrefix.class); + ASTPrimarySuffix suffix = expr.getFirstChildOfType(ASTPrimarySuffix.class); + if (prefix != null && suffix != null) { + if (prefix.getImage() == null) { + ASTName prefixName = prefix.getFirstChildOfType(ASTName.class); + if (prefixName != null && closeTargets.contains(prefixName.getImage())) { + // Found a call to a "close target" that is + // a direct + // method call without a "ClassName." + // prefix. + closed = variableIsPassedToMethod(expr, variableToClose); + if (closed) { + break; + } + } + } else if (suffix.getImage() != null) { + String prefixPlusSuffix = prefix.getImage() + "." + suffix.getImage(); + if (closeTargets.contains(prefixPlusSuffix)) { + // Found a call to a "close target" that is + // a method call + // in the form "ClassName.methodName". + closed = variableIsPassedToMethod(expr, variableToClose); + if (closed) { + break; + } + } + } + // look for primary suffix containing the close + // Targets elements. + // If the .close is executed in another class + // accessed by a method + // this form : + // getProviderInstance().closeConnexion(connexion) + // For this use case, we assume the variable is + // correctly closed + // in the other class since there is no way to + // really check it. + if (!closed) { + List suffixes = new ArrayList<>(); + expr.findDescendantsOfType(ASTPrimarySuffix.class, suffixes, true); + for (ASTPrimarySuffix oSuffix : suffixes) { + String suff = oSuffix.getImage(); + if (closeTargets.contains(suff)) { + closed = variableIsPassedToMethod(expr, variableToClose); + if (closed) { + break; + } + } + + } + } + } + } + } + if (closed) { + break; + } + } + } + + if (!closed) { + // See if the variable is returned by the method, which means the + // method is a utility for creating the db resource, which means of + // course it can't be closed by the method, so it isn't an error. + List returns = new ArrayList<>(); + top.findDescendantsOfType(ASTReturnStatement.class, returns, true); + for (ASTReturnStatement returnStatement : returns) { + ASTName name = returnStatement.getFirstDescendantOfType(ASTName.class); + if (name != null && name.getImage().equals(variableToClose)) { + closed = true; + break; + } + } + } + + // if all is not well, complain + if (!closed) { + ASTType type = var.getFirstChildOfType(ASTType.class); + ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0); + ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); + addViolation(data, id, clazz.getImage()); + } + } + + private boolean variableIsPassedToMethod(ASTPrimaryExpression expr, String variable) { + List methodParams = new ArrayList<>(); + expr.findDescendantsOfType(ASTName.class, methodParams, true); + for (ASTName pName : methodParams) { + String paramName = pName.getImage(); + // also check if we've got the a parameter (i.e if it's an argument + // !) + ASTArgumentList parentParam = pName.getFirstParentOfType(ASTArgumentList.class); + if (paramName.equals(variable) && parentParam != null) { + return true; + } + } + return false; + } + + private ASTIfStatement findIfStatement(ASTBlock enclosingBlock, Node node) { + ASTIfStatement ifStatement = node.getFirstParentOfType(ASTIfStatement.class); + List allIfStatements = enclosingBlock.findDescendantsOfType(ASTIfStatement.class); + if (ifStatement != null && allIfStatements.contains(ifStatement)) { + return ifStatement; + } + return null; + } + + /** + * Checks, whether the given node is inside a if condition, and if so, + * whether this is a null check for the given varName. + * + * @param enclosingBlock + * where to search for if statements + * @param node + * the node, where the call for the close is done + * @param varName + * the variable, that is maybe null-checked + * @return true if no if condition is involved or if the if + * condition is a null-check. + */ + private boolean nullCheckIfCondition(ASTBlock enclosingBlock, Node node, String varName) { + ASTIfStatement ifStatement = findIfStatement(enclosingBlock, node); + if (ifStatement != null) { + try { + // find expressions like: varName != null or null != varName + List nodes = ifStatement.findChildNodesWithXPath("Expression/EqualityExpression[@Image='!=']" + + " [PrimaryExpression/PrimaryPrefix/Name[@Image='" + varName + "']]" + + " [PrimaryExpression/PrimaryPrefix/Literal/NullLiteral]"); + return !nodes.isEmpty(); + } catch (JaxenException e) { + // no boolean literals or other condition + } + } + return true; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ConstructorCallsOverridableMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ConstructorCallsOverridableMethodRule.java index 4cc0f5207f..465ca59a25 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ConstructorCallsOverridableMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ConstructorCallsOverridableMethodRule.java @@ -1,1080 +1,1080 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; -import net.sourceforge.pmd.lang.java.ast.ASTArguments; -import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTExplicitConstructorInvocation; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; -import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.AccessNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -/** - * Searches through all methods and constructors called from constructors. It - * marks as dangerous any call to overridable methods from non-private - * constructors. It marks as dangerous any calls to dangerous private - * constructors from non-private constructors. - * - * @author CL Gilbert (dnoyeb@users.sourceforge.net) - * - * TODO match parameter types. Aggressively strips off any package - * names. Normal compares the names as is. TODO What about interface - * declarations which can have internal classes - */ -public final class ConstructorCallsOverridableMethodRule extends AbstractJavaRule { - /** - * 2: method(); - * ASTPrimaryPrefix - * ASTName image = "method" - * ASTPrimarySuffix - * *ASTArguments - * 3: a.method(); - * ASTPrimaryPrefix -> - * ASTName image = "a.method" ??? - * ASTPrimarySuffix -> () - * ASTArguments - * 3: this.method(); - * ASTPrimaryPrefix -> this image=null - * ASTPrimarySuffix -> method - * ASTPrimarySuffix -> () - * ASTArguments - *

- * super.method(); - * ASTPrimaryPrefix -> image = "method" - * ASTPrimarySuffix -> image = null - * ASTArguments -> - *

- * super.a.method(); - * ASTPrimaryPrefix -> image = "a" - * ASTPrimarySuffix -> image = "method" - * ASTPrimarySuffix -> image = null - * ASTArguments -> - *

- *

- * 4: this.a.method(); - * ASTPrimaryPrefix -> image = null - * ASTPrimarySuffix -> image = "a" - * ASTPrimarySuffix -> image = "method" - * ASTPrimarySuffix -> - * ASTArguments - *

- * 4: ClassName.this.method(); - * ASTPrimaryPrefix - * ASTName image = "ClassName" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> image = "method" - * ASTPrimarySuffix -> () - * ASTArguments - * 5: ClassName.this.a.method(); - * ASTPrimaryPrefix - * ASTName image = "ClassName" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> image="a" - * ASTPrimarySuffix -> image="method" - * ASTPrimarySuffix -> () - * ASTArguments - * 5: Package.ClassName.this.method(); - * ASTPrimaryPrefix - * ASTName image ="Package.ClassName" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> image="method" - * ASTPrimarySuffix -> () - * ASTArguments - * 6: Package.ClassName.this.a.method(); - * ASTPrimaryPrefix - * ASTName image ="Package.ClassName" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> a - * ASTPrimarySuffix -> method - * ASTPrimarySuffix -> () - * ASTArguments - * 5: OuterClass.InnerClass.this.method(); - * ASTPrimaryPrefix - * ASTName image = "OuterClass.InnerClass" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> method - * ASTPrimarySuffix -> () - * ASTArguments - * 6: OuterClass.InnerClass.this.a.method(); - * ASTPrimaryPrefix - * ASTName image = "OuterClass.InnerClass" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> a - * ASTPrimarySuffix -> method - * ASTPrimarySuffix -> () - * ASTArguments - *

- * OuterClass.InnerClass.this.a.method().method().method(); - * ASTPrimaryPrefix - * ASTName image = "OuterClass.InnerClass" - * ASTPrimarySuffix -> this image=null - * ASTPrimarySuffix -> a image='a' - * ASTPrimarySuffix -> method image='method' - * ASTPrimarySuffix -> () image=null - * ASTArguments - * ASTPrimarySuffix -> method image='method' - * ASTPrimarySuffix -> () image=null - * ASTArguments - * ASTPrimarySuffix -> method image='method' - * ASTPrimarySuffix -> () image=null - * ASTArguments - *

- * 3..n: Class.InnerClass[0].InnerClass[n].this.method(); - * ASTPrimaryPrefix - * ASTName image = "Class[0]..InnerClass[n]" - * ASTPrimarySuffix -> image=null - * ASTPrimarySuffix -> method - * ASTPrimarySuffix -> () - * ASTArguments - *

- * super.aMethod(); - * ASTPrimaryPrefix -> aMethod - * ASTPrimarySuffix -> () - *

- * Evaluate right to left - */ - - private static final NullEvalPackage NULL_EVAL_PACKAGE = new NullEvalPackage(); - - /** - * 1 package per class. - */ - // could use java.util.Stack - private final List evalPackages = new ArrayList<>(); - - private static class MethodInvocation { - private String name; - private ASTPrimaryExpression ape; - private List referenceNames; - private List qualifierNames; - private int argumentSize; - private List argumentTypes; - private boolean superCall; - - private MethodInvocation(ASTPrimaryExpression ape, List qualifierNames, List referenceNames, - String name, int argumentSize, List argumentTypes, boolean superCall) { - this.ape = ape; - this.qualifierNames = qualifierNames; - this.referenceNames = referenceNames; - this.name = name; - this.argumentSize = argumentSize; - this.argumentTypes = argumentTypes; - this.superCall = superCall; - } - - public boolean isSuper() { - return superCall; - } - - public String getName() { - return name; - } - - public int getArgumentCount() { - return argumentSize; - } - - public List getArgumentTypes() { - return argumentTypes; - } - - public List getReferenceNames() { - return referenceNames; // new ArrayList(variableNames); - } - - public List getQualifierNames() { - return qualifierNames; - } - - public ASTPrimaryExpression getASTPrimaryExpression() { - return ape; - } - - public static MethodInvocation getMethod(ASTPrimaryExpression node) { - MethodInvocation meth = null; - int i = node.jjtGetNumChildren(); - if (i > 1) { - // should always be at least 2, probably can eliminate this check - // start at end which is guaranteed, work backwards - Node lastNode = node.jjtGetChild(i - 1); - // could be ASTExpression for instance 'a[4] = 5'; - if (lastNode.jjtGetNumChildren() == 1 && lastNode.jjtGetChild(0) instanceof ASTArguments) { - // start putting method together - // System.out.println("Putting method together now"); - List varNames = new ArrayList<>(); - // look in JLS for better name here - List packagesAndClasses = new ArrayList<>(); - String methodName = null; - ASTArguments args = (ASTArguments) lastNode.jjtGetChild(0); - int numOfArguments = args.getArgumentCount(); - List argumentTypes = ConstructorCallsOverridableMethodRule.getArgumentTypes(args); - boolean superFirst = false; - int thisIndex = -1; - - FIND_SUPER_OR_THIS: { - // search all nodes except last for 'this' or 'super'. - // will be at: (node 0 | node 1 | nowhere) - // this is an ASTPrimarySuffix with a null image and - // does not have child (which will be of type - // ASTArguments) - // this is an ASTPrimaryPrefix with a null image and an - // ASTName that has a null image - // super is an ASTPrimarySuffix with a null image and - // does not have child (which will be of type - // ASTArguments) - // super is an ASTPrimaryPrefix with a non-null image - for (int x = 0; x < i - 1; x++) { - Node child = node.jjtGetChild(x); - // check suffix type match - if (child instanceof ASTPrimarySuffix) { - ASTPrimarySuffix child2 = (ASTPrimarySuffix) child; - // String name = - // getNameFromSuffix((ASTPrimarySuffix)child); - // System.out.println("found name suffix of : " - // + name); - if (child2.getImage() == null && child2.jjtGetNumChildren() == 0) { - thisIndex = x; - break; - } - // could be super, could be this. currently we - // cant tell difference so we miss super when - // XYZ.ClassName.super.method(); - // still works though. - } else if (child instanceof ASTPrimaryPrefix) { - // check prefix type match - ASTPrimaryPrefix child2 = (ASTPrimaryPrefix) child; - if (getNameFromPrefix(child2) == null) { - if (child2.getImage() == null) { - thisIndex = x; - break; - } else { - // happens when super is used - // [super.method(): image = 'method'] - superFirst = true; - thisIndex = x; - // the true super is at an unusable - // index because super.method() has only - // 2 nodes [method=0,()=1] - // as opposed to the 3 you might expect - // and which this.method() actually has. - // [this=0,method=1.()=2] - break; - } - } - } - // else{ - // System.err.println("Bad Format error"); //throw - // exception, quit evaluating this compilation node - // } - } - } - - if (thisIndex != -1) { - // System.out.println("Found this or super: " + - // thisIndex); - // Hack that must be removed if and when the patters of - // super.method() begins to logically match the rest of - // the patterns !!! - if (superFirst) { - // this is when super is the first - // node of statement. no qualifiers, - // all variables or method - // System.out.println("super first"); - FIRSTNODE: { - ASTPrimaryPrefix child = (ASTPrimaryPrefix) node.jjtGetChild(0); - String name = child.getImage(); // special case - if (i == 2) { // last named node = method name - methodName = name; - } else { - // not the last named node so its only - // var name - varNames.add(name); - } - } - OTHERNODES: { // variables - for (int x = 1; x < i - 1; x++) { - Node child = node.jjtGetChild(x); - ASTPrimarySuffix ps = (ASTPrimarySuffix) child; - if (!ps.isArguments()) { - String name = ((ASTPrimarySuffix) child).getImage(); - if (x == i - 2) { // last node - methodName = name; - } else { - // not the last named node so - // its only var name - varNames.add(name); - } - } - } - } - } else { - // not super call - FIRSTNODE: { - if (thisIndex == 1) { // qualifiers in node 0 - ASTPrimaryPrefix child = (ASTPrimaryPrefix) node.jjtGetChild(0); - String toParse = getNameFromPrefix(child); - // System.out.println("parsing for - // class/package names in : " + toParse); - java.util.StringTokenizer st = new java.util.StringTokenizer(toParse, "."); - while (st.hasMoreTokens()) { - packagesAndClasses.add(st.nextToken()); - } - } - } - OTHERNODES: { - // other methods called in this - // statement are grabbed here - // this is at 0, then no Qualifiers - // this is at 1, the node 0 contains qualifiers - for (int x = thisIndex + 1; x < i - 1; x++) { - // everything after this is var name or method name - ASTPrimarySuffix child = (ASTPrimarySuffix) node.jjtGetChild(x); - if (!child.isArguments()) { - // skip the () of method calls - String name = child.getImage(); - // System.out.println("Found suffix: " + - // suffixName); - if (x == i - 2) { - methodName = name; - } else { - varNames.add(name); - } - } - } - } - } - } else { - // if no this or super found, everything is method - // name or variable - // System.out.println("no this found:"); - FIRSTNODE: { - // variable names are in the prefix + the - // first method call [a.b.c.x()] - ASTPrimaryPrefix child = (ASTPrimaryPrefix) node.jjtGetChild(0); - String toParse = getNameFromPrefix(child); - // System.out.println("parsing for var names in : " - // + toParse); - java.util.StringTokenizer st = new java.util.StringTokenizer(toParse, "."); - while (st.hasMoreTokens()) { - String value = st.nextToken(); - if (!st.hasMoreTokens()) { - if (i == 2) { - // if this expression is 2 - // nodes long, then the last - // part of prefix is method - // name - methodName = value; - } else { - varNames.add(value); - } - } else { // variable name - varNames.add(value); - } - } - } - OTHERNODES: { - // other methods called in this statement - // are grabbed here - for (int x = 1; x < i - 1; x++) { - ASTPrimarySuffix child = (ASTPrimarySuffix) node.jjtGetChild(x); - if (!child.isArguments()) { - String name = child.getImage(); - if (x == i - 2) { - methodName = name; - } else { - varNames.add(name); - } - } - } - } - } - meth = new MethodInvocation(node, packagesAndClasses, varNames, methodName, numOfArguments, - argumentTypes, superFirst); - // meth.show(); - } - } - return meth; - } - - public void show() { - System.out.println(""); - System.out.println(" "); - for (String name : getQualifierNames()) { - System.out.println(" " + name); - } - System.out.println(" "); - System.out.println(" " + isSuper() + ""); - System.out.println(" "); - for (String name : getReferenceNames()) { - System.out.println(" " + name); - } - System.out.println(" "); - System.out.println(" " + getName() + ""); - System.out.println(" " + getArgumentCount() + ""); - System.out.println(" " + getArgumentTypes() + ""); - System.out.println(""); - } - } - - private static final class ConstructorInvocation { - private ASTExplicitConstructorInvocation eci; - private String name; - private int count = 0; - private List argumentTypes = new ArrayList<>(); - - ConstructorInvocation(ASTExplicitConstructorInvocation eci) { - this.eci = eci; - List l = eci.findChildrenOfType(ASTArguments.class); - if (!l.isEmpty()) { - ASTArguments aa = l.get(0); - count = aa.getArgumentCount(); - argumentTypes = ConstructorCallsOverridableMethodRule.getArgumentTypes(aa); - } - name = eci.getImage(); - } - - public ASTExplicitConstructorInvocation getASTExplicitConstructorInvocation() { - return eci; - } - - public int getArgumentCount() { - return count; - } - - public List getArgumentTypes() { - return argumentTypes; - } - - public String getName() { - return name; - } - } - - private static final class MethodHolder { - private ASTMethodDeclarator amd; - private boolean dangerous; - private String called; - - MethodHolder(ASTMethodDeclarator amd) { - this.amd = amd; - } - - public void setCalledMethod(String name) { - this.called = name; - } - - public String getCalled() { - return this.called; - } - - public ASTMethodDeclarator getASTMethodDeclarator() { - return amd; - } - - public boolean isDangerous() { - return dangerous; - } - - public void setDangerous() { - dangerous = true; - } - } - - private static final class ConstructorHolder { - private ASTConstructorDeclaration cd; - private boolean dangerous; - private ConstructorInvocation ci; - private boolean ciInitialized; - - ConstructorHolder(ASTConstructorDeclaration cd) { - this.cd = cd; - } - - public ASTConstructorDeclaration getASTConstructorDeclaration() { - return cd; - } - - public ConstructorInvocation getCalledConstructor() { - if (!ciInitialized) { - initCI(); - } - return ci; - } - - public ASTExplicitConstructorInvocation getASTExplicitConstructorInvocation() { - ASTExplicitConstructorInvocation eci = null; - if (!ciInitialized) { - initCI(); - } - if (ci != null) { - eci = ci.getASTExplicitConstructorInvocation(); - } - return eci; - } - - private void initCI() { - // only 1... - List expressions = cd - .findChildrenOfType(ASTExplicitConstructorInvocation.class); - if (!expressions.isEmpty()) { - ASTExplicitConstructorInvocation eci = expressions.get(0); - ci = new ConstructorInvocation(eci); - // System.out.println("Const call " + eci.getImage()); //super - // or this??? - } - ciInitialized = true; - } - - public boolean isDangerous() { - return dangerous; - } - - public void setDangerous(boolean dangerous) { - this.dangerous = dangerous; - } - } - - private static int compareNodes(Node n1, Node n2) { - int l1 = n1.getBeginLine(); - int l2 = n2.getBeginLine(); - if (l1 == l2) { - return n1.getBeginColumn() - n2.getBeginColumn(); - } - return l1 - l2; - } - - private static class MethodHolderComparator implements Comparator { - @Override - public int compare(MethodHolder o1, MethodHolder o2) { - return compareNodes(o1.getASTMethodDeclarator(), o2.getASTMethodDeclarator()); - } - } - - private static class ConstructorHolderComparator implements Comparator { - @Override - public int compare(ConstructorHolder o1, ConstructorHolder o2) { - return compareNodes(o1.getASTConstructorDeclaration(), o2.getASTConstructorDeclaration()); - } - } - - /** - * 1 package per class. holds info for evaluating a single class. - */ - private static class EvalPackage { - - public String className; - public List calledMethods; - public Map> allMethodsOfClass; - - public List calledConstructors; - public Map> allPrivateConstructorsOfClass; - - EvalPackage() { - } - - EvalPackage(String className) { - this.className = className; - // meths called from constructor - this.calledMethods = new ArrayList<>(); - this.allMethodsOfClass = new TreeMap<>(new MethodHolderComparator()); - // all constructors called from constructor - this.calledConstructors = new ArrayList<>(); - this.allPrivateConstructorsOfClass = new TreeMap<>(new ConstructorHolderComparator()); - } - - } - - private static final class NullEvalPackage extends EvalPackage { - NullEvalPackage() { - className = ""; - calledMethods = Collections.emptyList(); - allMethodsOfClass = Collections.emptyMap(); - calledConstructors = Collections.emptyList(); - allPrivateConstructorsOfClass = Collections.emptyMap(); - } - } - - private EvalPackage getCurrentEvalPackage() { - return evalPackages.get(evalPackages.size() - 1); - } - - /** - * Adds and evaluation package and makes it current - */ - private void putEvalPackage(EvalPackage ep) { - evalPackages.add(ep); - } - - private void removeCurrentEvalPackage() { - evalPackages.remove(evalPackages.size() - 1); - } - - private void clearEvalPackages() { - evalPackages.clear(); - } - - /** - * This check must be evaluated independently for each class. Inner classes - * get their own EvalPackage in order to perform independent evaluation. - */ - private Object visitClassDec(ASTClassOrInterfaceDeclaration node, Object data) { - String className = node.getImage(); - if (!node.isFinal()) { - putEvalPackage(new EvalPackage(className)); - } else { - putEvalPackage(NULL_EVAL_PACKAGE); - } - // store any errors caught from other passes. - super.visit(node, data); - - // skip this class if it has no evaluation package - if (!(getCurrentEvalPackage() instanceof NullEvalPackage)) { - // evaluate danger of all methods in class, this method will return - // false when all methods have been evaluated - while (evaluateDangerOfMethods(getCurrentEvalPackage().allMethodsOfClass)) { - } // NOPMD - - // evaluate danger of constructors - evaluateDangerOfConstructors1(getCurrentEvalPackage().allPrivateConstructorsOfClass, - getCurrentEvalPackage().allMethodsOfClass.keySet()); - while (evaluateDangerOfConstructors2(getCurrentEvalPackage().allPrivateConstructorsOfClass)) { - } // NOPMD - - // get each method called on this object from a non-private - // constructor, if its dangerous flag it - for (MethodInvocation meth : getCurrentEvalPackage().calledMethods) { - // check against each dangerous method in class - for (MethodHolder h : getCurrentEvalPackage().allMethodsOfClass.keySet()) { - if (h.isDangerous()) { - String methName = h.getASTMethodDeclarator().getImage(); - int count = h.getASTMethodDeclarator().getParameterCount(); - List parameterTypes = getMethodDeclaratorParameterTypes(h.getASTMethodDeclarator()); - if (methName.equals(meth.getName()) && meth.getArgumentCount() == count - && parameterTypes.equals(meth.getArgumentTypes())) { - addViolation(data, meth.getASTPrimaryExpression(), "method '" + h.getCalled() + "'"); - } - } - } - } - // get each unsafe private constructor, and check if its called from - // any non private constructors - for (ConstructorHolder ch : getCurrentEvalPackage().allPrivateConstructorsOfClass.keySet()) { - if (ch.isDangerous()) { - // if its dangerous check if its called - // from any non-private constructors - // System.out.println("visitClassDec Evaluating dangerous - // constructor with " + - // ch.getASTConstructorDeclaration().getParameterCount() + " - // params"); - int paramCount = ch.getASTConstructorDeclaration().getParameterCount(); - for (ConstructorInvocation ci : getCurrentEvalPackage().calledConstructors) { - if (ci.getArgumentCount() == paramCount) { - // match name super / this !? - addViolation(data, ci.getASTExplicitConstructorInvocation(), "constructor"); - } - } - } - } - } - // finished evaluating this class, move up a level - removeCurrentEvalPackage(); - return data; - } - - /** - * Check the methods called on this class by each of the methods on this - * class. If a method calls an unsafe method, mark the calling method as - * unsafe. This changes the list of unsafe methods which necessitates - * another pass. Keep passing until you make a clean pass in which no - * methods are changed to unsafe. For speed it is possible to limit the - * number of passes. - *

- * Impossible to tell type of arguments to method, so forget method matching - * on types. just use name and num of arguments. will be some false hits, - * but oh well. - * - * TODO investigate limiting the number of passes through config. - */ - private boolean evaluateDangerOfMethods(Map> classMethodMap) { - // check each method if it calls overridable method - boolean found = false; - for (Map.Entry> entry : classMethodMap.entrySet()) { - MethodHolder h = entry.getKey(); - List calledMeths = entry.getValue(); - for (Iterator calledMethsIter = calledMeths.iterator(); calledMethsIter.hasNext() - && !h.isDangerous();) { - // if this method matches one of our dangerous methods, mark it - // dangerous - MethodInvocation meth = calledMethsIter.next(); - // System.out.println("Called meth is " + meth); - for (MethodHolder h3 : classMethodMap.keySet()) { - // need to skip self here h == h3 - if (h3.isDangerous()) { - String matchMethodName = h3.getASTMethodDeclarator().getImage(); - int matchMethodParamCount = h3.getASTMethodDeclarator().getParameterCount(); - List parameterTypes = getMethodDeclaratorParameterTypes(h3.getASTMethodDeclarator()); - // System.out.println("matching " + matchMethodName + " - // to " + meth.getName()); - if (matchMethodName.equals(meth.getName()) && matchMethodParamCount == meth.getArgumentCount() - && parameterTypes.equals(meth.getArgumentTypes())) { - h.setDangerous(); - h.setCalledMethod(matchMethodName); - found = true; - break; - } - } - } - } - } - return found; - } - - /** - * marks constructors dangerous if they call any dangerous methods Requires - * only a single pass as methods are already marked - * - * TODO optimize by having methods already evaluated somehow!? - */ - private void evaluateDangerOfConstructors1(Map> classConstructorMap, - Set evaluatedMethods) { - // check each constructor in the class - for (Map.Entry> entry : classConstructorMap.entrySet()) { - ConstructorHolder ch = entry.getKey(); - if (!ch.isDangerous()) { - // if its not dangerous then evaluate if it - // should be - // if it calls dangerous method mark it as dangerous - List calledMeths = entry.getValue(); - // check each method it calls - for (Iterator calledMethsIter = calledMeths.iterator(); calledMethsIter.hasNext() - && !ch.isDangerous();) { - // but thee are diff objects - // which represent same thing - // but were never evaluated, - // they need reevaluation - MethodInvocation meth = calledMethsIter.next(); // CCE - String methName = meth.getName(); - int methArgCount = meth.getArgumentCount(); - // check each of the already evaluated methods: need to - // optimize this out - for (MethodHolder h : evaluatedMethods) { - if (h.isDangerous()) { - String matchName = h.getASTMethodDeclarator().getImage(); - int matchParamCount = h.getASTMethodDeclarator().getParameterCount(); - List parameterTypes = getMethodDeclaratorParameterTypes(h.getASTMethodDeclarator()); - if (methName.equals(matchName) && methArgCount == matchParamCount - && parameterTypes.equals(meth.getArgumentTypes())) { - ch.setDangerous(true); - // System.out.println("evaluateDangerOfConstructors1 - // setting dangerous constructor with " + - // ch.getASTConstructorDeclaration().getParameterCount() - // + " params"); - break; - } - } - } - } - } - } - } - - /** - * Constructor map should contain a key for each private constructor, and - * maps to a List which contains all called constructors of that key. marks - * dangerous if call dangerous private constructor we ignore all non-private - * constructors here. That is, the map passed in should not contain any - * non-private constructors. we return boolean in order to limit the number - * of passes through this method but it seems as if we can forgo that and - * just process it till its done. - */ - private boolean evaluateDangerOfConstructors2(Map> classConstructorMap) { - boolean found = false; // triggers on danger state change - // check each constructor in the class - for (ConstructorHolder ch : classConstructorMap.keySet()) { - ConstructorInvocation calledC = ch.getCalledConstructor(); - if (calledC == null || ch.isDangerous()) { - continue; - } - // if its not dangerous then evaluate if it should be - // if it calls dangerous constructor mark it as dangerous - int cCount = calledC.getArgumentCount(); - for (Iterator innerConstIter = classConstructorMap.keySet().iterator(); innerConstIter - .hasNext() && !ch.isDangerous();) { - // forget skipping self because that introduces another - // check for each, but only 1 hit - ConstructorHolder h2 = innerConstIter.next(); - if (h2.isDangerous()) { - int matchConstArgCount = h2.getASTConstructorDeclaration().getParameterCount(); - List parameterTypes = getMethodDeclaratorParameterTypes(h2.getASTConstructorDeclaration()); - if (matchConstArgCount == cCount && parameterTypes.equals(calledC.getArgumentTypes())) { - ch.setDangerous(true); - found = true; - // System.out.println("evaluateDangerOfConstructors2 - // setting dangerous constructor with " + - // ch.getASTConstructorDeclaration().getParameterCount() - // + " params"); - } - } - } - } - return found; - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - clearEvalPackages(); - return super.visit(node, data); - } - - @Override - public Object visit(ASTEnumDeclaration node, Object data) { - // just skip Enums - return data; - } - - /** - * This check must be evaluated independently for each class. Inner classes - * get their own EvalPackage in order to perform independent evaluation. - */ - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (!node.isInterface()) { - return visitClassDec(node, data); - } else { - putEvalPackage(NULL_EVAL_PACKAGE); - // interface may have inner - // classes, possible? if not just - // skip whole interface - Object o = super.visit(node, data); - removeCurrentEvalPackage(); - return o; - } - } - - /** - * Non-private constructor's methods are added to a list for later safety - * evaluation. Non-private constructor's calls on private constructors are - * added to a list for later safety evaluation. Private constructors are - * added to a list so their safety to be called can be later evaluated. - * - *

Note: We are not checking private constructor's calls on non-private - * constructors because all non-private constructors will be evaluated for - * safety anyway. This means we wont flag a private constructor as unsafe - * just because it calls an unsafe public constructor. We want to show only - * 1 instance of an error, and this would be 2 instances of the same error.

- * - *

TODO eliminate the redundancy

- */ - @Override - public Object visit(ASTConstructorDeclaration node, Object data) { - if (!(getCurrentEvalPackage() instanceof NullEvalPackage)) { - // only evaluate if we have an eval package for this class - List calledMethodsOfConstructor = new ArrayList<>(); - ConstructorHolder ch = new ConstructorHolder(node); - addCalledMethodsOfNode(node, calledMethodsOfConstructor, getCurrentEvalPackage().className); - if (!node.isPrivate()) { - // these calledMethods are what we will evaluate for being - // called badly - getCurrentEvalPackage().calledMethods.addAll(calledMethodsOfConstructor); - // these called private constructors are what we will evaluate - // for being called badly - // we add all constructors invoked by non-private constructors - // but we are only interested in the private ones. We just can't - // tell the difference here - ASTExplicitConstructorInvocation eci = ch.getASTExplicitConstructorInvocation(); - if (eci != null && eci.isThis()) { - getCurrentEvalPackage().calledConstructors.add(ch.getCalledConstructor()); - } - } else { - // add all private constructors to list for later evaluation on - // if they are safe to call from another constructor - // store this constructorHolder for later evaluation - getCurrentEvalPackage().allPrivateConstructorsOfClass.put(ch, calledMethodsOfConstructor); - } - } - return super.visit(node, data); - } - - /** - * Create a MethodHolder to hold the method. Store the MethodHolder in the - * Map as the key Store each method called by the current method as a List - * in the Map as the Object - */ - @Override - public Object visit(ASTMethodDeclarator node, Object data) { - if (!(getCurrentEvalPackage() instanceof NullEvalPackage)) { - // only evaluate if we have an eval package for this class - AccessNode parent = (AccessNode) node.jjtGetParent(); - MethodHolder h = new MethodHolder(node); - if (!parent.isAbstract() && !parent.isPrivate() && !parent.isStatic() && !parent.isFinal()) { - // Skip abstract methods, have a separate rule for that - h.setDangerous(); // this method is overridable - ASTMethodDeclaration decl = node.getFirstParentOfType(ASTMethodDeclaration.class); - h.setCalledMethod(decl.getMethodName()); - } - List l = new ArrayList<>(); - addCalledMethodsOfNode(parent, l, getCurrentEvalPackage().className); - getCurrentEvalPackage().allMethodsOfClass.put(h, l); - } - return super.visit(node, data); - } - - /** - * Adds all methods called on this instance from within this Node. - */ - private static void addCalledMethodsOfNode(Node node, List calledMethods, String className) { - List expressions = new ArrayList<>(); - node.findDescendantsOfType(ASTPrimaryExpression.class, expressions, !(node instanceof AccessNode)); - addCalledMethodsOfNodeImpl(expressions, calledMethods, className); - } - - private static void addCalledMethodsOfNodeImpl(List expressions, - List calledMethods, String className) { - for (ASTPrimaryExpression ape : expressions) { - MethodInvocation meth = findMethod(ape, className); - if (meth != null) { - // System.out.println("Adding call " + methName); - calledMethods.add(meth); - } - } - } - - /** - * @return A method call on the class passed in, or null if no method call - * is found. TODO Need a better way to match the class and package - * name to the actual method being called. - */ - private static MethodInvocation findMethod(ASTPrimaryExpression node, String className) { - if (node.jjtGetNumChildren() > 0 && node.jjtGetChild(0).jjtGetNumChildren() > 0 - && node.jjtGetChild(0).jjtGetChild(0) instanceof ASTLiteral) { - return null; - } - MethodInvocation meth = MethodInvocation.getMethod(node); - boolean found = false; - // if(meth != null){ - // meth.show(); - // } - if (meth != null) { - // if it's a call on a variable, or on its superclass ignore it. - if (meth.getReferenceNames().isEmpty() && !meth.isSuper()) { - // if this list does not contain our class name, then its not - // referencing our class - // this is a cheezy test... but it errs on the side of less - // false hits. - List packClass = meth.getQualifierNames(); - if (!packClass.isEmpty()) { - for (String name : packClass) { - if (name.equals(className)) { - found = true; - break; - } - } - } else { - found = true; - } - } - } - - return found ? meth : null; - } - - /** - * ASTPrimaryPrefix has name in child node of ASTName - */ - private static String getNameFromPrefix(ASTPrimaryPrefix node) { - String name = null; - // should only be 1 child, if more I need more knowledge - if (node.jjtGetNumChildren() == 1) { // safety check - Node nnode = node.jjtGetChild(0); - if (nnode instanceof ASTName) { - // just as easy as null check and it - // should be an ASTName anyway - name = ((ASTName) nnode).getImage(); - } - } - return name; - } - - private static List getMethodDeclaratorParameterTypes(Node methodOrConstructorDeclarator) { - List parameters = methodOrConstructorDeclarator - .findDescendantsOfType(ASTFormalParameter.class); - List parameterTypes = new ArrayList<>(); - if (parameters != null) { - for (ASTFormalParameter p : parameters) { - ASTType type = p.getFirstChildOfType(ASTType.class); - if (type.jjtGetChild(0) instanceof ASTPrimitiveType) { - parameterTypes.add(type.jjtGetChild(0).getImage()); - } else if (type.jjtGetChild(0) instanceof ASTReferenceType) { - parameterTypes.add("ref"); - } else { - parameterTypes.add(""); - } - } - } - return parameterTypes; - } - - private static List getArgumentTypes(ASTArguments args) { - List argumentTypes = new ArrayList<>(); - ASTArgumentList argumentList = args.getFirstChildOfType(ASTArgumentList.class); - if (argumentList != null) { - for (int a = 0; a < argumentList.jjtGetNumChildren(); a++) { - Node expression = argumentList.jjtGetChild(a); - ASTPrimaryPrefix arg = expression.getFirstDescendantOfType(ASTPrimaryPrefix.class); - String type = ""; - if (arg != null && arg.jjtGetNumChildren() > 0) { - if (arg.jjtGetChild(0) instanceof ASTLiteral) { - ASTLiteral lit = (ASTLiteral) arg.jjtGetChild(0); - if (lit.isCharLiteral()) { - type = "char"; - } else if (lit.isFloatLiteral()) { - type = "float"; - } else if (lit.isIntLiteral()) { - type = "int"; - } else if (lit.isStringLiteral()) { - type = "String"; - } else if (lit.jjtGetNumChildren() > 0 && lit.jjtGetChild(0) instanceof ASTBooleanLiteral) { - type = "boolean"; - } else if (lit.isDoubleLiteral()) { - type = "double"; - } else if (lit.isLongLiteral()) { - type = "long"; - } - } else if (arg.jjtGetChild(0) instanceof ASTName) { - // ASTName n = (ASTName)arg.jjtGetChild(0); - type = "ref"; - } - } - argumentTypes.add(type); - } - } - return argumentTypes; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; +import net.sourceforge.pmd.lang.java.ast.ASTArguments; +import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTExplicitConstructorInvocation; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +/** + * Searches through all methods and constructors called from constructors. It + * marks as dangerous any call to overridable methods from non-private + * constructors. It marks as dangerous any calls to dangerous private + * constructors from non-private constructors. + * + * @author CL Gilbert (dnoyeb@users.sourceforge.net) + * + * TODO match parameter types. Aggressively strips off any package + * names. Normal compares the names as is. TODO What about interface + * declarations which can have internal classes + */ +public final class ConstructorCallsOverridableMethodRule extends AbstractJavaRule { + /** + * 2: method(); + * ASTPrimaryPrefix + * ASTName image = "method" + * ASTPrimarySuffix + * *ASTArguments + * 3: a.method(); + * ASTPrimaryPrefix -> + * ASTName image = "a.method" ??? + * ASTPrimarySuffix -> () + * ASTArguments + * 3: this.method(); + * ASTPrimaryPrefix -> this image=null + * ASTPrimarySuffix -> method + * ASTPrimarySuffix -> () + * ASTArguments + *

+ * super.method(); + * ASTPrimaryPrefix -> image = "method" + * ASTPrimarySuffix -> image = null + * ASTArguments -> + *

+ * super.a.method(); + * ASTPrimaryPrefix -> image = "a" + * ASTPrimarySuffix -> image = "method" + * ASTPrimarySuffix -> image = null + * ASTArguments -> + *

+ *

+ * 4: this.a.method(); + * ASTPrimaryPrefix -> image = null + * ASTPrimarySuffix -> image = "a" + * ASTPrimarySuffix -> image = "method" + * ASTPrimarySuffix -> + * ASTArguments + *

+ * 4: ClassName.this.method(); + * ASTPrimaryPrefix + * ASTName image = "ClassName" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> image = "method" + * ASTPrimarySuffix -> () + * ASTArguments + * 5: ClassName.this.a.method(); + * ASTPrimaryPrefix + * ASTName image = "ClassName" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> image="a" + * ASTPrimarySuffix -> image="method" + * ASTPrimarySuffix -> () + * ASTArguments + * 5: Package.ClassName.this.method(); + * ASTPrimaryPrefix + * ASTName image ="Package.ClassName" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> image="method" + * ASTPrimarySuffix -> () + * ASTArguments + * 6: Package.ClassName.this.a.method(); + * ASTPrimaryPrefix + * ASTName image ="Package.ClassName" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> a + * ASTPrimarySuffix -> method + * ASTPrimarySuffix -> () + * ASTArguments + * 5: OuterClass.InnerClass.this.method(); + * ASTPrimaryPrefix + * ASTName image = "OuterClass.InnerClass" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> method + * ASTPrimarySuffix -> () + * ASTArguments + * 6: OuterClass.InnerClass.this.a.method(); + * ASTPrimaryPrefix + * ASTName image = "OuterClass.InnerClass" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> a + * ASTPrimarySuffix -> method + * ASTPrimarySuffix -> () + * ASTArguments + *

+ * OuterClass.InnerClass.this.a.method().method().method(); + * ASTPrimaryPrefix + * ASTName image = "OuterClass.InnerClass" + * ASTPrimarySuffix -> this image=null + * ASTPrimarySuffix -> a image='a' + * ASTPrimarySuffix -> method image='method' + * ASTPrimarySuffix -> () image=null + * ASTArguments + * ASTPrimarySuffix -> method image='method' + * ASTPrimarySuffix -> () image=null + * ASTArguments + * ASTPrimarySuffix -> method image='method' + * ASTPrimarySuffix -> () image=null + * ASTArguments + *

+ * 3..n: Class.InnerClass[0].InnerClass[n].this.method(); + * ASTPrimaryPrefix + * ASTName image = "Class[0]..InnerClass[n]" + * ASTPrimarySuffix -> image=null + * ASTPrimarySuffix -> method + * ASTPrimarySuffix -> () + * ASTArguments + *

+ * super.aMethod(); + * ASTPrimaryPrefix -> aMethod + * ASTPrimarySuffix -> () + *

+ * Evaluate right to left + */ + + private static final NullEvalPackage NULL_EVAL_PACKAGE = new NullEvalPackage(); + + /** + * 1 package per class. + */ + // could use java.util.Stack + private final List evalPackages = new ArrayList<>(); + + private static class MethodInvocation { + private String name; + private ASTPrimaryExpression ape; + private List referenceNames; + private List qualifierNames; + private int argumentSize; + private List argumentTypes; + private boolean superCall; + + private MethodInvocation(ASTPrimaryExpression ape, List qualifierNames, List referenceNames, + String name, int argumentSize, List argumentTypes, boolean superCall) { + this.ape = ape; + this.qualifierNames = qualifierNames; + this.referenceNames = referenceNames; + this.name = name; + this.argumentSize = argumentSize; + this.argumentTypes = argumentTypes; + this.superCall = superCall; + } + + public boolean isSuper() { + return superCall; + } + + public String getName() { + return name; + } + + public int getArgumentCount() { + return argumentSize; + } + + public List getArgumentTypes() { + return argumentTypes; + } + + public List getReferenceNames() { + return referenceNames; // new ArrayList(variableNames); + } + + public List getQualifierNames() { + return qualifierNames; + } + + public ASTPrimaryExpression getASTPrimaryExpression() { + return ape; + } + + public static MethodInvocation getMethod(ASTPrimaryExpression node) { + MethodInvocation meth = null; + int i = node.jjtGetNumChildren(); + if (i > 1) { + // should always be at least 2, probably can eliminate this check + // start at end which is guaranteed, work backwards + Node lastNode = node.jjtGetChild(i - 1); + // could be ASTExpression for instance 'a[4] = 5'; + if (lastNode.jjtGetNumChildren() == 1 && lastNode.jjtGetChild(0) instanceof ASTArguments) { + // start putting method together + // System.out.println("Putting method together now"); + List varNames = new ArrayList<>(); + // look in JLS for better name here + List packagesAndClasses = new ArrayList<>(); + String methodName = null; + ASTArguments args = (ASTArguments) lastNode.jjtGetChild(0); + int numOfArguments = args.getArgumentCount(); + List argumentTypes = ConstructorCallsOverridableMethodRule.getArgumentTypes(args); + boolean superFirst = false; + int thisIndex = -1; + + FIND_SUPER_OR_THIS: { + // search all nodes except last for 'this' or 'super'. + // will be at: (node 0 | node 1 | nowhere) + // this is an ASTPrimarySuffix with a null image and + // does not have child (which will be of type + // ASTArguments) + // this is an ASTPrimaryPrefix with a null image and an + // ASTName that has a null image + // super is an ASTPrimarySuffix with a null image and + // does not have child (which will be of type + // ASTArguments) + // super is an ASTPrimaryPrefix with a non-null image + for (int x = 0; x < i - 1; x++) { + Node child = node.jjtGetChild(x); + // check suffix type match + if (child instanceof ASTPrimarySuffix) { + ASTPrimarySuffix child2 = (ASTPrimarySuffix) child; + // String name = + // getNameFromSuffix((ASTPrimarySuffix)child); + // System.out.println("found name suffix of : " + // + name); + if (child2.getImage() == null && child2.jjtGetNumChildren() == 0) { + thisIndex = x; + break; + } + // could be super, could be this. currently we + // cant tell difference so we miss super when + // XYZ.ClassName.super.method(); + // still works though. + } else if (child instanceof ASTPrimaryPrefix) { + // check prefix type match + ASTPrimaryPrefix child2 = (ASTPrimaryPrefix) child; + if (getNameFromPrefix(child2) == null) { + if (child2.getImage() == null) { + thisIndex = x; + break; + } else { + // happens when super is used + // [super.method(): image = 'method'] + superFirst = true; + thisIndex = x; + // the true super is at an unusable + // index because super.method() has only + // 2 nodes [method=0,()=1] + // as opposed to the 3 you might expect + // and which this.method() actually has. + // [this=0,method=1.()=2] + break; + } + } + } + // else{ + // System.err.println("Bad Format error"); //throw + // exception, quit evaluating this compilation node + // } + } + } + + if (thisIndex != -1) { + // System.out.println("Found this or super: " + + // thisIndex); + // Hack that must be removed if and when the patters of + // super.method() begins to logically match the rest of + // the patterns !!! + if (superFirst) { + // this is when super is the first + // node of statement. no qualifiers, + // all variables or method + // System.out.println("super first"); + FIRSTNODE: { + ASTPrimaryPrefix child = (ASTPrimaryPrefix) node.jjtGetChild(0); + String name = child.getImage(); // special case + if (i == 2) { // last named node = method name + methodName = name; + } else { + // not the last named node so its only + // var name + varNames.add(name); + } + } + OTHERNODES: { // variables + for (int x = 1; x < i - 1; x++) { + Node child = node.jjtGetChild(x); + ASTPrimarySuffix ps = (ASTPrimarySuffix) child; + if (!ps.isArguments()) { + String name = ((ASTPrimarySuffix) child).getImage(); + if (x == i - 2) { // last node + methodName = name; + } else { + // not the last named node so + // its only var name + varNames.add(name); + } + } + } + } + } else { + // not super call + FIRSTNODE: { + if (thisIndex == 1) { // qualifiers in node 0 + ASTPrimaryPrefix child = (ASTPrimaryPrefix) node.jjtGetChild(0); + String toParse = getNameFromPrefix(child); + // System.out.println("parsing for + // class/package names in : " + toParse); + java.util.StringTokenizer st = new java.util.StringTokenizer(toParse, "."); + while (st.hasMoreTokens()) { + packagesAndClasses.add(st.nextToken()); + } + } + } + OTHERNODES: { + // other methods called in this + // statement are grabbed here + // this is at 0, then no Qualifiers + // this is at 1, the node 0 contains qualifiers + for (int x = thisIndex + 1; x < i - 1; x++) { + // everything after this is var name or method name + ASTPrimarySuffix child = (ASTPrimarySuffix) node.jjtGetChild(x); + if (!child.isArguments()) { + // skip the () of method calls + String name = child.getImage(); + // System.out.println("Found suffix: " + + // suffixName); + if (x == i - 2) { + methodName = name; + } else { + varNames.add(name); + } + } + } + } + } + } else { + // if no this or super found, everything is method + // name or variable + // System.out.println("no this found:"); + FIRSTNODE: { + // variable names are in the prefix + the + // first method call [a.b.c.x()] + ASTPrimaryPrefix child = (ASTPrimaryPrefix) node.jjtGetChild(0); + String toParse = getNameFromPrefix(child); + // System.out.println("parsing for var names in : " + // + toParse); + java.util.StringTokenizer st = new java.util.StringTokenizer(toParse, "."); + while (st.hasMoreTokens()) { + String value = st.nextToken(); + if (!st.hasMoreTokens()) { + if (i == 2) { + // if this expression is 2 + // nodes long, then the last + // part of prefix is method + // name + methodName = value; + } else { + varNames.add(value); + } + } else { // variable name + varNames.add(value); + } + } + } + OTHERNODES: { + // other methods called in this statement + // are grabbed here + for (int x = 1; x < i - 1; x++) { + ASTPrimarySuffix child = (ASTPrimarySuffix) node.jjtGetChild(x); + if (!child.isArguments()) { + String name = child.getImage(); + if (x == i - 2) { + methodName = name; + } else { + varNames.add(name); + } + } + } + } + } + meth = new MethodInvocation(node, packagesAndClasses, varNames, methodName, numOfArguments, + argumentTypes, superFirst); + // meth.show(); + } + } + return meth; + } + + public void show() { + System.out.println(""); + System.out.println(" "); + for (String name : getQualifierNames()) { + System.out.println(" " + name); + } + System.out.println(" "); + System.out.println(" " + isSuper() + ""); + System.out.println(" "); + for (String name : getReferenceNames()) { + System.out.println(" " + name); + } + System.out.println(" "); + System.out.println(" " + getName() + ""); + System.out.println(" " + getArgumentCount() + ""); + System.out.println(" " + getArgumentTypes() + ""); + System.out.println(""); + } + } + + private static final class ConstructorInvocation { + private ASTExplicitConstructorInvocation eci; + private String name; + private int count = 0; + private List argumentTypes = new ArrayList<>(); + + ConstructorInvocation(ASTExplicitConstructorInvocation eci) { + this.eci = eci; + List l = eci.findChildrenOfType(ASTArguments.class); + if (!l.isEmpty()) { + ASTArguments aa = l.get(0); + count = aa.getArgumentCount(); + argumentTypes = ConstructorCallsOverridableMethodRule.getArgumentTypes(aa); + } + name = eci.getImage(); + } + + public ASTExplicitConstructorInvocation getASTExplicitConstructorInvocation() { + return eci; + } + + public int getArgumentCount() { + return count; + } + + public List getArgumentTypes() { + return argumentTypes; + } + + public String getName() { + return name; + } + } + + private static final class MethodHolder { + private ASTMethodDeclarator amd; + private boolean dangerous; + private String called; + + MethodHolder(ASTMethodDeclarator amd) { + this.amd = amd; + } + + public void setCalledMethod(String name) { + this.called = name; + } + + public String getCalled() { + return this.called; + } + + public ASTMethodDeclarator getASTMethodDeclarator() { + return amd; + } + + public boolean isDangerous() { + return dangerous; + } + + public void setDangerous() { + dangerous = true; + } + } + + private static final class ConstructorHolder { + private ASTConstructorDeclaration cd; + private boolean dangerous; + private ConstructorInvocation ci; + private boolean ciInitialized; + + ConstructorHolder(ASTConstructorDeclaration cd) { + this.cd = cd; + } + + public ASTConstructorDeclaration getASTConstructorDeclaration() { + return cd; + } + + public ConstructorInvocation getCalledConstructor() { + if (!ciInitialized) { + initCI(); + } + return ci; + } + + public ASTExplicitConstructorInvocation getASTExplicitConstructorInvocation() { + ASTExplicitConstructorInvocation eci = null; + if (!ciInitialized) { + initCI(); + } + if (ci != null) { + eci = ci.getASTExplicitConstructorInvocation(); + } + return eci; + } + + private void initCI() { + // only 1... + List expressions = cd + .findChildrenOfType(ASTExplicitConstructorInvocation.class); + if (!expressions.isEmpty()) { + ASTExplicitConstructorInvocation eci = expressions.get(0); + ci = new ConstructorInvocation(eci); + // System.out.println("Const call " + eci.getImage()); //super + // or this??? + } + ciInitialized = true; + } + + public boolean isDangerous() { + return dangerous; + } + + public void setDangerous(boolean dangerous) { + this.dangerous = dangerous; + } + } + + private static int compareNodes(Node n1, Node n2) { + int l1 = n1.getBeginLine(); + int l2 = n2.getBeginLine(); + if (l1 == l2) { + return n1.getBeginColumn() - n2.getBeginColumn(); + } + return l1 - l2; + } + + private static class MethodHolderComparator implements Comparator { + @Override + public int compare(MethodHolder o1, MethodHolder o2) { + return compareNodes(o1.getASTMethodDeclarator(), o2.getASTMethodDeclarator()); + } + } + + private static class ConstructorHolderComparator implements Comparator { + @Override + public int compare(ConstructorHolder o1, ConstructorHolder o2) { + return compareNodes(o1.getASTConstructorDeclaration(), o2.getASTConstructorDeclaration()); + } + } + + /** + * 1 package per class. holds info for evaluating a single class. + */ + private static class EvalPackage { + + public String className; + public List calledMethods; + public Map> allMethodsOfClass; + + public List calledConstructors; + public Map> allPrivateConstructorsOfClass; + + EvalPackage() { + } + + EvalPackage(String className) { + this.className = className; + // meths called from constructor + this.calledMethods = new ArrayList<>(); + this.allMethodsOfClass = new TreeMap<>(new MethodHolderComparator()); + // all constructors called from constructor + this.calledConstructors = new ArrayList<>(); + this.allPrivateConstructorsOfClass = new TreeMap<>(new ConstructorHolderComparator()); + } + + } + + private static final class NullEvalPackage extends EvalPackage { + NullEvalPackage() { + className = ""; + calledMethods = Collections.emptyList(); + allMethodsOfClass = Collections.emptyMap(); + calledConstructors = Collections.emptyList(); + allPrivateConstructorsOfClass = Collections.emptyMap(); + } + } + + private EvalPackage getCurrentEvalPackage() { + return evalPackages.get(evalPackages.size() - 1); + } + + /** + * Adds and evaluation package and makes it current + */ + private void putEvalPackage(EvalPackage ep) { + evalPackages.add(ep); + } + + private void removeCurrentEvalPackage() { + evalPackages.remove(evalPackages.size() - 1); + } + + private void clearEvalPackages() { + evalPackages.clear(); + } + + /** + * This check must be evaluated independently for each class. Inner classes + * get their own EvalPackage in order to perform independent evaluation. + */ + private Object visitClassDec(ASTClassOrInterfaceDeclaration node, Object data) { + String className = node.getImage(); + if (!node.isFinal()) { + putEvalPackage(new EvalPackage(className)); + } else { + putEvalPackage(NULL_EVAL_PACKAGE); + } + // store any errors caught from other passes. + super.visit(node, data); + + // skip this class if it has no evaluation package + if (!(getCurrentEvalPackage() instanceof NullEvalPackage)) { + // evaluate danger of all methods in class, this method will return + // false when all methods have been evaluated + while (evaluateDangerOfMethods(getCurrentEvalPackage().allMethodsOfClass)) { + } // NOPMD + + // evaluate danger of constructors + evaluateDangerOfConstructors1(getCurrentEvalPackage().allPrivateConstructorsOfClass, + getCurrentEvalPackage().allMethodsOfClass.keySet()); + while (evaluateDangerOfConstructors2(getCurrentEvalPackage().allPrivateConstructorsOfClass)) { + } // NOPMD + + // get each method called on this object from a non-private + // constructor, if its dangerous flag it + for (MethodInvocation meth : getCurrentEvalPackage().calledMethods) { + // check against each dangerous method in class + for (MethodHolder h : getCurrentEvalPackage().allMethodsOfClass.keySet()) { + if (h.isDangerous()) { + String methName = h.getASTMethodDeclarator().getImage(); + int count = h.getASTMethodDeclarator().getParameterCount(); + List parameterTypes = getMethodDeclaratorParameterTypes(h.getASTMethodDeclarator()); + if (methName.equals(meth.getName()) && meth.getArgumentCount() == count + && parameterTypes.equals(meth.getArgumentTypes())) { + addViolation(data, meth.getASTPrimaryExpression(), "method '" + h.getCalled() + "'"); + } + } + } + } + // get each unsafe private constructor, and check if its called from + // any non private constructors + for (ConstructorHolder ch : getCurrentEvalPackage().allPrivateConstructorsOfClass.keySet()) { + if (ch.isDangerous()) { + // if its dangerous check if its called + // from any non-private constructors + // System.out.println("visitClassDec Evaluating dangerous + // constructor with " + + // ch.getASTConstructorDeclaration().getParameterCount() + " + // params"); + int paramCount = ch.getASTConstructorDeclaration().getParameterCount(); + for (ConstructorInvocation ci : getCurrentEvalPackage().calledConstructors) { + if (ci.getArgumentCount() == paramCount) { + // match name super / this !? + addViolation(data, ci.getASTExplicitConstructorInvocation(), "constructor"); + } + } + } + } + } + // finished evaluating this class, move up a level + removeCurrentEvalPackage(); + return data; + } + + /** + * Check the methods called on this class by each of the methods on this + * class. If a method calls an unsafe method, mark the calling method as + * unsafe. This changes the list of unsafe methods which necessitates + * another pass. Keep passing until you make a clean pass in which no + * methods are changed to unsafe. For speed it is possible to limit the + * number of passes. + *

+ * Impossible to tell type of arguments to method, so forget method matching + * on types. just use name and num of arguments. will be some false hits, + * but oh well. + * + * TODO investigate limiting the number of passes through config. + */ + private boolean evaluateDangerOfMethods(Map> classMethodMap) { + // check each method if it calls overridable method + boolean found = false; + for (Map.Entry> entry : classMethodMap.entrySet()) { + MethodHolder h = entry.getKey(); + List calledMeths = entry.getValue(); + for (Iterator calledMethsIter = calledMeths.iterator(); calledMethsIter.hasNext() + && !h.isDangerous();) { + // if this method matches one of our dangerous methods, mark it + // dangerous + MethodInvocation meth = calledMethsIter.next(); + // System.out.println("Called meth is " + meth); + for (MethodHolder h3 : classMethodMap.keySet()) { + // need to skip self here h == h3 + if (h3.isDangerous()) { + String matchMethodName = h3.getASTMethodDeclarator().getImage(); + int matchMethodParamCount = h3.getASTMethodDeclarator().getParameterCount(); + List parameterTypes = getMethodDeclaratorParameterTypes(h3.getASTMethodDeclarator()); + // System.out.println("matching " + matchMethodName + " + // to " + meth.getName()); + if (matchMethodName.equals(meth.getName()) && matchMethodParamCount == meth.getArgumentCount() + && parameterTypes.equals(meth.getArgumentTypes())) { + h.setDangerous(); + h.setCalledMethod(matchMethodName); + found = true; + break; + } + } + } + } + } + return found; + } + + /** + * marks constructors dangerous if they call any dangerous methods Requires + * only a single pass as methods are already marked + * + * TODO optimize by having methods already evaluated somehow!? + */ + private void evaluateDangerOfConstructors1(Map> classConstructorMap, + Set evaluatedMethods) { + // check each constructor in the class + for (Map.Entry> entry : classConstructorMap.entrySet()) { + ConstructorHolder ch = entry.getKey(); + if (!ch.isDangerous()) { + // if its not dangerous then evaluate if it + // should be + // if it calls dangerous method mark it as dangerous + List calledMeths = entry.getValue(); + // check each method it calls + for (Iterator calledMethsIter = calledMeths.iterator(); calledMethsIter.hasNext() + && !ch.isDangerous();) { + // but thee are diff objects + // which represent same thing + // but were never evaluated, + // they need reevaluation + MethodInvocation meth = calledMethsIter.next(); // CCE + String methName = meth.getName(); + int methArgCount = meth.getArgumentCount(); + // check each of the already evaluated methods: need to + // optimize this out + for (MethodHolder h : evaluatedMethods) { + if (h.isDangerous()) { + String matchName = h.getASTMethodDeclarator().getImage(); + int matchParamCount = h.getASTMethodDeclarator().getParameterCount(); + List parameterTypes = getMethodDeclaratorParameterTypes(h.getASTMethodDeclarator()); + if (methName.equals(matchName) && methArgCount == matchParamCount + && parameterTypes.equals(meth.getArgumentTypes())) { + ch.setDangerous(true); + // System.out.println("evaluateDangerOfConstructors1 + // setting dangerous constructor with " + + // ch.getASTConstructorDeclaration().getParameterCount() + // + " params"); + break; + } + } + } + } + } + } + } + + /** + * Constructor map should contain a key for each private constructor, and + * maps to a List which contains all called constructors of that key. marks + * dangerous if call dangerous private constructor we ignore all non-private + * constructors here. That is, the map passed in should not contain any + * non-private constructors. we return boolean in order to limit the number + * of passes through this method but it seems as if we can forgo that and + * just process it till its done. + */ + private boolean evaluateDangerOfConstructors2(Map> classConstructorMap) { + boolean found = false; // triggers on danger state change + // check each constructor in the class + for (ConstructorHolder ch : classConstructorMap.keySet()) { + ConstructorInvocation calledC = ch.getCalledConstructor(); + if (calledC == null || ch.isDangerous()) { + continue; + } + // if its not dangerous then evaluate if it should be + // if it calls dangerous constructor mark it as dangerous + int cCount = calledC.getArgumentCount(); + for (Iterator innerConstIter = classConstructorMap.keySet().iterator(); innerConstIter + .hasNext() && !ch.isDangerous();) { + // forget skipping self because that introduces another + // check for each, but only 1 hit + ConstructorHolder h2 = innerConstIter.next(); + if (h2.isDangerous()) { + int matchConstArgCount = h2.getASTConstructorDeclaration().getParameterCount(); + List parameterTypes = getMethodDeclaratorParameterTypes(h2.getASTConstructorDeclaration()); + if (matchConstArgCount == cCount && parameterTypes.equals(calledC.getArgumentTypes())) { + ch.setDangerous(true); + found = true; + // System.out.println("evaluateDangerOfConstructors2 + // setting dangerous constructor with " + + // ch.getASTConstructorDeclaration().getParameterCount() + // + " params"); + } + } + } + } + return found; + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + clearEvalPackages(); + return super.visit(node, data); + } + + @Override + public Object visit(ASTEnumDeclaration node, Object data) { + // just skip Enums + return data; + } + + /** + * This check must be evaluated independently for each class. Inner classes + * get their own EvalPackage in order to perform independent evaluation. + */ + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (!node.isInterface()) { + return visitClassDec(node, data); + } else { + putEvalPackage(NULL_EVAL_PACKAGE); + // interface may have inner + // classes, possible? if not just + // skip whole interface + Object o = super.visit(node, data); + removeCurrentEvalPackage(); + return o; + } + } + + /** + * Non-private constructor's methods are added to a list for later safety + * evaluation. Non-private constructor's calls on private constructors are + * added to a list for later safety evaluation. Private constructors are + * added to a list so their safety to be called can be later evaluated. + * + *

Note: We are not checking private constructor's calls on non-private + * constructors because all non-private constructors will be evaluated for + * safety anyway. This means we wont flag a private constructor as unsafe + * just because it calls an unsafe public constructor. We want to show only + * 1 instance of an error, and this would be 2 instances of the same error.

+ * + *

TODO eliminate the redundancy

+ */ + @Override + public Object visit(ASTConstructorDeclaration node, Object data) { + if (!(getCurrentEvalPackage() instanceof NullEvalPackage)) { + // only evaluate if we have an eval package for this class + List calledMethodsOfConstructor = new ArrayList<>(); + ConstructorHolder ch = new ConstructorHolder(node); + addCalledMethodsOfNode(node, calledMethodsOfConstructor, getCurrentEvalPackage().className); + if (!node.isPrivate()) { + // these calledMethods are what we will evaluate for being + // called badly + getCurrentEvalPackage().calledMethods.addAll(calledMethodsOfConstructor); + // these called private constructors are what we will evaluate + // for being called badly + // we add all constructors invoked by non-private constructors + // but we are only interested in the private ones. We just can't + // tell the difference here + ASTExplicitConstructorInvocation eci = ch.getASTExplicitConstructorInvocation(); + if (eci != null && eci.isThis()) { + getCurrentEvalPackage().calledConstructors.add(ch.getCalledConstructor()); + } + } else { + // add all private constructors to list for later evaluation on + // if they are safe to call from another constructor + // store this constructorHolder for later evaluation + getCurrentEvalPackage().allPrivateConstructorsOfClass.put(ch, calledMethodsOfConstructor); + } + } + return super.visit(node, data); + } + + /** + * Create a MethodHolder to hold the method. Store the MethodHolder in the + * Map as the key Store each method called by the current method as a List + * in the Map as the Object + */ + @Override + public Object visit(ASTMethodDeclarator node, Object data) { + if (!(getCurrentEvalPackage() instanceof NullEvalPackage)) { + // only evaluate if we have an eval package for this class + AccessNode parent = (AccessNode) node.jjtGetParent(); + MethodHolder h = new MethodHolder(node); + if (!parent.isAbstract() && !parent.isPrivate() && !parent.isStatic() && !parent.isFinal()) { + // Skip abstract methods, have a separate rule for that + h.setDangerous(); // this method is overridable + ASTMethodDeclaration decl = node.getFirstParentOfType(ASTMethodDeclaration.class); + h.setCalledMethod(decl.getMethodName()); + } + List l = new ArrayList<>(); + addCalledMethodsOfNode(parent, l, getCurrentEvalPackage().className); + getCurrentEvalPackage().allMethodsOfClass.put(h, l); + } + return super.visit(node, data); + } + + /** + * Adds all methods called on this instance from within this Node. + */ + private static void addCalledMethodsOfNode(Node node, List calledMethods, String className) { + List expressions = new ArrayList<>(); + node.findDescendantsOfType(ASTPrimaryExpression.class, expressions, !(node instanceof AccessNode)); + addCalledMethodsOfNodeImpl(expressions, calledMethods, className); + } + + private static void addCalledMethodsOfNodeImpl(List expressions, + List calledMethods, String className) { + for (ASTPrimaryExpression ape : expressions) { + MethodInvocation meth = findMethod(ape, className); + if (meth != null) { + // System.out.println("Adding call " + methName); + calledMethods.add(meth); + } + } + } + + /** + * @return A method call on the class passed in, or null if no method call + * is found. TODO Need a better way to match the class and package + * name to the actual method being called. + */ + private static MethodInvocation findMethod(ASTPrimaryExpression node, String className) { + if (node.jjtGetNumChildren() > 0 && node.jjtGetChild(0).jjtGetNumChildren() > 0 + && node.jjtGetChild(0).jjtGetChild(0) instanceof ASTLiteral) { + return null; + } + MethodInvocation meth = MethodInvocation.getMethod(node); + boolean found = false; + // if(meth != null){ + // meth.show(); + // } + if (meth != null) { + // if it's a call on a variable, or on its superclass ignore it. + if (meth.getReferenceNames().isEmpty() && !meth.isSuper()) { + // if this list does not contain our class name, then its not + // referencing our class + // this is a cheezy test... but it errs on the side of less + // false hits. + List packClass = meth.getQualifierNames(); + if (!packClass.isEmpty()) { + for (String name : packClass) { + if (name.equals(className)) { + found = true; + break; + } + } + } else { + found = true; + } + } + } + + return found ? meth : null; + } + + /** + * ASTPrimaryPrefix has name in child node of ASTName + */ + private static String getNameFromPrefix(ASTPrimaryPrefix node) { + String name = null; + // should only be 1 child, if more I need more knowledge + if (node.jjtGetNumChildren() == 1) { // safety check + Node nnode = node.jjtGetChild(0); + if (nnode instanceof ASTName) { + // just as easy as null check and it + // should be an ASTName anyway + name = ((ASTName) nnode).getImage(); + } + } + return name; + } + + private static List getMethodDeclaratorParameterTypes(Node methodOrConstructorDeclarator) { + List parameters = methodOrConstructorDeclarator + .findDescendantsOfType(ASTFormalParameter.class); + List parameterTypes = new ArrayList<>(); + if (parameters != null) { + for (ASTFormalParameter p : parameters) { + ASTType type = p.getFirstChildOfType(ASTType.class); + if (type.jjtGetChild(0) instanceof ASTPrimitiveType) { + parameterTypes.add(type.jjtGetChild(0).getImage()); + } else if (type.jjtGetChild(0) instanceof ASTReferenceType) { + parameterTypes.add("ref"); + } else { + parameterTypes.add(""); + } + } + } + return parameterTypes; + } + + private static List getArgumentTypes(ASTArguments args) { + List argumentTypes = new ArrayList<>(); + ASTArgumentList argumentList = args.getFirstChildOfType(ASTArgumentList.class); + if (argumentList != null) { + for (int a = 0; a < argumentList.jjtGetNumChildren(); a++) { + Node expression = argumentList.jjtGetChild(a); + ASTPrimaryPrefix arg = expression.getFirstDescendantOfType(ASTPrimaryPrefix.class); + String type = ""; + if (arg != null && arg.jjtGetNumChildren() > 0) { + if (arg.jjtGetChild(0) instanceof ASTLiteral) { + ASTLiteral lit = (ASTLiteral) arg.jjtGetChild(0); + if (lit.isCharLiteral()) { + type = "char"; + } else if (lit.isFloatLiteral()) { + type = "float"; + } else if (lit.isIntLiteral()) { + type = "int"; + } else if (lit.isStringLiteral()) { + type = "String"; + } else if (lit.jjtGetNumChildren() > 0 && lit.jjtGetChild(0) instanceof ASTBooleanLiteral) { + type = "boolean"; + } else if (lit.isDoubleLiteral()) { + type = "double"; + } else if (lit.isLongLiteral()) { + type = "long"; + } + } else if (arg.jjtGetChild(0) instanceof ASTName) { + // ASTName n = (ASTName)arg.jjtGetChild(0); + type = "ref"; + } + } + argumentTypes.add(type); + } + } + return argumentTypes; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/IdempotentOperationsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/IdempotentOperationsRule.java index e5dd31f1f1..8656433bdb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/IdempotentOperationsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/IdempotentOperationsRule.java @@ -1,85 +1,85 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class IdempotentOperationsRule extends AbstractJavaRule { - - @Override - public Object visit(ASTStatementExpression node, Object data) { - if (node.jjtGetNumChildren() != 3 || !(node.jjtGetChild(0) instanceof ASTPrimaryExpression) - || !(node.jjtGetChild(1) instanceof ASTAssignmentOperator) - || ((ASTAssignmentOperator) node.jjtGetChild(1)).isCompound() - || !(node.jjtGetChild(2) instanceof ASTExpression) - || node.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0 - || node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0) { - return super.visit(node, data); - } - - Node lhs = node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); - if (!(lhs instanceof ASTName)) { - return super.visit(node, data); - } - - Node rhs = node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); - if (!(rhs instanceof ASTName)) { - return super.visit(node, data); - } - - if (!lhs.hasImageEqualTo(rhs.getImage())) { - return super.visit(node, data); - } - - if (lhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) { - Node n = lhs.jjtGetParent().jjtGetParent().jjtGetChild(1); - if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArrayDereference()) { - return super.visit(node, data); - } - } - - if (rhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) { - Node n = rhs.jjtGetParent().jjtGetParent().jjtGetChild(1); - if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArguments() - || ((ASTPrimarySuffix) n).isArrayDereference()) { - return super.visit(node, data); - } - } - - if (lhs.findDescendantsOfType(ASTPrimarySuffix.class).size() != rhs - .findDescendantsOfType(ASTPrimarySuffix.class).size()) { - return super.visit(node, data); - } - - List lhsSuffixes = lhs.jjtGetParent().jjtGetParent() - .findDescendantsOfType(ASTPrimarySuffix.class); - List rhsSuffixes = rhs.jjtGetParent().jjtGetParent() - .findDescendantsOfType(ASTPrimarySuffix.class); - if (lhsSuffixes.size() != rhsSuffixes.size()) { - return super.visit(node, data); - } - - for (int i = 0; i < lhsSuffixes.size(); i++) { - ASTPrimarySuffix l = lhsSuffixes.get(i); - ASTPrimarySuffix r = rhsSuffixes.get(i); - - if (!l.hasImageEqualTo(r.getImage())) { - return super.visit(node, data); - } - } - - addViolation(data, node); - return super.visit(node, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class IdempotentOperationsRule extends AbstractJavaRule { + + @Override + public Object visit(ASTStatementExpression node, Object data) { + if (node.jjtGetNumChildren() != 3 || !(node.jjtGetChild(0) instanceof ASTPrimaryExpression) + || !(node.jjtGetChild(1) instanceof ASTAssignmentOperator) + || ((ASTAssignmentOperator) node.jjtGetChild(1)).isCompound() + || !(node.jjtGetChild(2) instanceof ASTExpression) + || node.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0 + || node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0) { + return super.visit(node, data); + } + + Node lhs = node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); + if (!(lhs instanceof ASTName)) { + return super.visit(node, data); + } + + Node rhs = node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); + if (!(rhs instanceof ASTName)) { + return super.visit(node, data); + } + + if (!lhs.hasImageEqualTo(rhs.getImage())) { + return super.visit(node, data); + } + + if (lhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) { + Node n = lhs.jjtGetParent().jjtGetParent().jjtGetChild(1); + if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArrayDereference()) { + return super.visit(node, data); + } + } + + if (rhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) { + Node n = rhs.jjtGetParent().jjtGetParent().jjtGetChild(1); + if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArguments() + || ((ASTPrimarySuffix) n).isArrayDereference()) { + return super.visit(node, data); + } + } + + if (lhs.findDescendantsOfType(ASTPrimarySuffix.class).size() != rhs + .findDescendantsOfType(ASTPrimarySuffix.class).size()) { + return super.visit(node, data); + } + + List lhsSuffixes = lhs.jjtGetParent().jjtGetParent() + .findDescendantsOfType(ASTPrimarySuffix.class); + List rhsSuffixes = rhs.jjtGetParent().jjtGetParent() + .findDescendantsOfType(ASTPrimarySuffix.class); + if (lhsSuffixes.size() != rhsSuffixes.size()) { + return super.visit(node, data); + } + + for (int i = 0; i < lhsSuffixes.size(); i++) { + ASTPrimarySuffix l = lhsSuffixes.get(i); + ASTPrimarySuffix r = rhsSuffixes.get(i); + + if (!l.hasImageEqualTo(r.getImage())) { + return super.visit(node, data); + } + } + + addViolation(data, node); + return super.visit(node, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanReturnsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanReturnsRule.java index 7dd4ad6130..b6390905fa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanReturnsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanReturnsRule.java @@ -1,268 +1,268 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBlock; -import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; -import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class SimplifyBooleanReturnsRule extends AbstractJavaRule { - - public Object visit(ASTMethodDeclaration node, Object data) { - // only boolean methods should be inspected - ASTResultType r = node.getResultType(); - - if (!r.isVoid()) { - Node t = r.jjtGetChild(0); - if (t.jjtGetNumChildren() == 1) { - t = t.jjtGetChild(0); - if (t instanceof ASTPrimitiveType && ((ASTPrimitiveType) t).isBoolean()) { - return super.visit(node, data); - } - } - } - // skip method - return data; - } - - public Object visit(ASTIfStatement node, Object data) { - // that's the case: if..then..return; return; - if (!node.hasElse() && isIfJustReturnsBoolean(node) && isJustReturnsBooleanAfter(node)) { - addViolation(data, node); - return super.visit(node, data); - } - - // only deal with if..then..else stmts - if (node.jjtGetNumChildren() != 3) { - return super.visit(node, data); - } - - // don't bother if either the if or the else block is empty - if (node.jjtGetChild(1).jjtGetNumChildren() == 0 || node.jjtGetChild(2).jjtGetNumChildren() == 0) { - return super.visit(node, data); - } - - Node returnStatement1 = node.jjtGetChild(1).jjtGetChild(0); - Node returnStatement2 = node.jjtGetChild(2).jjtGetChild(0); - - if (returnStatement1 instanceof ASTReturnStatement && returnStatement2 instanceof ASTReturnStatement) { - Node expression1 = returnStatement1.jjtGetChild(0).jjtGetChild(0); - Node expression2 = returnStatement2.jjtGetChild(0).jjtGetChild(0); - if (terminatesInBooleanLiteral(returnStatement1) && terminatesInBooleanLiteral(returnStatement2)) { - addViolation(data, node); - } else if (expression1 instanceof ASTUnaryExpressionNotPlusMinus - ^ expression2 instanceof ASTUnaryExpressionNotPlusMinus) { - // We get the nodes under the '!' operator - // If they are the same => error - if (isNodesEqualWithUnaryExpression(expression1, expression2)) { - // second case: - // If - // Expr - // Statement - // ReturnStatement - // UnaryExpressionNotPlusMinus '!' - // Expression E - // Statement - // ReturnStatement - // Expression E - // i.e., - // if (foo) - // return !a; - // else - // return a; - addViolation(data, node); - } - } - } else if (hasOneBlockStmt(node.jjtGetChild(1)) && hasOneBlockStmt(node.jjtGetChild(2))) { - // We have blocks so we must go down three levels (BlockStatement, - // Statement, ReturnStatement) - returnStatement1 = returnStatement1.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); - returnStatement2 = returnStatement2.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); - - // if we have 2 return; - if (isSimpleReturn(returnStatement1) && isSimpleReturn(returnStatement2)) { - // third case - // If - // Expr - // Statement - // Block - // BlockStatement - // Statement - // ReturnStatement - // Statement - // Block - // BlockStatement - // Statement - // ReturnStatement - // i.e., - // if (foo) { - // return true; - // } else { - // return false; - // } - addViolation(data, node); - } else { - Node expression1 = getDescendant(returnStatement1, 4); - Node expression2 = getDescendant(returnStatement2, 4); - if (terminatesInBooleanLiteral(node.jjtGetChild(1).jjtGetChild(0)) - && terminatesInBooleanLiteral(node.jjtGetChild(2).jjtGetChild(0))) { - addViolation(data, node); - } else if (expression1 instanceof ASTUnaryExpressionNotPlusMinus - ^ expression2 instanceof ASTUnaryExpressionNotPlusMinus) { - // We get the nodes under the '!' operator - // If they are the same => error - if (isNodesEqualWithUnaryExpression(expression1, expression2)) { - // forth case - // If - // Expr - // Statement - // Block - // BlockStatement - // Statement - // ReturnStatement - // UnaryExpressionNotPlusMinus '!' - // Expression E - // Statement - // Block - // BlockStatement - // Statement - // ReturnStatement - // Expression E - // i.e., - // if (foo) { - // return !a; - // } else { - // return a; - // } - addViolation(data, node); - } - } - } - } - return super.visit(node, data); - } - - /** - * Checks, whether there is a statement after the given if statement, and if - * so, whether this is just a return boolean statement. - * - * @param node - * the if statement - * @return - */ - private boolean isJustReturnsBooleanAfter(ASTIfStatement ifNode) { - Node blockStatement = ifNode.jjtGetParent().jjtGetParent(); - Node block = blockStatement.jjtGetParent(); - if (block.jjtGetNumChildren() != blockStatement.jjtGetChildIndex() + 1 + 1) { - return false; - } - - Node nextBlockStatement = block.jjtGetChild(blockStatement.jjtGetChildIndex() + 1); - return terminatesInBooleanLiteral(nextBlockStatement); - } - - /** - * Checks whether the given ifstatement just returns a boolean in the if - * clause. - * - * @param node - * the if statement - * @return - */ - private boolean isIfJustReturnsBoolean(ASTIfStatement ifNode) { - Node node = ifNode.jjtGetChild(1); - return node.jjtGetNumChildren() == 1 - && (hasOneBlockStmt(node) || terminatesInBooleanLiteral(node.jjtGetChild(0))); - } - - private boolean hasOneBlockStmt(Node node) { - return node.jjtGetChild(0) instanceof ASTBlock && node.jjtGetChild(0).jjtGetNumChildren() == 1 - && terminatesInBooleanLiteral(node.jjtGetChild(0).jjtGetChild(0)); - } - - /** - * Returns the first child node going down 'level' levels or null if level - * is invalid - */ - private Node getDescendant(Node node, int level) { - Node n = node; - for (int i = 0; i < level; i++) { - if (n.jjtGetNumChildren() == 0) { - return null; - } - n = n.jjtGetChild(0); - } - return n; - } - - private boolean terminatesInBooleanLiteral(Node node) { - return eachNodeHasOneChild(node) && getLastChild(node) instanceof ASTBooleanLiteral; - } - - private boolean eachNodeHasOneChild(Node node) { - if (node.jjtGetNumChildren() > 1) { - return false; - } - if (node.jjtGetNumChildren() == 0) { - return true; - } - return eachNodeHasOneChild(node.jjtGetChild(0)); - } - - private Node getLastChild(Node node) { - if (node.jjtGetNumChildren() == 0) { - return node; - } - return getLastChild(node.jjtGetChild(0)); - } - - private boolean isNodesEqualWithUnaryExpression(Node n1, Node n2) { - Node node1; - Node node2; - if (n1 instanceof ASTUnaryExpressionNotPlusMinus) { - node1 = n1.jjtGetChild(0); - } else { - node1 = n1; - } - if (n2 instanceof ASTUnaryExpressionNotPlusMinus) { - node2 = n2.jjtGetChild(0); - } else { - node2 = n2; - } - return isNodesEquals(node1, node2); - } - - private boolean isNodesEquals(Node n1, Node n2) { - int numberChild1 = n1.jjtGetNumChildren(); - int numberChild2 = n2.jjtGetNumChildren(); - if (numberChild1 != numberChild2) { - return false; - } - if (!n1.getClass().equals(n2.getClass())) { - return false; - } - if (!n1.toString().equals(n2.toString())) { - return false; - } - for (int i = 0; i < numberChild1; i++) { - if (!isNodesEquals(n1.jjtGetChild(i), n2.jjtGetChild(i))) { - return false; - } - } - return true; - } - - private boolean isSimpleReturn(Node node) { - return node instanceof ASTReturnStatement && node.jjtGetNumChildren() == 0; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTBlock; +import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; +import net.sourceforge.pmd.lang.java.ast.ASTResultType; +import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class SimplifyBooleanReturnsRule extends AbstractJavaRule { + + public Object visit(ASTMethodDeclaration node, Object data) { + // only boolean methods should be inspected + ASTResultType r = node.getResultType(); + + if (!r.isVoid()) { + Node t = r.jjtGetChild(0); + if (t.jjtGetNumChildren() == 1) { + t = t.jjtGetChild(0); + if (t instanceof ASTPrimitiveType && ((ASTPrimitiveType) t).isBoolean()) { + return super.visit(node, data); + } + } + } + // skip method + return data; + } + + public Object visit(ASTIfStatement node, Object data) { + // that's the case: if..then..return; return; + if (!node.hasElse() && isIfJustReturnsBoolean(node) && isJustReturnsBooleanAfter(node)) { + addViolation(data, node); + return super.visit(node, data); + } + + // only deal with if..then..else stmts + if (node.jjtGetNumChildren() != 3) { + return super.visit(node, data); + } + + // don't bother if either the if or the else block is empty + if (node.jjtGetChild(1).jjtGetNumChildren() == 0 || node.jjtGetChild(2).jjtGetNumChildren() == 0) { + return super.visit(node, data); + } + + Node returnStatement1 = node.jjtGetChild(1).jjtGetChild(0); + Node returnStatement2 = node.jjtGetChild(2).jjtGetChild(0); + + if (returnStatement1 instanceof ASTReturnStatement && returnStatement2 instanceof ASTReturnStatement) { + Node expression1 = returnStatement1.jjtGetChild(0).jjtGetChild(0); + Node expression2 = returnStatement2.jjtGetChild(0).jjtGetChild(0); + if (terminatesInBooleanLiteral(returnStatement1) && terminatesInBooleanLiteral(returnStatement2)) { + addViolation(data, node); + } else if (expression1 instanceof ASTUnaryExpressionNotPlusMinus + ^ expression2 instanceof ASTUnaryExpressionNotPlusMinus) { + // We get the nodes under the '!' operator + // If they are the same => error + if (isNodesEqualWithUnaryExpression(expression1, expression2)) { + // second case: + // If + // Expr + // Statement + // ReturnStatement + // UnaryExpressionNotPlusMinus '!' + // Expression E + // Statement + // ReturnStatement + // Expression E + // i.e., + // if (foo) + // return !a; + // else + // return a; + addViolation(data, node); + } + } + } else if (hasOneBlockStmt(node.jjtGetChild(1)) && hasOneBlockStmt(node.jjtGetChild(2))) { + // We have blocks so we must go down three levels (BlockStatement, + // Statement, ReturnStatement) + returnStatement1 = returnStatement1.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); + returnStatement2 = returnStatement2.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0); + + // if we have 2 return; + if (isSimpleReturn(returnStatement1) && isSimpleReturn(returnStatement2)) { + // third case + // If + // Expr + // Statement + // Block + // BlockStatement + // Statement + // ReturnStatement + // Statement + // Block + // BlockStatement + // Statement + // ReturnStatement + // i.e., + // if (foo) { + // return true; + // } else { + // return false; + // } + addViolation(data, node); + } else { + Node expression1 = getDescendant(returnStatement1, 4); + Node expression2 = getDescendant(returnStatement2, 4); + if (terminatesInBooleanLiteral(node.jjtGetChild(1).jjtGetChild(0)) + && terminatesInBooleanLiteral(node.jjtGetChild(2).jjtGetChild(0))) { + addViolation(data, node); + } else if (expression1 instanceof ASTUnaryExpressionNotPlusMinus + ^ expression2 instanceof ASTUnaryExpressionNotPlusMinus) { + // We get the nodes under the '!' operator + // If they are the same => error + if (isNodesEqualWithUnaryExpression(expression1, expression2)) { + // forth case + // If + // Expr + // Statement + // Block + // BlockStatement + // Statement + // ReturnStatement + // UnaryExpressionNotPlusMinus '!' + // Expression E + // Statement + // Block + // BlockStatement + // Statement + // ReturnStatement + // Expression E + // i.e., + // if (foo) { + // return !a; + // } else { + // return a; + // } + addViolation(data, node); + } + } + } + } + return super.visit(node, data); + } + + /** + * Checks, whether there is a statement after the given if statement, and if + * so, whether this is just a return boolean statement. + * + * @param node + * the if statement + * @return + */ + private boolean isJustReturnsBooleanAfter(ASTIfStatement ifNode) { + Node blockStatement = ifNode.jjtGetParent().jjtGetParent(); + Node block = blockStatement.jjtGetParent(); + if (block.jjtGetNumChildren() != blockStatement.jjtGetChildIndex() + 1 + 1) { + return false; + } + + Node nextBlockStatement = block.jjtGetChild(blockStatement.jjtGetChildIndex() + 1); + return terminatesInBooleanLiteral(nextBlockStatement); + } + + /** + * Checks whether the given ifstatement just returns a boolean in the if + * clause. + * + * @param node + * the if statement + * @return + */ + private boolean isIfJustReturnsBoolean(ASTIfStatement ifNode) { + Node node = ifNode.jjtGetChild(1); + return node.jjtGetNumChildren() == 1 + && (hasOneBlockStmt(node) || terminatesInBooleanLiteral(node.jjtGetChild(0))); + } + + private boolean hasOneBlockStmt(Node node) { + return node.jjtGetChild(0) instanceof ASTBlock && node.jjtGetChild(0).jjtGetNumChildren() == 1 + && terminatesInBooleanLiteral(node.jjtGetChild(0).jjtGetChild(0)); + } + + /** + * Returns the first child node going down 'level' levels or null if level + * is invalid + */ + private Node getDescendant(Node node, int level) { + Node n = node; + for (int i = 0; i < level; i++) { + if (n.jjtGetNumChildren() == 0) { + return null; + } + n = n.jjtGetChild(0); + } + return n; + } + + private boolean terminatesInBooleanLiteral(Node node) { + return eachNodeHasOneChild(node) && getLastChild(node) instanceof ASTBooleanLiteral; + } + + private boolean eachNodeHasOneChild(Node node) { + if (node.jjtGetNumChildren() > 1) { + return false; + } + if (node.jjtGetNumChildren() == 0) { + return true; + } + return eachNodeHasOneChild(node.jjtGetChild(0)); + } + + private Node getLastChild(Node node) { + if (node.jjtGetNumChildren() == 0) { + return node; + } + return getLastChild(node.jjtGetChild(0)); + } + + private boolean isNodesEqualWithUnaryExpression(Node n1, Node n2) { + Node node1; + Node node2; + if (n1 instanceof ASTUnaryExpressionNotPlusMinus) { + node1 = n1.jjtGetChild(0); + } else { + node1 = n1; + } + if (n2 instanceof ASTUnaryExpressionNotPlusMinus) { + node2 = n2.jjtGetChild(0); + } else { + node2 = n2; + } + return isNodesEquals(node1, node2); + } + + private boolean isNodesEquals(Node n1, Node n2) { + int numberChild1 = n1.jjtGetNumChildren(); + int numberChild2 = n2.jjtGetNumChildren(); + if (numberChild1 != numberChild2) { + return false; + } + if (!n1.getClass().equals(n2.getClass())) { + return false; + } + if (!n1.toString().equals(n2.toString())) { + return false; + } + for (int i = 0; i < numberChild1; i++) { + if (!isNodesEquals(n1.jjtGetChild(i), n2.jjtGetChild(i))) { + return false; + } + } + return true; + } + + private boolean isSimpleReturn(Node node) { + return node instanceof ASTReturnStatement && node.jjtGetNumChildren() == 0; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/finalizers/AvoidCallingFinalizeRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/finalizers/AvoidCallingFinalizeRule.java index d9637a763f..76585fd3c0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/finalizers/AvoidCallingFinalizeRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/finalizers/AvoidCallingFinalizeRule.java @@ -1,68 +1,68 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.finalizers; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.MethodScope; -import net.sourceforge.pmd.lang.symboltable.ScopedNode; - -public class AvoidCallingFinalizeRule extends AbstractJavaRule { - - private Set checked = new HashSet<>(); - - public Object visit(ASTCompilationUnit acu, Object ctx) { - checked.clear(); - return super.visit(acu, ctx); - } - - public Object visit(ASTName name, Object ctx) { - if (name.getImage() == null || !name.getImage().endsWith("finalize")) { - return ctx; - } - if (!checkForViolation(name)) { - return ctx; - } - addViolation(ctx, name); - return ctx; - } - - public Object visit(ASTPrimaryPrefix pp, Object ctx) { - List primarySuffixes = pp.jjtGetParent().findChildrenOfType(ASTPrimarySuffix.class); - ASTPrimarySuffix firstSuffix = null; - if (!primarySuffixes.isEmpty()) { - firstSuffix = primarySuffixes.get(0); - } - if (firstSuffix == null || firstSuffix.getImage() == null || !firstSuffix.getImage().endsWith("finalize")) { - return super.visit(pp, ctx); - } - if (!checkForViolation(pp)) { - return super.visit(pp, ctx); - } - addViolation(ctx, pp); - return super.visit(pp, ctx); - } - - private boolean checkForViolation(ScopedNode node) { - MethodScope meth = node.getScope().getEnclosingScope(MethodScope.class); - if (meth != null && "finalize".equals(meth.getName())) { - return false; - } - if (meth != null && checked.contains(meth)) { - return false; - } - if (meth != null) { - checked.add(meth); - } - return true; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.finalizers; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.MethodScope; +import net.sourceforge.pmd.lang.symboltable.ScopedNode; + +public class AvoidCallingFinalizeRule extends AbstractJavaRule { + + private Set checked = new HashSet<>(); + + public Object visit(ASTCompilationUnit acu, Object ctx) { + checked.clear(); + return super.visit(acu, ctx); + } + + public Object visit(ASTName name, Object ctx) { + if (name.getImage() == null || !name.getImage().endsWith("finalize")) { + return ctx; + } + if (!checkForViolation(name)) { + return ctx; + } + addViolation(ctx, name); + return ctx; + } + + public Object visit(ASTPrimaryPrefix pp, Object ctx) { + List primarySuffixes = pp.jjtGetParent().findChildrenOfType(ASTPrimarySuffix.class); + ASTPrimarySuffix firstSuffix = null; + if (!primarySuffixes.isEmpty()) { + firstSuffix = primarySuffixes.get(0); + } + if (firstSuffix == null || firstSuffix.getImage() == null || !firstSuffix.getImage().endsWith("finalize")) { + return super.visit(pp, ctx); + } + if (!checkForViolation(pp)) { + return super.visit(pp, ctx); + } + addViolation(ctx, pp); + return super.visit(pp, ctx); + } + + private boolean checkForViolation(ScopedNode node) { + MethodScope meth = node.getScope().getEnclosingScope(MethodScope.class); + if (meth != null && "finalize".equals(meth.getName())) { + return false; + } + if (meth != null && checked.contains(meth)) { + return false; + } + if (meth != null) { + checked.add(meth); + } + return true; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/javabeans/BeanMembersShouldSerializeRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/javabeans/BeanMembersShouldSerializeRule.java index 6e0ed79ba9..f594616b86 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/javabeans/BeanMembersShouldSerializeRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/javabeans/BeanMembersShouldSerializeRule.java @@ -1,119 +1,119 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.javabeans; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; -import net.sourceforge.pmd.lang.java.ast.AccessNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.ClassScope; -import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration; -import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.rule.properties.StringProperty; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -public class BeanMembersShouldSerializeRule extends AbstractJavaRule { - - private String prefixProperty; - - private static final StringProperty PREFIX_DESCRIPTOR = new StringProperty("prefix", - "A variable prefix to skip, i.e., m_", "", 1.0f); - - public BeanMembersShouldSerializeRule() { - definePropertyDescriptor(PREFIX_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - prefixProperty = getProperty(PREFIX_DESCRIPTOR); - super.visit(node, data); - return data; - } - - private static String[] imagesOf(List nodes) { - - String[] imageArray = new String[nodes.size()]; - - for (int i = 0; i < nodes.size(); i++) { - imageArray[i] = nodes.get(i).getImage(); - } - return imageArray; - } - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - - Map> methods = node.getScope().getEnclosingScope(ClassScope.class) - .getMethodDeclarations(); - List getSetMethList = new ArrayList<>(methods.size()); - for (MethodNameDeclaration d : methods.keySet()) { - ASTMethodDeclarator mnd = d.getMethodNameDeclaratorNode(); - if (isBeanAccessor(mnd)) { - getSetMethList.add(mnd); - } - } - - String[] methNameArray = imagesOf(getSetMethList); - - Arrays.sort(methNameArray); - - Map> vars = node.getScope() - .getDeclarations(VariableNameDeclaration.class); - for (VariableNameDeclaration decl : vars.keySet()) { - AccessNode accessNodeParent = decl.getAccessNodeParent(); - if (vars.get(decl).isEmpty() || accessNodeParent.isTransient() || accessNodeParent.isStatic()) { - continue; - } - String varName = trimIfPrefix(decl.getImage()); - varName = varName.substring(0, 1).toUpperCase() + varName.substring(1, varName.length()); - boolean hasGetMethod = Arrays.binarySearch(methNameArray, "get" + varName) >= 0 - || Arrays.binarySearch(methNameArray, "is" + varName) >= 0; - boolean hasSetMethod = Arrays.binarySearch(methNameArray, "set" + varName) >= 0; - // Note that a Setter method is not applicable to a final - // variable... - if (!hasGetMethod || !accessNodeParent.isFinal() && !hasSetMethod) { - addViolation(data, decl.getNode(), decl.getImage()); - } - } - return super.visit(node, data); - } - - private String trimIfPrefix(String img) { - if (prefixProperty != null && img.startsWith(prefixProperty)) { - return img.substring(prefixProperty.length()); - } - return img; - } - - private boolean isBeanAccessor(ASTMethodDeclarator meth) { - - String methodName = meth.getImage(); - - if (methodName.startsWith("get") || methodName.startsWith("set")) { - return true; - } - if (methodName.startsWith("is")) { - ASTResultType ret = ((ASTMethodDeclaration) meth.jjtGetParent()).getResultType(); - List primitives = ret.findDescendantsOfType(ASTPrimitiveType.class); - if (!primitives.isEmpty() && primitives.get(0).isBoolean()) { - return true; - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.javabeans; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; +import net.sourceforge.pmd.lang.java.ast.ASTResultType; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.ClassScope; +import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.rule.properties.StringProperty; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +public class BeanMembersShouldSerializeRule extends AbstractJavaRule { + + private String prefixProperty; + + private static final StringProperty PREFIX_DESCRIPTOR = new StringProperty("prefix", + "A variable prefix to skip, i.e., m_", "", 1.0f); + + public BeanMembersShouldSerializeRule() { + definePropertyDescriptor(PREFIX_DESCRIPTOR); + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + prefixProperty = getProperty(PREFIX_DESCRIPTOR); + super.visit(node, data); + return data; + } + + private static String[] imagesOf(List nodes) { + + String[] imageArray = new String[nodes.size()]; + + for (int i = 0; i < nodes.size(); i++) { + imageArray[i] = nodes.get(i).getImage(); + } + return imageArray; + } + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + + Map> methods = node.getScope().getEnclosingScope(ClassScope.class) + .getMethodDeclarations(); + List getSetMethList = new ArrayList<>(methods.size()); + for (MethodNameDeclaration d : methods.keySet()) { + ASTMethodDeclarator mnd = d.getMethodNameDeclaratorNode(); + if (isBeanAccessor(mnd)) { + getSetMethList.add(mnd); + } + } + + String[] methNameArray = imagesOf(getSetMethList); + + Arrays.sort(methNameArray); + + Map> vars = node.getScope() + .getDeclarations(VariableNameDeclaration.class); + for (VariableNameDeclaration decl : vars.keySet()) { + AccessNode accessNodeParent = decl.getAccessNodeParent(); + if (vars.get(decl).isEmpty() || accessNodeParent.isTransient() || accessNodeParent.isStatic()) { + continue; + } + String varName = trimIfPrefix(decl.getImage()); + varName = varName.substring(0, 1).toUpperCase() + varName.substring(1, varName.length()); + boolean hasGetMethod = Arrays.binarySearch(methNameArray, "get" + varName) >= 0 + || Arrays.binarySearch(methNameArray, "is" + varName) >= 0; + boolean hasSetMethod = Arrays.binarySearch(methNameArray, "set" + varName) >= 0; + // Note that a Setter method is not applicable to a final + // variable... + if (!hasGetMethod || !accessNodeParent.isFinal() && !hasSetMethod) { + addViolation(data, decl.getNode(), decl.getImage()); + } + } + return super.visit(node, data); + } + + private String trimIfPrefix(String img) { + if (prefixProperty != null && img.startsWith(prefixProperty)) { + return img.substring(prefixProperty.length()); + } + return img; + } + + private boolean isBeanAccessor(ASTMethodDeclarator meth) { + + String methodName = meth.getImage(); + + if (methodName.startsWith("get") || methodName.startsWith("set")) { + return true; + } + if (methodName.startsWith("is")) { + ASTResultType ret = ((ASTMethodDeclaration) meth.jjtGetParent()).getResultType(); + List primitives = ret.findDescendantsOfType(ASTPrimitiveType.class); + if (!primitives.isEmpty() && primitives.get(0).isBoolean()) { + return true; + } + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/junit/JUnitTestsShouldIncludeAssertRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/junit/JUnitTestsShouldIncludeAssertRule.java index 5785a1b728..f421b6ff6f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/junit/JUnitTestsShouldIncludeAssertRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/junit/JUnitTestsShouldIncludeAssertRule.java @@ -1,98 +1,98 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.junit; - -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTNormalAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; - -public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTMethodDeclaration method, Object data) { - if (isJUnitMethod(method, data)) { - if (!containsAssert(method.getBlock(), false) && !containsExpect(method.jjtGetParent())) { - addViolation(data, method); - } - } - return data; - } - - private boolean containsAssert(Node n, boolean assertFound) { - if (!assertFound) { - if (n instanceof ASTStatementExpression) { - if (isAssertOrFailStatement((ASTStatementExpression) n)) { - return true; - } - } - if (!assertFound) { - for (int i = 0; i < n.jjtGetNumChildren() && !assertFound; i++) { - Node c = n.jjtGetChild(i); - if (containsAssert(c, assertFound)) { - return true; - } - } - } - } - return false; - } - - /** - * Tells if the node contains a Test annotation with an expected exception. - */ - private boolean containsExpect(Node methodParent) { - List annotations = methodParent.findDescendantsOfType(ASTNormalAnnotation.class); - for (ASTNormalAnnotation annotation : annotations) { - ASTName name = annotation.getFirstChildOfType(ASTName.class); - if (name != null && ("Test".equals(name.getImage()) - || name.getType() != null && name.getType().equals(JUNIT4_CLASS))) { - List memberValues = annotation.findDescendantsOfType(ASTMemberValuePair.class); - for (ASTMemberValuePair pair : memberValues) { - if ("expected".equals(pair.getImage())) { - return true; - } - } - } - } - return false; - } - - /** - * Tells if the expression is an assert statement or not. - */ - private boolean isAssertOrFailStatement(ASTStatementExpression expression) { - if (expression != null && expression.jjtGetNumChildren() > 0 - && expression.jjtGetChild(0) instanceof ASTPrimaryExpression) { - ASTPrimaryExpression pe = (ASTPrimaryExpression) expression.jjtGetChild(0); - if (pe.jjtGetNumChildren() > 0 && pe.jjtGetChild(0) instanceof ASTPrimaryPrefix) { - ASTPrimaryPrefix pp = (ASTPrimaryPrefix) pe.jjtGetChild(0); - if (pp.jjtGetNumChildren() > 0 && pp.jjtGetChild(0) instanceof ASTName) { - String img = ((ASTName) pp.jjtGetChild(0)).getImage(); - if (img != null && (img.startsWith("assert") || img.startsWith("fail") - || img.startsWith("Assert.assert") || img.startsWith("Assert.fail"))) { - return true; - } - } - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.junit; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTNormalAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; + +public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + return super.visit(node, data); + } + + @Override + public Object visit(ASTMethodDeclaration method, Object data) { + if (isJUnitMethod(method, data)) { + if (!containsAssert(method.getBlock(), false) && !containsExpect(method.jjtGetParent())) { + addViolation(data, method); + } + } + return data; + } + + private boolean containsAssert(Node n, boolean assertFound) { + if (!assertFound) { + if (n instanceof ASTStatementExpression) { + if (isAssertOrFailStatement((ASTStatementExpression) n)) { + return true; + } + } + if (!assertFound) { + for (int i = 0; i < n.jjtGetNumChildren() && !assertFound; i++) { + Node c = n.jjtGetChild(i); + if (containsAssert(c, assertFound)) { + return true; + } + } + } + } + return false; + } + + /** + * Tells if the node contains a Test annotation with an expected exception. + */ + private boolean containsExpect(Node methodParent) { + List annotations = methodParent.findDescendantsOfType(ASTNormalAnnotation.class); + for (ASTNormalAnnotation annotation : annotations) { + ASTName name = annotation.getFirstChildOfType(ASTName.class); + if (name != null && ("Test".equals(name.getImage()) + || name.getType() != null && name.getType().equals(JUNIT4_CLASS))) { + List memberValues = annotation.findDescendantsOfType(ASTMemberValuePair.class); + for (ASTMemberValuePair pair : memberValues) { + if ("expected".equals(pair.getImage())) { + return true; + } + } + } + } + return false; + } + + /** + * Tells if the expression is an assert statement or not. + */ + private boolean isAssertOrFailStatement(ASTStatementExpression expression) { + if (expression != null && expression.jjtGetNumChildren() > 0 + && expression.jjtGetChild(0) instanceof ASTPrimaryExpression) { + ASTPrimaryExpression pe = (ASTPrimaryExpression) expression.jjtGetChild(0); + if (pe.jjtGetNumChildren() > 0 && pe.jjtGetChild(0) instanceof ASTPrimaryPrefix) { + ASTPrimaryPrefix pp = (ASTPrimaryPrefix) pe.jjtGetChild(0); + if (pp.jjtGetNumChildren() > 0 && pp.jjtGetChild(0) instanceof ASTName) { + String img = ((ASTName) pp.jjtGetChild(0)).getImage(); + if (img != null && (img.startsWith("assert") || img.startsWith("fail") + || img.startsWith("Assert.assert") || img.startsWith("Assert.fail"))) { + return true; + } + } + } + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/logging/MoreThanOneLoggerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/logging/MoreThanOneLoggerRule.java index 6c3e8926e1..20de8dec78 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/logging/MoreThanOneLoggerRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/logging/MoreThanOneLoggerRule.java @@ -1,109 +1,109 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.logging; - -import java.util.Stack; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.util.NumericConstants; - -public class MoreThanOneLoggerRule extends AbstractJavaRule { - - private static final Class LOG4J_LOGGER; - - private static final Class JAVA_LOGGER; - - private static final Class SLF4J_LOGGER; - - static { - Class c; - try { - c = Class.forName("org.apache.log4j.Logger"); - } catch (Throwable t) { - c = null; - } - LOG4J_LOGGER = c; - try { - c = Class.forName("java.util.logging.Logger"); - } catch (Throwable t) { - c = null; - } - JAVA_LOGGER = c; - try { - c = Class.forName("org.slf4j.Logger"); - } catch (Throwable t) { - c = null; - } - SLF4J_LOGGER = c; - } - - private Stack stack = new Stack<>(); - - private Integer count; - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - return init(node, data); - } - - @Override - public Object visit(ASTEnumDeclaration node, Object data) { - return init(node, data); - } - - @Override - public Object visit(ASTAnnotationTypeDeclaration node, Object data) { - return init(node, data); - } - - private Object init(JavaNode node, Object data) { - stack.push(count); - count = NumericConstants.ZERO; - - node.childrenAccept(this, data); - - if (count > 1) { - addViolation(data, node); - } - count = stack.pop(); - - return data; - } - - @Override - public Object visit(ASTVariableDeclarator node, Object data) { - if (count > 1) { - return super.visit(node, data); - } - Node type = node.jjtGetParent().getFirstChildOfType(ASTType.class); - if (type != null) { - Node reftypeNode = type.jjtGetChild(0); - if (reftypeNode instanceof ASTReferenceType) { - Node classOrIntType = reftypeNode.jjtGetChild(0); - if (classOrIntType instanceof ASTClassOrInterfaceType) { - Class clazzType = ((ASTClassOrInterfaceType) classOrIntType).getType(); - if (clazzType != null - && (clazzType.equals(LOG4J_LOGGER) || clazzType.equals(JAVA_LOGGER) - || clazzType.equals(SLF4J_LOGGER)) - || clazzType == null && "Logger".equals(classOrIntType.getImage())) { - ++count; - } - } - } - } - - return super.visit(node, data); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.logging; + +import java.util.Stack; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.util.NumericConstants; + +public class MoreThanOneLoggerRule extends AbstractJavaRule { + + private static final Class LOG4J_LOGGER; + + private static final Class JAVA_LOGGER; + + private static final Class SLF4J_LOGGER; + + static { + Class c; + try { + c = Class.forName("org.apache.log4j.Logger"); + } catch (Throwable t) { + c = null; + } + LOG4J_LOGGER = c; + try { + c = Class.forName("java.util.logging.Logger"); + } catch (Throwable t) { + c = null; + } + JAVA_LOGGER = c; + try { + c = Class.forName("org.slf4j.Logger"); + } catch (Throwable t) { + c = null; + } + SLF4J_LOGGER = c; + } + + private Stack stack = new Stack<>(); + + private Integer count; + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + return init(node, data); + } + + @Override + public Object visit(ASTEnumDeclaration node, Object data) { + return init(node, data); + } + + @Override + public Object visit(ASTAnnotationTypeDeclaration node, Object data) { + return init(node, data); + } + + private Object init(JavaNode node, Object data) { + stack.push(count); + count = NumericConstants.ZERO; + + node.childrenAccept(this, data); + + if (count > 1) { + addViolation(data, node); + } + count = stack.pop(); + + return data; + } + + @Override + public Object visit(ASTVariableDeclarator node, Object data) { + if (count > 1) { + return super.visit(node, data); + } + Node type = node.jjtGetParent().getFirstChildOfType(ASTType.class); + if (type != null) { + Node reftypeNode = type.jjtGetChild(0); + if (reftypeNode instanceof ASTReferenceType) { + Node classOrIntType = reftypeNode.jjtGetChild(0); + if (classOrIntType instanceof ASTClassOrInterfaceType) { + Class clazzType = ((ASTClassOrInterfaceType) classOrIntType).getType(); + if (clazzType != null + && (clazzType.equals(LOG4J_LOGGER) || clazzType.equals(JAVA_LOGGER) + || clazzType.equals(SLF4J_LOGGER)) + || clazzType == null && "Logger".equals(classOrIntType.getImage())) { + ++count; + } + } + } + } + + return super.visit(node, data); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingMethodNameRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingMethodNameRule.java index 231a8db34f..51fdc1fc15 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingMethodNameRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingMethodNameRule.java @@ -1,55 +1,55 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.naming; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class AvoidFieldNameMatchingMethodNameRule extends AbstractJavaRule { - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTClassOrInterfaceBody node, Object data) { - int n = node.jjtGetNumChildren(); - List fields = new ArrayList<>(); - Set methodNames = new HashSet<>(); - for (int i = 0; i < n; i++) { - Node child = node.jjtGetChild(i); - if (child.jjtGetNumChildren() == 0) { - continue; - } - child = child.jjtGetChild(child.jjtGetNumChildren() - 1); - if (child instanceof ASTFieldDeclaration) { - fields.add((ASTFieldDeclaration) child); - } else if (child instanceof ASTMethodDeclaration) { - methodNames.add(((ASTMethodDeclaration) child).getMethodName().toLowerCase()); - } - } - for (ASTFieldDeclaration field : fields) { - String varName = field.getVariableName().toLowerCase(); - if (methodNames.contains(varName)) { - addViolation(data, field, field.getVariableName()); - } - } - return super.visit(node, data); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.naming; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class AvoidFieldNameMatchingMethodNameRule extends AbstractJavaRule { + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + return super.visit(node, data); + } + + @Override + public Object visit(ASTClassOrInterfaceBody node, Object data) { + int n = node.jjtGetNumChildren(); + List fields = new ArrayList<>(); + Set methodNames = new HashSet<>(); + for (int i = 0; i < n; i++) { + Node child = node.jjtGetChild(i); + if (child.jjtGetNumChildren() == 0) { + continue; + } + child = child.jjtGetChild(child.jjtGetNumChildren() - 1); + if (child instanceof ASTFieldDeclaration) { + fields.add((ASTFieldDeclaration) child); + } else if (child instanceof ASTMethodDeclaration) { + methodNames.add(((ASTMethodDeclaration) child).getMethodName().toLowerCase()); + } + } + for (ASTFieldDeclaration field : fields) { + String varName = field.getVariableName().toLowerCase(); + if (methodNames.contains(varName)) { + addViolation(data, field, field.getVariableName()); + } + } + return super.visit(node, data); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingTypeNameRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingTypeNameRule.java index 6e4d9b8d9e..b557716046 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingTypeNameRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/AvoidFieldNameMatchingTypeNameRule.java @@ -1,27 +1,27 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.naming; - -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class AvoidFieldNameMatchingTypeNameRule extends AbstractJavaRule { - - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); - } - - public Object visit(ASTFieldDeclaration node, Object data) { - ASTClassOrInterfaceDeclaration cl = node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); - if (cl != null && node.getVariableName().equalsIgnoreCase(cl.getImage())) { - addViolation(data, node); - } - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.naming; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class AvoidFieldNameMatchingTypeNameRule extends AbstractJavaRule { + + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + return super.visit(node, data); + } + + public Object visit(ASTFieldDeclaration node, Object data) { + ASTClassOrInterfaceDeclaration cl = node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); + if (cl != null && node.getVariableName().equalsIgnoreCase(cl.getImage())) { + addViolation(data, node); + } + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/ClassNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/ClassNamingConventionsRule.java index 6342b0f646..59015b70c8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/ClassNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/ClassNamingConventionsRule.java @@ -1,18 +1,18 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.naming; - -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class ClassNamingConventionsRule extends AbstractJavaRule { - - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (Character.isLowerCase(node.getImage().charAt(0))) { - addViolation(data, node); - } - return data; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.naming; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class ClassNamingConventionsRule extends AbstractJavaRule { + + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (Character.isLowerCase(node.getImage().charAt(0))) { + addViolation(data, node); + } + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodNamingConventionsRule.java index 8e5808699d..25f7963e9e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodNamingConventionsRule.java @@ -1,66 +1,66 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.naming; - -import java.util.List; - -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; - -public class MethodNamingConventionsRule extends AbstractJavaRule { - - private boolean checkNativeMethods; - - private static final BooleanProperty CHECK_NATIVE_METHODS_DESCRIPTOR = new BooleanProperty("checkNativeMethods", - "Check native methods", true, 1.0f); - - public MethodNamingConventionsRule() { - definePropertyDescriptor(CHECK_NATIVE_METHODS_DESCRIPTOR); - } - - public Object visit(ASTCompilationUnit node, Object data) { - checkNativeMethods = getProperty(CHECK_NATIVE_METHODS_DESCRIPTOR); - return super.visit(node, data); - } - - public Object visit(ASTMethodDeclarator node, Object data) { - if (!checkNativeMethods && node.getFirstParentOfType(ASTMethodDeclaration.class).isNative()) { - return data; - } - - if (isOverriddenMethod(node)) { - return data; - } - - String methodName = node.getImage(); - - if (Character.isUpperCase(methodName.charAt(0))) { - addViolationWithMessage(data, node, "Method names should not start with capital letters"); - } - if (methodName.indexOf('_') >= 0) { - addViolationWithMessage(data, node, "Method names should not contain underscores"); - } - return data; - } - - private boolean isOverriddenMethod(ASTMethodDeclarator node) { - ASTClassOrInterfaceBodyDeclaration declaration = node - .getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class); - List annotations = declaration.findDescendantsOfType(ASTMarkerAnnotation.class); - for (ASTMarkerAnnotation ann : annotations) { - ASTName name = ann.getFirstChildOfType(ASTName.class); - if (name != null && name.hasImageEqualTo("Override")) { - return true; - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.naming; + +import java.util.List; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; + +public class MethodNamingConventionsRule extends AbstractJavaRule { + + private boolean checkNativeMethods; + + private static final BooleanProperty CHECK_NATIVE_METHODS_DESCRIPTOR = new BooleanProperty("checkNativeMethods", + "Check native methods", true, 1.0f); + + public MethodNamingConventionsRule() { + definePropertyDescriptor(CHECK_NATIVE_METHODS_DESCRIPTOR); + } + + public Object visit(ASTCompilationUnit node, Object data) { + checkNativeMethods = getProperty(CHECK_NATIVE_METHODS_DESCRIPTOR); + return super.visit(node, data); + } + + public Object visit(ASTMethodDeclarator node, Object data) { + if (!checkNativeMethods && node.getFirstParentOfType(ASTMethodDeclaration.class).isNative()) { + return data; + } + + if (isOverriddenMethod(node)) { + return data; + } + + String methodName = node.getImage(); + + if (Character.isUpperCase(methodName.charAt(0))) { + addViolationWithMessage(data, node, "Method names should not start with capital letters"); + } + if (methodName.indexOf('_') >= 0) { + addViolationWithMessage(data, node, "Method names should not contain underscores"); + } + return data; + } + + private boolean isOverriddenMethod(ASTMethodDeclarator node) { + ASTClassOrInterfaceBodyDeclaration declaration = node + .getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class); + List annotations = declaration.findDescendantsOfType(ASTMarkerAnnotation.class); + for (ASTMarkerAnnotation ann : annotations) { + ASTName name = ann.getFirstChildOfType(ASTName.class); + if (name != null && name.hasImageEqualTo("Override")) { + return true; + } + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodWithSameNameAsEnclosingClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodWithSameNameAsEnclosingClassRule.java index f8bda5ae34..55ef2f548c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodWithSameNameAsEnclosingClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/MethodWithSameNameAsEnclosingClassRule.java @@ -1,25 +1,25 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.naming; - -import java.util.List; - -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class MethodWithSameNameAsEnclosingClassRule extends AbstractJavaRule { - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - List methods = node.findDescendantsOfType(ASTMethodDeclarator.class); - for (ASTMethodDeclarator m : methods) { - if (m.hasImageEqualTo(node.getImage())) { - addViolation(data, m); - } - } - return super.visit(node, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.naming; + +import java.util.List; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class MethodWithSameNameAsEnclosingClassRule extends AbstractJavaRule { + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + List methods = node.findDescendantsOfType(ASTMethodDeclarator.class); + for (ASTMethodDeclarator m : methods) { + if (m.hasImageEqualTo(node.getImage())) { + addViolation(data, m); + } + } + return super.visit(node, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/VariableNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/VariableNamingConventionsRule.java index 39695b1aad..c190b2a621 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/VariableNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/naming/VariableNamingConventionsRule.java @@ -1,246 +1,246 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.naming; - -import net.sourceforge.pmd.PropertyDescriptor; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; -import net.sourceforge.pmd.util.CollectionUtil; - -public class VariableNamingConventionsRule extends AbstractJavaRule { - - private boolean checkMembers; - private boolean checkLocals; - private boolean checkParameters; - private boolean checkNativeMethodParameters; - private String[] staticPrefixes; - private String[] staticSuffixes; - private String[] memberPrefixes; - private String[] memberSuffixes; - private String[] localPrefixes; - private String[] localSuffixes; - private String[] parameterPrefixes; - private String[] parameterSuffixes; - - private static final BooleanProperty CHECK_MEMBERS_DESCRIPTOR = new BooleanProperty("checkMembers", - "Check member variables", true, 1.0f); - - private static final BooleanProperty CHECK_LOCALS_DESCRIPTOR = new BooleanProperty("checkLocals", - "Check local variables", true, 2.0f); - - private static final BooleanProperty CHECK_PARAMETERS_DESCRIPTOR = new BooleanProperty("checkParameters", - "Check constructor and method parameter variables", true, 3.0f); - - private static final BooleanProperty CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR = new BooleanProperty( - "checkNativeMethodParameters", "Check method parameter of native methods", true, 3.5f); - - private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix", - "Static variable prefixes", new String[] { "" }, 4.0f, ','); - - private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix", - "Static variable suffixes", new String[] { "" }, 5.0f, ','); - - private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix", - "Member variable prefixes", new String[] { "" }, 6.0f, ','); - - private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix", - "Member variable suffixes", new String[] { "" }, 7.0f, ','); - - private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix", - "Local variable prefixes", new String[] { "" }, 8.0f, ','); - - private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix", - "Local variable suffixes", new String[] { "" }, 9.0f, ','); - - private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix", - "Method parameter variable prefixes", new String[] { "" }, 10.0f, ','); - - private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix", - "Method parameter variable suffixes", new String[] { "" }, 11.0f, ','); - - public VariableNamingConventionsRule() { - definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR); - definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR); - definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR); - definePropertyDescriptor(CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR); - definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR); - } - - public Object visit(ASTCompilationUnit node, Object data) { - init(); - return super.visit(node, data); - } - - protected void init() { - checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR); - checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR); - checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR); - checkNativeMethodParameters = getProperty(CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR); - staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR); - staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR); - memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR); - memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR); - localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR); - localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR); - parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR); - parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR); - } - - public Object visit(ASTFieldDeclaration node, Object data) { - if (!checkMembers) { - return data; - } - boolean isStatic = node.isStatic(); - boolean isFinal = node.isFinal(); - - Node type = node.jjtGetParent().jjtGetParent().jjtGetParent(); - // Anything from an interface is necessarily static and final - // Anything inside an annotation type is also static and final - if (type instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) type).isInterface() - || type instanceof ASTAnnotationTypeDeclaration) { - isStatic = true; - isFinal = true; - } - return checkVariableDeclarators(node.isStatic() ? staticPrefixes : memberPrefixes, - isStatic ? staticSuffixes : memberSuffixes, node, isStatic, isFinal, data); - } - - public Object visit(ASTLocalVariableDeclaration node, Object data) { - if (!checkLocals) { - return data; - } - return checkVariableDeclarators(localPrefixes, localSuffixes, node, false, node.isFinal(), data); - } - - public Object visit(ASTFormalParameters node, Object data) { - if (!checkParameters) { - return data; - } - ASTMethodDeclaration methodDeclaration = node.getFirstParentOfType(ASTMethodDeclaration.class); - if (!checkNativeMethodParameters && methodDeclaration.isNative()) { - return data; - } - - for (ASTFormalParameter formalParameter : node.findChildrenOfType(ASTFormalParameter.class)) { - for (ASTVariableDeclaratorId variableDeclaratorId : formalParameter - .findChildrenOfType(ASTVariableDeclaratorId.class)) { - checkVariableDeclaratorId(parameterPrefixes, parameterSuffixes, node, false, formalParameter.isFinal(), - variableDeclaratorId, data); - } - } - return data; - } - - private Object checkVariableDeclarators(String[] prefixes, String[] suffixes, Node root, boolean isStatic, - boolean isFinal, Object data) { - for (ASTVariableDeclarator variableDeclarator : root.findChildrenOfType(ASTVariableDeclarator.class)) { - for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclarator - .findChildrenOfType(ASTVariableDeclaratorId.class)) { - checkVariableDeclaratorId(prefixes, suffixes, root, isStatic, isFinal, variableDeclaratorId, data); - } - } - return data; - } - - private Object checkVariableDeclaratorId(String[] prefixes, String[] suffixes, Node root, boolean isStatic, - boolean isFinal, ASTVariableDeclaratorId variableDeclaratorId, Object data) { - - // Get the variable name - String varName = variableDeclaratorId.getImage(); - - // Skip serialVersionUID - if ("serialVersionUID".equals(varName)) { - return data; - } - - // Static finals should be uppercase - if (isStatic && isFinal) { - if (!varName.equals(varName.toUpperCase())) { - addViolationWithMessage(data, variableDeclaratorId, - "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.", - new Object[] { varName }); - } - return data; - } else if (!isFinal) { - String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes); - - if (normalizedVarName.indexOf('_') >= 0) { - addViolationWithMessage(data, variableDeclaratorId, - "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.", - new Object[] { varName }); - } - if (Character.isUpperCase(varName.charAt(0))) { - addViolationWithMessage(data, variableDeclaratorId, - "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.", - new Object[] { varName }); - } - } - return data; - } - - private String normalizeVariableName(String varName, String[] prefixes, String[] suffixes) { - return stripSuffix(stripPrefix(varName, prefixes), suffixes); - } - - private String stripSuffix(String varName, String[] suffixes) { - if (suffixes != null) { - for (int i = 0; i < suffixes.length; i++) { - if (varName.endsWith(suffixes[i])) { - varName = varName.substring(0, varName.length() - suffixes[i].length()); - break; - } - } - } - return varName; - } - - private String stripPrefix(String varName, String[] prefixes) { - if (prefixes != null) { - for (int i = 0; i < prefixes.length; i++) { - if (varName.startsWith(prefixes[i])) { - return varName.substring(prefixes[i].length()); - } - } - } - return varName; - } - - public boolean hasPrefixesOrSuffixes() { - - for (PropertyDescriptor desc : getPropertyDescriptors()) { - if (desc instanceof StringMultiProperty) { - String[] values = getProperty((StringMultiProperty) desc); - if (CollectionUtil.isNotEmpty(values)) { - return true; - } - } - } - return false; - } - - public String dysfunctionReason() { - return hasPrefixesOrSuffixes() ? null : "No prefixes or suffixes specified"; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.naming; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; +import net.sourceforge.pmd.util.CollectionUtil; + +public class VariableNamingConventionsRule extends AbstractJavaRule { + + private boolean checkMembers; + private boolean checkLocals; + private boolean checkParameters; + private boolean checkNativeMethodParameters; + private String[] staticPrefixes; + private String[] staticSuffixes; + private String[] memberPrefixes; + private String[] memberSuffixes; + private String[] localPrefixes; + private String[] localSuffixes; + private String[] parameterPrefixes; + private String[] parameterSuffixes; + + private static final BooleanProperty CHECK_MEMBERS_DESCRIPTOR = new BooleanProperty("checkMembers", + "Check member variables", true, 1.0f); + + private static final BooleanProperty CHECK_LOCALS_DESCRIPTOR = new BooleanProperty("checkLocals", + "Check local variables", true, 2.0f); + + private static final BooleanProperty CHECK_PARAMETERS_DESCRIPTOR = new BooleanProperty("checkParameters", + "Check constructor and method parameter variables", true, 3.0f); + + private static final BooleanProperty CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR = new BooleanProperty( + "checkNativeMethodParameters", "Check method parameter of native methods", true, 3.5f); + + private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix", + "Static variable prefixes", new String[] { "" }, 4.0f, ','); + + private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix", + "Static variable suffixes", new String[] { "" }, 5.0f, ','); + + private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix", + "Member variable prefixes", new String[] { "" }, 6.0f, ','); + + private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix", + "Member variable suffixes", new String[] { "" }, 7.0f, ','); + + private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix", + "Local variable prefixes", new String[] { "" }, 8.0f, ','); + + private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix", + "Local variable suffixes", new String[] { "" }, 9.0f, ','); + + private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix", + "Method parameter variable prefixes", new String[] { "" }, 10.0f, ','); + + private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix", + "Method parameter variable suffixes", new String[] { "" }, 11.0f, ','); + + public VariableNamingConventionsRule() { + definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR); + definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR); + definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR); + definePropertyDescriptor(CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR); + definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR); + definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR); + definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR); + definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR); + definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR); + } + + public Object visit(ASTCompilationUnit node, Object data) { + init(); + return super.visit(node, data); + } + + protected void init() { + checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR); + checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR); + checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR); + checkNativeMethodParameters = getProperty(CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR); + staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR); + staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR); + memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR); + memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR); + localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR); + localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR); + parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR); + parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR); + } + + public Object visit(ASTFieldDeclaration node, Object data) { + if (!checkMembers) { + return data; + } + boolean isStatic = node.isStatic(); + boolean isFinal = node.isFinal(); + + Node type = node.jjtGetParent().jjtGetParent().jjtGetParent(); + // Anything from an interface is necessarily static and final + // Anything inside an annotation type is also static and final + if (type instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) type).isInterface() + || type instanceof ASTAnnotationTypeDeclaration) { + isStatic = true; + isFinal = true; + } + return checkVariableDeclarators(node.isStatic() ? staticPrefixes : memberPrefixes, + isStatic ? staticSuffixes : memberSuffixes, node, isStatic, isFinal, data); + } + + public Object visit(ASTLocalVariableDeclaration node, Object data) { + if (!checkLocals) { + return data; + } + return checkVariableDeclarators(localPrefixes, localSuffixes, node, false, node.isFinal(), data); + } + + public Object visit(ASTFormalParameters node, Object data) { + if (!checkParameters) { + return data; + } + ASTMethodDeclaration methodDeclaration = node.getFirstParentOfType(ASTMethodDeclaration.class); + if (!checkNativeMethodParameters && methodDeclaration.isNative()) { + return data; + } + + for (ASTFormalParameter formalParameter : node.findChildrenOfType(ASTFormalParameter.class)) { + for (ASTVariableDeclaratorId variableDeclaratorId : formalParameter + .findChildrenOfType(ASTVariableDeclaratorId.class)) { + checkVariableDeclaratorId(parameterPrefixes, parameterSuffixes, node, false, formalParameter.isFinal(), + variableDeclaratorId, data); + } + } + return data; + } + + private Object checkVariableDeclarators(String[] prefixes, String[] suffixes, Node root, boolean isStatic, + boolean isFinal, Object data) { + for (ASTVariableDeclarator variableDeclarator : root.findChildrenOfType(ASTVariableDeclarator.class)) { + for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclarator + .findChildrenOfType(ASTVariableDeclaratorId.class)) { + checkVariableDeclaratorId(prefixes, suffixes, root, isStatic, isFinal, variableDeclaratorId, data); + } + } + return data; + } + + private Object checkVariableDeclaratorId(String[] prefixes, String[] suffixes, Node root, boolean isStatic, + boolean isFinal, ASTVariableDeclaratorId variableDeclaratorId, Object data) { + + // Get the variable name + String varName = variableDeclaratorId.getImage(); + + // Skip serialVersionUID + if ("serialVersionUID".equals(varName)) { + return data; + } + + // Static finals should be uppercase + if (isStatic && isFinal) { + if (!varName.equals(varName.toUpperCase())) { + addViolationWithMessage(data, variableDeclaratorId, + "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.", + new Object[] { varName }); + } + return data; + } else if (!isFinal) { + String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes); + + if (normalizedVarName.indexOf('_') >= 0) { + addViolationWithMessage(data, variableDeclaratorId, + "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.", + new Object[] { varName }); + } + if (Character.isUpperCase(varName.charAt(0))) { + addViolationWithMessage(data, variableDeclaratorId, + "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.", + new Object[] { varName }); + } + } + return data; + } + + private String normalizeVariableName(String varName, String[] prefixes, String[] suffixes) { + return stripSuffix(stripPrefix(varName, prefixes), suffixes); + } + + private String stripSuffix(String varName, String[] suffixes) { + if (suffixes != null) { + for (int i = 0; i < suffixes.length; i++) { + if (varName.endsWith(suffixes[i])) { + varName = varName.substring(0, varName.length() - suffixes[i].length()); + break; + } + } + } + return varName; + } + + private String stripPrefix(String varName, String[] prefixes) { + if (prefixes != null) { + for (int i = 0; i < prefixes.length; i++) { + if (varName.startsWith(prefixes[i])) { + return varName.substring(prefixes[i].length()); + } + } + } + return varName; + } + + public boolean hasPrefixesOrSuffixes() { + + for (PropertyDescriptor desc : getPropertyDescriptors()) { + if (desc instanceof StringMultiProperty) { + String[] values = getProperty((StringMultiProperty) desc); + if (CollectionUtil.isNotEmpty(values)) { + return true; + } + } + } + return false; + } + + public String dysfunctionReason() { + return hasPrefixesOrSuffixes() ? null : "No prefixes or suffixes specified"; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/PrematureDeclarationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/PrematureDeclarationRule.java index cc4467db7e..04edc4fc14 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/PrematureDeclarationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/PrematureDeclarationRule.java @@ -1,234 +1,234 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.optimizations; - -import java.util.ArrayList; -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTForInit; -import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.ast.AbstractJavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -/** - * Checks for variables in methods that are defined before they are really - * needed. A reference is deemed to be premature if it is created ahead of a - * block of code that doesn't use it that also has the ability to return or - * throw an exception. - * - * @author Brian Remedios - */ -public class PrematureDeclarationRule extends AbstractJavaRule { - - /** - * - * @param node - * ASTLocalVariableDeclaration - * @param data - * Object - * @return Object - * @see net.sourceforge.pmd.lang.java.ast.JavaParserVisitor#visit(ASTLocalVariableDeclaration, - * Object) - */ - public Object visit(ASTLocalVariableDeclaration node, Object data) { - - // is it part of a for-loop declaration? - if (node.jjtGetParent() instanceof ASTForInit) { - // yes, those don't count - return visit((AbstractJavaNode) node, data); - } - - String varName = varNameIn(node); - - AbstractJavaNode grandparent = (AbstractJavaNode) node.jjtGetParent().jjtGetParent(); - - List nextBlocks = blocksAfter(grandparent, node); - - for (ASTBlockStatement block : nextBlocks) { - if (hasReferencesIn(block, varName) || isLambda(block)) { - break; - } - - if (hasExit(block)) { - addViolation(data, node, varName); - break; - } - } - - return visit((AbstractJavaNode) node, data); - } - - private boolean isLambda(ASTBlockStatement block) { - return block.getFirstParentOfType(ASTLambdaExpression.class) != null; - } - - /** - * Return whether a class of the specified type exists between the node - * argument and the topParent argument. - * - * @param node - * Node - * @param intermediateParentClass - * Class - * @param topParent - * Node - * @return boolean - */ - public static boolean hasAsParentBetween(Node node, Class intermediateParentClass, Node topParent) { - - Node currentParent = node.jjtGetParent(); - - while (!currentParent.equals(topParent)) { - currentParent = currentParent.jjtGetParent(); - if (currentParent.getClass().equals(intermediateParentClass)) { - return true; - } - } - return false; - } - - /** - * Returns whether the block contains a return call or throws an exception. - * Exclude blocks that have these things as part of an inner class. - * - * @param block - * ASTBlockStatement - * @return boolean - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private boolean hasExit(ASTBlockStatement block) { - - List exitBlocks = block.findDescendantsOfType(ASTReturnStatement.class); - exitBlocks.addAll(block.findDescendantsOfType(ASTThrowStatement.class)); - - if (exitBlocks.isEmpty()) { - return false; - } - - // now check to see if the ones we have are part of a method on a - // declared inner class - // or part of a lambda expression - boolean result = false; - for (int i = 0; i < exitBlocks.size(); i++) { - Node exitNode = (Node) exitBlocks.get(i); - if (!hasAsParentBetween(exitNode, ASTMethodDeclaration.class, block) - && !hasAsParentBetween(exitNode, ASTLambdaExpression.class, block)) { - result = true; - break; - } - } - - return result; - } - - /** - * Returns whether the variable is mentioned within the statement block or - * not. - * - * @param block - * ASTBlockStatement - * @param varName - * String - * @return boolean - */ - private static boolean hasReferencesIn(ASTBlockStatement block, String varName) { - - List names = block.findDescendantsOfType(ASTName.class); - - for (ASTName name : names) { - if (isReference(varName, name.getImage())) { - return true; - } - } - return false; - } - - /** - * Return whether the shortName is part of the compound name by itself or as - * a method call receiver. - * - * @param shortName - * String - * @param compoundName - * String - * @return boolean - */ - private static boolean isReference(String shortName, String compoundName) { - - int dotPos = compoundName.indexOf('.'); - - return dotPos < 0 ? shortName.equals(compoundName) : shortName.endsWith(compoundName.substring(0, dotPos)); - } - - /** - * Return the name of the variable we just assigned something to. - * - * @param node - * ASTLocalVariableDeclaration - * @return String - */ - private static String varNameIn(ASTLocalVariableDeclaration node) { - ASTVariableDeclarator declarator = node.getFirstChildOfType(ASTVariableDeclarator.class); - return ((ASTVariableDeclaratorId) declarator.jjtGetChild(0)).getImage(); - } - - /** - * Returns the index of the node block in relation to its siblings. - * - * @param block - * SimpleJavaNode - * @param node - * Node - * @return int - */ - private static int indexOf(AbstractJavaNode block, Node node) { - - int count = block.jjtGetNumChildren(); - - for (int i = 0; i < count; i++) { - if (node == block.jjtGetChild(i)) { - return i; - } - } - - return -1; - } - - /** - * Returns all the blocks found right after the node supplied within the its - * current scope. - * - * @param block - * SimpleJavaNode - * @param node - * SimpleNode - * @return List - */ - private static List blocksAfter(AbstractJavaNode block, AbstractJavaNode node) { - - int count = block.jjtGetNumChildren(); - int start = indexOf(block, node.jjtGetParent()) + 1; - - List nextBlocks = new ArrayList<>(count); - - for (int i = start; i < count; i++) { - Node maybeBlock = block.jjtGetChild(i); - if (maybeBlock instanceof ASTBlockStatement) { - nextBlocks.add((ASTBlockStatement) maybeBlock); - } - } - - return nextBlocks; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.optimizations; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; +import net.sourceforge.pmd.lang.java.ast.ASTForInit; +import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.ast.AbstractJavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +/** + * Checks for variables in methods that are defined before they are really + * needed. A reference is deemed to be premature if it is created ahead of a + * block of code that doesn't use it that also has the ability to return or + * throw an exception. + * + * @author Brian Remedios + */ +public class PrematureDeclarationRule extends AbstractJavaRule { + + /** + * + * @param node + * ASTLocalVariableDeclaration + * @param data + * Object + * @return Object + * @see net.sourceforge.pmd.lang.java.ast.JavaParserVisitor#visit(ASTLocalVariableDeclaration, + * Object) + */ + public Object visit(ASTLocalVariableDeclaration node, Object data) { + + // is it part of a for-loop declaration? + if (node.jjtGetParent() instanceof ASTForInit) { + // yes, those don't count + return visit((AbstractJavaNode) node, data); + } + + String varName = varNameIn(node); + + AbstractJavaNode grandparent = (AbstractJavaNode) node.jjtGetParent().jjtGetParent(); + + List nextBlocks = blocksAfter(grandparent, node); + + for (ASTBlockStatement block : nextBlocks) { + if (hasReferencesIn(block, varName) || isLambda(block)) { + break; + } + + if (hasExit(block)) { + addViolation(data, node, varName); + break; + } + } + + return visit((AbstractJavaNode) node, data); + } + + private boolean isLambda(ASTBlockStatement block) { + return block.getFirstParentOfType(ASTLambdaExpression.class) != null; + } + + /** + * Return whether a class of the specified type exists between the node + * argument and the topParent argument. + * + * @param node + * Node + * @param intermediateParentClass + * Class + * @param topParent + * Node + * @return boolean + */ + public static boolean hasAsParentBetween(Node node, Class intermediateParentClass, Node topParent) { + + Node currentParent = node.jjtGetParent(); + + while (!currentParent.equals(topParent)) { + currentParent = currentParent.jjtGetParent(); + if (currentParent.getClass().equals(intermediateParentClass)) { + return true; + } + } + return false; + } + + /** + * Returns whether the block contains a return call or throws an exception. + * Exclude blocks that have these things as part of an inner class. + * + * @param block + * ASTBlockStatement + * @return boolean + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private boolean hasExit(ASTBlockStatement block) { + + List exitBlocks = block.findDescendantsOfType(ASTReturnStatement.class); + exitBlocks.addAll(block.findDescendantsOfType(ASTThrowStatement.class)); + + if (exitBlocks.isEmpty()) { + return false; + } + + // now check to see if the ones we have are part of a method on a + // declared inner class + // or part of a lambda expression + boolean result = false; + for (int i = 0; i < exitBlocks.size(); i++) { + Node exitNode = (Node) exitBlocks.get(i); + if (!hasAsParentBetween(exitNode, ASTMethodDeclaration.class, block) + && !hasAsParentBetween(exitNode, ASTLambdaExpression.class, block)) { + result = true; + break; + } + } + + return result; + } + + /** + * Returns whether the variable is mentioned within the statement block or + * not. + * + * @param block + * ASTBlockStatement + * @param varName + * String + * @return boolean + */ + private static boolean hasReferencesIn(ASTBlockStatement block, String varName) { + + List names = block.findDescendantsOfType(ASTName.class); + + for (ASTName name : names) { + if (isReference(varName, name.getImage())) { + return true; + } + } + return false; + } + + /** + * Return whether the shortName is part of the compound name by itself or as + * a method call receiver. + * + * @param shortName + * String + * @param compoundName + * String + * @return boolean + */ + private static boolean isReference(String shortName, String compoundName) { + + int dotPos = compoundName.indexOf('.'); + + return dotPos < 0 ? shortName.equals(compoundName) : shortName.endsWith(compoundName.substring(0, dotPos)); + } + + /** + * Return the name of the variable we just assigned something to. + * + * @param node + * ASTLocalVariableDeclaration + * @return String + */ + private static String varNameIn(ASTLocalVariableDeclaration node) { + ASTVariableDeclarator declarator = node.getFirstChildOfType(ASTVariableDeclarator.class); + return ((ASTVariableDeclaratorId) declarator.jjtGetChild(0)).getImage(); + } + + /** + * Returns the index of the node block in relation to its siblings. + * + * @param block + * SimpleJavaNode + * @param node + * Node + * @return int + */ + private static int indexOf(AbstractJavaNode block, Node node) { + + int count = block.jjtGetNumChildren(); + + for (int i = 0; i < count; i++) { + if (node == block.jjtGetChild(i)) { + return i; + } + } + + return -1; + } + + /** + * Returns all the blocks found right after the node supplied within the its + * current scope. + * + * @param block + * SimpleJavaNode + * @param node + * SimpleNode + * @return List + */ + private static List blocksAfter(AbstractJavaNode block, AbstractJavaNode node) { + + int count = block.jjtGetNumChildren(); + int start = indexOf(block, node.jjtGetParent()) + 1; + + List nextBlocks = new ArrayList<>(count); + + for (int i = start; i < count; i++) { + Node maybeBlock = block.jjtGetChild(i); + if (maybeBlock instanceof ASTBlockStatement) { + nextBlocks.add((ASTBlockStatement) maybeBlock); + } + } + + return nextBlocks; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/RedundantFieldInitializerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/RedundantFieldInitializerRule.java index d63cd59634..3cee0a6bd4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/RedundantFieldInitializerRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/optimizations/RedundantFieldInitializerRule.java @@ -1,178 +1,178 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.optimizations; - -import java.math.BigInteger; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; -import net.sourceforge.pmd.lang.java.ast.ASTExpression; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -/** - * Detects redundant field initializers, i.e. the field initializer expressions - * the JVM would assign by default. - * - * @author lucian.ciufudean@gmail.com - * @since Apr 10, 2009 - */ -public class RedundantFieldInitializerRule extends AbstractJavaRule { - - public RedundantFieldInitializerRule() { - addRuleChainVisit(ASTFieldDeclaration.class); - } - - public Object visit(ASTFieldDeclaration fieldDeclaration, Object data) { - // Finals can only be initialized once. - if (fieldDeclaration.isFinal()) { - return data; - } - - // Look for a match to the following XPath: - // VariableDeclarator/VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal - for (ASTVariableDeclarator variableDeclarator : fieldDeclaration - .findChildrenOfType(ASTVariableDeclarator.class)) { - if (variableDeclarator.jjtGetNumChildren() > 1) { - final Node variableInitializer = variableDeclarator.jjtGetChild(1); - if (variableInitializer.jjtGetChild(0) instanceof ASTExpression) { - final Node expression = variableInitializer.jjtGetChild(0); - final Node primaryExpression; - if (expression.jjtGetNumChildren() == 1) { - if (expression.jjtGetChild(0) instanceof ASTPrimaryExpression) { - primaryExpression = expression.jjtGetChild(0); - } else if (expression.jjtGetChild(0) instanceof ASTCastExpression - && expression.jjtGetChild(0).jjtGetChild(1) instanceof ASTPrimaryExpression) { - primaryExpression = expression.jjtGetChild(0).jjtGetChild(1); - } else { - continue; - } - } else { - continue; - } - final Node primaryPrefix = primaryExpression.jjtGetChild(0); - if (primaryPrefix.jjtGetNumChildren() == 1 && primaryPrefix.jjtGetChild(0) instanceof ASTLiteral) { - final ASTLiteral literal = (ASTLiteral) primaryPrefix.jjtGetChild(0); - if (isRef(fieldDeclaration, variableDeclarator)) { - // Reference type - if (literal.jjtGetNumChildren() == 1 && literal.jjtGetChild(0) instanceof ASTNullLiteral) { - addViolation(data, variableDeclarator); - } - } else { - // Primitive type - if (literal.jjtGetNumChildren() == 1 - && literal.jjtGetChild(0) instanceof ASTBooleanLiteral) { - // boolean type - ASTBooleanLiteral booleanLiteral = (ASTBooleanLiteral) literal.jjtGetChild(0); - if (!booleanLiteral.isTrue()) { - addViolation(data, variableDeclarator); - } - } else if (literal.jjtGetNumChildren() == 0) { - // numeric type - // Note: Not catching NumberFormatException, as - // it shouldn't be happening on valid source - // code. - Number value = -1; - if (literal.isIntLiteral()) { - value = parseInteger(literal.getImage()); - } else if (literal.isLongLiteral()) { - String s = literal.getImage(); - // remove the ending "l" or "L" for long - // values - s = s.substring(0, s.length() - 1); - value = parseInteger(s); - } else if (literal.isFloatLiteral()) { - String s = literal.getImage(); - // remove the ending "f" or "F" for float - // values - s = s.substring(0, s.length() - 1); - value = Float.valueOf(s); - } else if (literal.isDoubleLiteral()) { - value = Double.valueOf(literal.getImage()); - } else if (literal.isCharLiteral()) { - value = (int) literal.getImage().charAt(1); - } - - if (value.doubleValue() == 0) { - addViolation(data, variableDeclarator); - } - } - } - } - } - } - } - - return data; - } - - /** - * Checks if a FieldDeclaration is a reference type (includes arrays). The - * reference information is in the FieldDeclaration for this example: - * - *
-     * int[] ia1
-     * 
- * - * and in the VariableDeclarator for this example: - * - *
-     * int ia2[];
-     * 
- * - * . - * - * @param fieldDeclaration - * the field to check. - * @param variableDeclarator - * the variable declarator to check. - * @return true if the field is a reference. false - * otherwise. - */ - private boolean isRef(ASTFieldDeclaration fieldDeclaration, ASTVariableDeclarator variableDeclarator) { - Node type = fieldDeclaration.jjtGetChild(0).jjtGetChild(0); - if (type instanceof ASTReferenceType) { - // Reference type, array or otherwise - return true; - } else { - // Primitive array? - return ((ASTVariableDeclaratorId) variableDeclarator.jjtGetChild(0)).isArray(); - } - } - - private void addViolation(Object data, ASTVariableDeclarator variableDeclarator) { - super.addViolation(data, variableDeclarator, variableDeclarator.jjtGetChild(0).getImage()); - } - - private Number parseInteger(String s) { - boolean negative = false; - String number = s; - if (number.charAt(0) == '-') { - negative = true; - number = number.substring(1); - } - BigInteger result; - if (number.startsWith("0x") || number.startsWith("0X")) { - result = new BigInteger(number.substring(2).replaceAll("_", ""), 16); - } else if (number.startsWith("0b") || number.startsWith("0B")) { - result = new BigInteger(number.substring(2).replaceAll("_", ""), 8); - } else if (number.charAt(0) == '0' && number.length() > 1) { - result = new BigInteger(number.substring(1).replaceAll("_", ""), 8); - } else { - result = new BigInteger(number.replaceAll("_", "")); - } - if (negative) { - result = result.negate(); - } - return result; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.optimizations; + +import java.math.BigInteger; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +/** + * Detects redundant field initializers, i.e. the field initializer expressions + * the JVM would assign by default. + * + * @author lucian.ciufudean@gmail.com + * @since Apr 10, 2009 + */ +public class RedundantFieldInitializerRule extends AbstractJavaRule { + + public RedundantFieldInitializerRule() { + addRuleChainVisit(ASTFieldDeclaration.class); + } + + public Object visit(ASTFieldDeclaration fieldDeclaration, Object data) { + // Finals can only be initialized once. + if (fieldDeclaration.isFinal()) { + return data; + } + + // Look for a match to the following XPath: + // VariableDeclarator/VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal + for (ASTVariableDeclarator variableDeclarator : fieldDeclaration + .findChildrenOfType(ASTVariableDeclarator.class)) { + if (variableDeclarator.jjtGetNumChildren() > 1) { + final Node variableInitializer = variableDeclarator.jjtGetChild(1); + if (variableInitializer.jjtGetChild(0) instanceof ASTExpression) { + final Node expression = variableInitializer.jjtGetChild(0); + final Node primaryExpression; + if (expression.jjtGetNumChildren() == 1) { + if (expression.jjtGetChild(0) instanceof ASTPrimaryExpression) { + primaryExpression = expression.jjtGetChild(0); + } else if (expression.jjtGetChild(0) instanceof ASTCastExpression + && expression.jjtGetChild(0).jjtGetChild(1) instanceof ASTPrimaryExpression) { + primaryExpression = expression.jjtGetChild(0).jjtGetChild(1); + } else { + continue; + } + } else { + continue; + } + final Node primaryPrefix = primaryExpression.jjtGetChild(0); + if (primaryPrefix.jjtGetNumChildren() == 1 && primaryPrefix.jjtGetChild(0) instanceof ASTLiteral) { + final ASTLiteral literal = (ASTLiteral) primaryPrefix.jjtGetChild(0); + if (isRef(fieldDeclaration, variableDeclarator)) { + // Reference type + if (literal.jjtGetNumChildren() == 1 && literal.jjtGetChild(0) instanceof ASTNullLiteral) { + addViolation(data, variableDeclarator); + } + } else { + // Primitive type + if (literal.jjtGetNumChildren() == 1 + && literal.jjtGetChild(0) instanceof ASTBooleanLiteral) { + // boolean type + ASTBooleanLiteral booleanLiteral = (ASTBooleanLiteral) literal.jjtGetChild(0); + if (!booleanLiteral.isTrue()) { + addViolation(data, variableDeclarator); + } + } else if (literal.jjtGetNumChildren() == 0) { + // numeric type + // Note: Not catching NumberFormatException, as + // it shouldn't be happening on valid source + // code. + Number value = -1; + if (literal.isIntLiteral()) { + value = parseInteger(literal.getImage()); + } else if (literal.isLongLiteral()) { + String s = literal.getImage(); + // remove the ending "l" or "L" for long + // values + s = s.substring(0, s.length() - 1); + value = parseInteger(s); + } else if (literal.isFloatLiteral()) { + String s = literal.getImage(); + // remove the ending "f" or "F" for float + // values + s = s.substring(0, s.length() - 1); + value = Float.valueOf(s); + } else if (literal.isDoubleLiteral()) { + value = Double.valueOf(literal.getImage()); + } else if (literal.isCharLiteral()) { + value = (int) literal.getImage().charAt(1); + } + + if (value.doubleValue() == 0) { + addViolation(data, variableDeclarator); + } + } + } + } + } + } + } + + return data; + } + + /** + * Checks if a FieldDeclaration is a reference type (includes arrays). The + * reference information is in the FieldDeclaration for this example: + * + *
+     * int[] ia1
+     * 
+ * + * and in the VariableDeclarator for this example: + * + *
+     * int ia2[];
+     * 
+ * + * . + * + * @param fieldDeclaration + * the field to check. + * @param variableDeclarator + * the variable declarator to check. + * @return true if the field is a reference. false + * otherwise. + */ + private boolean isRef(ASTFieldDeclaration fieldDeclaration, ASTVariableDeclarator variableDeclarator) { + Node type = fieldDeclaration.jjtGetChild(0).jjtGetChild(0); + if (type instanceof ASTReferenceType) { + // Reference type, array or otherwise + return true; + } else { + // Primitive array? + return ((ASTVariableDeclaratorId) variableDeclarator.jjtGetChild(0)).isArray(); + } + } + + private void addViolation(Object data, ASTVariableDeclarator variableDeclarator) { + super.addViolation(data, variableDeclarator, variableDeclarator.jjtGetChild(0).getImage()); + } + + private Number parseInteger(String s) { + boolean negative = false; + String number = s; + if (number.charAt(0) == '-') { + negative = true; + number = number.substring(1); + } + BigInteger result; + if (number.startsWith("0x") || number.startsWith("0X")) { + result = new BigInteger(number.substring(2).replaceAll("_", ""), 16); + } else if (number.startsWith("0b") || number.startsWith("0B")) { + result = new BigInteger(number.substring(2).replaceAll("_", ""), 8); + } else if (number.charAt(0) == '0' && number.length() > 1) { + result = new BigInteger(number.substring(1).replaceAll("_", ""), 8); + } else { + result = new BigInteger(number.replaceAll("_", "")); + } + if (negative) { + result = result.negate(); + } + return result; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/ExceptionAsFlowControlRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/ExceptionAsFlowControlRule.java index 1c8c28118e..231a4a04f5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/ExceptionAsFlowControlRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/ExceptionAsFlowControlRule.java @@ -1,47 +1,47 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.strictexception; - -import java.util.List; - -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; -import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -/** - * Catches the use of exception statements as a flow control device. - * - * @author Will Sargent - */ -public class ExceptionAsFlowControlRule extends AbstractJavaRule { - - @Override - public Object visit(ASTThrowStatement node, Object data) { - ASTTryStatement parent = node.getFirstParentOfType(ASTTryStatement.class); - if (parent == null) { - return data; - } - for (parent = parent.getFirstParentOfType(ASTTryStatement.class); parent != null; parent = parent - .getFirstParentOfType(ASTTryStatement.class)) { - - List list = parent.findDescendantsOfType(ASTCatchStatement.class); - for (ASTCatchStatement catchStmt : list) { - ASTFormalParameter fp = (ASTFormalParameter) catchStmt.jjtGetChild(0); - ASTType type = fp.getFirstDescendantOfType(ASTType.class); - ASTClassOrInterfaceType name = type.getFirstDescendantOfType(ASTClassOrInterfaceType.class); - if (node.getFirstClassOrInterfaceTypeImage() != null - && node.getFirstClassOrInterfaceTypeImage().equals(name.getImage())) { - addViolation(data, name); - } - } - } - return data; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.strictexception; + +import java.util.List; + +import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; +import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +/** + * Catches the use of exception statements as a flow control device. + * + * @author Will Sargent + */ +public class ExceptionAsFlowControlRule extends AbstractJavaRule { + + @Override + public Object visit(ASTThrowStatement node, Object data) { + ASTTryStatement parent = node.getFirstParentOfType(ASTTryStatement.class); + if (parent == null) { + return data; + } + for (parent = parent.getFirstParentOfType(ASTTryStatement.class); parent != null; parent = parent + .getFirstParentOfType(ASTTryStatement.class)) { + + List list = parent.findDescendantsOfType(ASTCatchStatement.class); + for (ASTCatchStatement catchStmt : list) { + ASTFormalParameter fp = (ASTFormalParameter) catchStmt.jjtGetChild(0); + ASTType type = fp.getFirstDescendantOfType(ASTType.class); + ASTClassOrInterfaceType name = type.getFirstDescendantOfType(ASTClassOrInterfaceType.class); + if (node.getFirstClassOrInterfaceTypeImage() != null + && node.getFirstClassOrInterfaceTypeImage().equals(name.getImage())) { + addViolation(data, name); + } + } + } + return data; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/SignatureDeclareThrowsExceptionRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/SignatureDeclareThrowsExceptionRule.java index f706f556a7..0c36c5a87f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/SignatureDeclareThrowsExceptionRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/strictexception/SignatureDeclareThrowsExceptionRule.java @@ -1,116 +1,116 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.strictexception; - -import java.util.Collections; -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTNameList; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -/** - * - * @author Trond Andersen - * @version 1.0 - * @since 1.2 - */ - -public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule { - - private boolean junitImported; - - @Override - public Object visit(ASTCompilationUnit node, Object o) { - junitImported = false; - return super.visit(node, o); - } - - @Override - public Object visit(ASTImportDeclaration node, Object o) { - if (node.getImportedName().indexOf("junit") != -1) { - junitImported = true; - } - return super.visit(node, o); - } - - @Override - public Object visit(ASTMethodDeclaration methodDeclaration, Object o) { - if ((methodDeclaration.getMethodName().equals("setUp") || methodDeclaration.getMethodName().equals("tearDown")) - && junitImported) { - return super.visit(methodDeclaration, o); - } - - if (methodDeclaration.getMethodName().startsWith("test")) { - return super.visit(methodDeclaration, o); - } - - List exceptionList = Collections.emptyList(); - ASTNameList nameList = methodDeclaration.getFirstChildOfType(ASTNameList.class); - if (nameList != null) { - exceptionList = nameList.findDescendantsOfType(ASTName.class); - } - if (!exceptionList.isEmpty()) { - evaluateExceptions(exceptionList, o); - } - return super.visit(methodDeclaration, o); - } - - @Override - public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) { - List exceptionList = constructorDeclaration.findDescendantsOfType(ASTName.class); - if (!exceptionList.isEmpty()) { - evaluateExceptions(exceptionList, o); - } - return super.visit(constructorDeclaration, o); - } - - /** - * Checks all exceptions for possible violation on the exception - * declaration. - * - * @param exceptionList - * containing all exception for declaration - * @param context - */ - private void evaluateExceptions(List exceptionList, Object context) { - for (ASTName exception : exceptionList) { - if (hasDeclaredExceptionInSignature(exception)) { - addViolation(context, exception); - } - } - } - - /** - * Checks if the given value is defined as Exception and the - * parent is either a method or constructor declaration. - * - * @param exception - * to evaluate - * @return true if Exception is declared and has proper parents - */ - private boolean hasDeclaredExceptionInSignature(ASTName exception) { - return exception.hasImageEqualTo("Exception") && isParentSignatureDeclaration(exception); - } - - /** - * Checks if the given exception is declared in the method or constructor - * signature. - * - * @param exception - * to evaluate - * @return true if parent node is either a method or constructor declaration - */ - private boolean isParentSignatureDeclaration(ASTName exception) { - Node parent = exception.jjtGetParent().jjtGetParent(); - return parent instanceof ASTMethodDeclaration || parent instanceof ASTConstructorDeclaration; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.strictexception; + +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTNameList; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +/** + * + * @author Trond Andersen + * @version 1.0 + * @since 1.2 + */ + +public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule { + + private boolean junitImported; + + @Override + public Object visit(ASTCompilationUnit node, Object o) { + junitImported = false; + return super.visit(node, o); + } + + @Override + public Object visit(ASTImportDeclaration node, Object o) { + if (node.getImportedName().indexOf("junit") != -1) { + junitImported = true; + } + return super.visit(node, o); + } + + @Override + public Object visit(ASTMethodDeclaration methodDeclaration, Object o) { + if ((methodDeclaration.getMethodName().equals("setUp") || methodDeclaration.getMethodName().equals("tearDown")) + && junitImported) { + return super.visit(methodDeclaration, o); + } + + if (methodDeclaration.getMethodName().startsWith("test")) { + return super.visit(methodDeclaration, o); + } + + List exceptionList = Collections.emptyList(); + ASTNameList nameList = methodDeclaration.getFirstChildOfType(ASTNameList.class); + if (nameList != null) { + exceptionList = nameList.findDescendantsOfType(ASTName.class); + } + if (!exceptionList.isEmpty()) { + evaluateExceptions(exceptionList, o); + } + return super.visit(methodDeclaration, o); + } + + @Override + public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) { + List exceptionList = constructorDeclaration.findDescendantsOfType(ASTName.class); + if (!exceptionList.isEmpty()) { + evaluateExceptions(exceptionList, o); + } + return super.visit(constructorDeclaration, o); + } + + /** + * Checks all exceptions for possible violation on the exception + * declaration. + * + * @param exceptionList + * containing all exception for declaration + * @param context + */ + private void evaluateExceptions(List exceptionList, Object context) { + for (ASTName exception : exceptionList) { + if (hasDeclaredExceptionInSignature(exception)) { + addViolation(context, exception); + } + } + } + + /** + * Checks if the given value is defined as Exception and the + * parent is either a method or constructor declaration. + * + * @param exception + * to evaluate + * @return true if Exception is declared and has proper parents + */ + private boolean hasDeclaredExceptionInSignature(ASTName exception) { + return exception.hasImageEqualTo("Exception") && isParentSignatureDeclaration(exception); + } + + /** + * Checks if the given exception is declared in the method or constructor + * signature. + * + * @param exception + * to evaluate + * @return true if parent node is either a method or constructor declaration + */ + private boolean isParentSignatureDeclaration(ASTName exception) { + Node parent = exception.jjtGetParent().jjtGetParent(); + return parent instanceof ASTMethodDeclaration || parent instanceof ASTConstructorDeclaration; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UnnecessaryConversionTemporaryRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UnnecessaryConversionTemporaryRule.java index a5216919f8..2be78660f0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UnnecessaryConversionTemporaryRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UnnecessaryConversionTemporaryRule.java @@ -1,62 +1,62 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unnecessary; - -import java.util.Set; - -import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.util.CollectionUtil; - -public class UnnecessaryConversionTemporaryRule extends AbstractJavaRule { - - private boolean inPrimaryExpressionContext; - private ASTPrimaryExpression primary; - private boolean usingPrimitiveWrapperAllocation; - - private static final Set PRIMITIVE_WRAPPERS = CollectionUtil - .asSet(new String[] { "Integer", "Boolean", "Double", "Long", "Short", "Byte", "Float" }); - - public Object visit(ASTPrimaryExpression node, Object data) { - if (node.jjtGetNumChildren() == 0 || (node.jjtGetChild(0)).jjtGetNumChildren() == 0 - || !(node.jjtGetChild(0).jjtGetChild(0) instanceof ASTAllocationExpression)) { - return super.visit(node, data); - } - // TODO... hmmm... is this inPrimaryExpressionContext gibberish - // necessary? - inPrimaryExpressionContext = true; - primary = node; - super.visit(node, data); - inPrimaryExpressionContext = false; - usingPrimitiveWrapperAllocation = false; - return data; - } - - public Object visit(ASTAllocationExpression node, Object data) { - if (!inPrimaryExpressionContext || !(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) { - return super.visit(node, data); - } - if (!PRIMITIVE_WRAPPERS.contains(node.jjtGetChild(0).getImage())) { - return super.visit(node, data); - } - usingPrimitiveWrapperAllocation = true; - return super.visit(node, data); - } - - public Object visit(ASTPrimarySuffix node, Object data) { - if (inPrimaryExpressionContext && usingPrimitiveWrapperAllocation) { - if (node.hasImageEqualTo("toString")) { - if (node.jjtGetParent() == primary) { - addViolation(data, node); - } - } - } - return super.visit(node, data); - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unnecessary; + +import java.util.Set; + +import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.util.CollectionUtil; + +public class UnnecessaryConversionTemporaryRule extends AbstractJavaRule { + + private boolean inPrimaryExpressionContext; + private ASTPrimaryExpression primary; + private boolean usingPrimitiveWrapperAllocation; + + private static final Set PRIMITIVE_WRAPPERS = CollectionUtil + .asSet(new String[] { "Integer", "Boolean", "Double", "Long", "Short", "Byte", "Float" }); + + public Object visit(ASTPrimaryExpression node, Object data) { + if (node.jjtGetNumChildren() == 0 || (node.jjtGetChild(0)).jjtGetNumChildren() == 0 + || !(node.jjtGetChild(0).jjtGetChild(0) instanceof ASTAllocationExpression)) { + return super.visit(node, data); + } + // TODO... hmmm... is this inPrimaryExpressionContext gibberish + // necessary? + inPrimaryExpressionContext = true; + primary = node; + super.visit(node, data); + inPrimaryExpressionContext = false; + usingPrimitiveWrapperAllocation = false; + return data; + } + + public Object visit(ASTAllocationExpression node, Object data) { + if (!inPrimaryExpressionContext || !(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) { + return super.visit(node, data); + } + if (!PRIMITIVE_WRAPPERS.contains(node.jjtGetChild(0).getImage())) { + return super.visit(node, data); + } + usingPrimitiveWrapperAllocation = true; + return super.visit(node, data); + } + + public Object visit(ASTPrimarySuffix node, Object data) { + if (inPrimaryExpressionContext && usingPrimitiveWrapperAllocation) { + if (node.hasImageEqualTo("toString")) { + if (node.jjtGetParent() == primary) { + addViolation(data, node); + } + } + } + return super.visit(node, data); + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UselessOverridingMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UselessOverridingMethodRule.java index c4fb9cd988..9ac119aa3c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UselessOverridingMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unnecessary/UselessOverridingMethodRule.java @@ -1,259 +1,259 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unnecessary; - -import java.util.ArrayList; -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; -import net.sourceforge.pmd.lang.java.ast.ASTArguments; -import net.sourceforge.pmd.lang.java.ast.ASTBlock; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; -import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTNameList; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; -import net.sourceforge.pmd.lang.java.ast.ASTStatement; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; - -/** - * @author Romain Pelisse, bugfix for [ 1522517 ] False +: - * UselessOverridingMethod - */ -public class UselessOverridingMethodRule extends AbstractJavaRule { - private final List exceptions; - private boolean ignoreAnnotations; - private static final String CLONE = "clone"; - private static final String OBJECT = "Object"; - - private static final BooleanProperty IGNORE_ANNOTATIONS_DESCRIPTOR = new BooleanProperty("ignoreAnnotations", - "Ignore annotations", false, 1.0f); - - public UselessOverridingMethodRule() { - definePropertyDescriptor(IGNORE_ANNOTATIONS_DESCRIPTOR); - - exceptions = new ArrayList<>(1); - exceptions.add("CloneNotSupportedException"); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - init(); - return super.visit(node, data); - } - - private void init() { - ignoreAnnotations = getProperty(IGNORE_ANNOTATIONS_DESCRIPTOR); - } - - @Override - public Object visit(ASTClassOrInterfaceDeclaration clz, Object data) { - if (clz.isInterface()) { - return data; - } - return super.visit(clz, data); - } - - // TODO: this method should be externalize into an utility class, shouldn't it ? - private boolean isMethodType(ASTMethodDeclaration node, String methodType) { - boolean result = false; - ASTResultType type = node.getResultType(); - if (type != null) { - result = type.hasDescendantMatchingXPath( - "./Type/ReferenceType/ClassOrInterfaceType[@Image = '" + methodType + "']"); - } - return result; - } - - // TODO: this method should be externalize into an utility class, shouldn't it ? - private boolean isMethodThrowingType(ASTMethodDeclaration node, List exceptedExceptions) { - boolean result = false; - ASTNameList thrownsExceptions = node.getFirstChildOfType(ASTNameList.class); - if (thrownsExceptions != null) { - List names = thrownsExceptions.findChildrenOfType(ASTName.class); - for (ASTName name : names) { - for (String exceptedException : exceptedExceptions) { - if (exceptedException.equals(name.getImage())) { - result = true; - } - } - } - } - return result; - } - - private boolean hasArguments(ASTMethodDeclaration node) { - return node.hasDescendantMatchingXPath("./MethodDeclarator/FormalParameters/*"); - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - // Can skip abstract methods and methods whose only purpose is to - // guarantee that the inherited method is not changed by finalizing - // them. - if (node.isAbstract() || node.isFinal() || node.isNative() || node.isSynchronized()) { - return super.visit(node, data); - } - // We can also skip the 'clone' method as they are generally - // 'useless' but as it is considered a 'good practice' to - // implement them anyway ( see bug 1522517) - if (CLONE.equals(node.getMethodName()) && node.isPublic() && !this.hasArguments(node) - && this.isMethodType(node, OBJECT) && this.isMethodThrowingType(node, exceptions)) { - return super.visit(node, data); - } - - ASTBlock block = node.getBlock(); - if (block == null) { - return super.visit(node, data); - } - // Only process functions with one BlockStatement - if (block.jjtGetNumChildren() != 1 || block.findDescendantsOfType(ASTStatement.class).size() != 1) { - return super.visit(node, data); - } - - Node statement = block.jjtGetChild(0).jjtGetChild(0); - if (statement.jjtGetChild(0).jjtGetNumChildren() == 0) { - return data; // skips empty return statements - } - Node statementGrandChild = statement.jjtGetChild(0).jjtGetChild(0); - ASTPrimaryExpression primaryExpression; - - if (statementGrandChild instanceof ASTPrimaryExpression) { - primaryExpression = (ASTPrimaryExpression) statementGrandChild; - } else { - List primaryExpressions = findFirstDegreeChildrenOfType(statementGrandChild, - ASTPrimaryExpression.class); - if (primaryExpressions.size() != 1) { - return super.visit(node, data); - } - primaryExpression = primaryExpressions.get(0); - } - - ASTPrimaryPrefix primaryPrefix = findFirstDegreeChildrenOfType(primaryExpression, ASTPrimaryPrefix.class) - .get(0); - if (!primaryPrefix.usesSuperModifier()) { - return super.visit(node, data); - } - - List primarySuffixList = findFirstDegreeChildrenOfType(primaryExpression, - ASTPrimarySuffix.class); - if (primarySuffixList.size() != 2) { - // extra method call on result of super method - return super.visit(node, data); - } - - ASTMethodDeclarator methodDeclarator = findFirstDegreeChildrenOfType(node, ASTMethodDeclarator.class).get(0); - ASTPrimarySuffix primarySuffix = primarySuffixList.get(0); - if (!primarySuffix.hasImageEqualTo(methodDeclarator.getImage())) { - return super.visit(node, data); - } - // Process arguments - primarySuffix = primarySuffixList.get(1); - ASTArguments arguments = (ASTArguments) primarySuffix.jjtGetChild(0); - ASTFormalParameters formalParameters = (ASTFormalParameters) methodDeclarator.jjtGetChild(0); - if (formalParameters.jjtGetNumChildren() != arguments.jjtGetNumChildren()) { - return super.visit(node, data); - } - - if (!ignoreAnnotations) { - ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.jjtGetParent(); - for (int i = 0; i < parent.jjtGetNumChildren(); i++) { - Node n = parent.jjtGetChild(i); - if (n instanceof ASTAnnotation) { - if (n.jjtGetChild(0) instanceof ASTMarkerAnnotation) { - // @Override is ignored - if ("Override".equals(((ASTName) n.jjtGetChild(0).jjtGetChild(0)).getImage())) { - continue; - } - } - return super.visit(node, data); - } - } - } - - if (arguments.jjtGetNumChildren() == 0) { - addViolation(data, node, getMessage()); - } else { - ASTArgumentList argumentList = (ASTArgumentList) arguments.jjtGetChild(0); - for (int i = 0; i < argumentList.jjtGetNumChildren(); i++) { - Node expressionChild = argumentList.jjtGetChild(i).jjtGetChild(0); - if (!(expressionChild instanceof ASTPrimaryExpression) || expressionChild.jjtGetNumChildren() != 1) { - // The arguments are not simply passed through - return super.visit(node, data); - } - - ASTPrimaryExpression argumentPrimaryExpression = (ASTPrimaryExpression) expressionChild; - ASTPrimaryPrefix argumentPrimaryPrefix = (ASTPrimaryPrefix) argumentPrimaryExpression.jjtGetChild(0); - if (argumentPrimaryPrefix.jjtGetNumChildren() == 0) { - // The arguments are not simply passed through (using "this" for instance) - return super.visit(node, data); - } - Node argumentPrimaryPrefixChild = argumentPrimaryPrefix.jjtGetChild(0); - if (!(argumentPrimaryPrefixChild instanceof ASTName)) { - // The arguments are not simply passed through - return super.visit(node, data); - } - - if (formalParameters.jjtGetNumChildren() < i + 1) { - return super.visit(node, data); // different number of args - } - - ASTName argumentName = (ASTName) argumentPrimaryPrefixChild; - ASTFormalParameter formalParameter = (ASTFormalParameter) formalParameters.jjtGetChild(i); - ASTVariableDeclaratorId variableId = findFirstDegreeChildrenOfType(formalParameter, - ASTVariableDeclaratorId.class).get(0); - if (!argumentName.hasImageEqualTo(variableId.getImage())) { - // The arguments are not simply passed through - return super.visit(node, data); - } - - } - // All arguments are passed through directly - addViolation(data, node, getMessage()); - } - return super.visit(node, data); - } - - public List findFirstDegreeChildrenOfType(Node n, Class targetType) { - List l = new ArrayList<>(); - lclFindChildrenOfType(n, targetType, l); - return l; - } - - private void lclFindChildrenOfType(Node node, Class targetType, List results) { - if (node.getClass().equals(targetType)) { - results.add((T) node); - } - - if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) { - return; - } - - if (node instanceof ASTClassOrInterfaceBodyDeclaration - && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) { - return; - } - - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - Node child = node.jjtGetChild(i); - if (child.getClass().equals(targetType)) { - results.add((T) child); - } - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unnecessary; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; +import net.sourceforge.pmd.lang.java.ast.ASTArguments; +import net.sourceforge.pmd.lang.java.ast.ASTBlock; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; +import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTNameList; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.ASTResultType; +import net.sourceforge.pmd.lang.java.ast.ASTStatement; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; + +/** + * @author Romain Pelisse, bugfix for [ 1522517 ] False +: + * UselessOverridingMethod + */ +public class UselessOverridingMethodRule extends AbstractJavaRule { + private final List exceptions; + private boolean ignoreAnnotations; + private static final String CLONE = "clone"; + private static final String OBJECT = "Object"; + + private static final BooleanProperty IGNORE_ANNOTATIONS_DESCRIPTOR = new BooleanProperty("ignoreAnnotations", + "Ignore annotations", false, 1.0f); + + public UselessOverridingMethodRule() { + definePropertyDescriptor(IGNORE_ANNOTATIONS_DESCRIPTOR); + + exceptions = new ArrayList<>(1); + exceptions.add("CloneNotSupportedException"); + } + + @Override + public Object visit(ASTCompilationUnit node, Object data) { + init(); + return super.visit(node, data); + } + + private void init() { + ignoreAnnotations = getProperty(IGNORE_ANNOTATIONS_DESCRIPTOR); + } + + @Override + public Object visit(ASTClassOrInterfaceDeclaration clz, Object data) { + if (clz.isInterface()) { + return data; + } + return super.visit(clz, data); + } + + // TODO: this method should be externalize into an utility class, shouldn't it ? + private boolean isMethodType(ASTMethodDeclaration node, String methodType) { + boolean result = false; + ASTResultType type = node.getResultType(); + if (type != null) { + result = type.hasDescendantMatchingXPath( + "./Type/ReferenceType/ClassOrInterfaceType[@Image = '" + methodType + "']"); + } + return result; + } + + // TODO: this method should be externalize into an utility class, shouldn't it ? + private boolean isMethodThrowingType(ASTMethodDeclaration node, List exceptedExceptions) { + boolean result = false; + ASTNameList thrownsExceptions = node.getFirstChildOfType(ASTNameList.class); + if (thrownsExceptions != null) { + List names = thrownsExceptions.findChildrenOfType(ASTName.class); + for (ASTName name : names) { + for (String exceptedException : exceptedExceptions) { + if (exceptedException.equals(name.getImage())) { + result = true; + } + } + } + } + return result; + } + + private boolean hasArguments(ASTMethodDeclaration node) { + return node.hasDescendantMatchingXPath("./MethodDeclarator/FormalParameters/*"); + } + + @Override + public Object visit(ASTMethodDeclaration node, Object data) { + // Can skip abstract methods and methods whose only purpose is to + // guarantee that the inherited method is not changed by finalizing + // them. + if (node.isAbstract() || node.isFinal() || node.isNative() || node.isSynchronized()) { + return super.visit(node, data); + } + // We can also skip the 'clone' method as they are generally + // 'useless' but as it is considered a 'good practice' to + // implement them anyway ( see bug 1522517) + if (CLONE.equals(node.getMethodName()) && node.isPublic() && !this.hasArguments(node) + && this.isMethodType(node, OBJECT) && this.isMethodThrowingType(node, exceptions)) { + return super.visit(node, data); + } + + ASTBlock block = node.getBlock(); + if (block == null) { + return super.visit(node, data); + } + // Only process functions with one BlockStatement + if (block.jjtGetNumChildren() != 1 || block.findDescendantsOfType(ASTStatement.class).size() != 1) { + return super.visit(node, data); + } + + Node statement = block.jjtGetChild(0).jjtGetChild(0); + if (statement.jjtGetChild(0).jjtGetNumChildren() == 0) { + return data; // skips empty return statements + } + Node statementGrandChild = statement.jjtGetChild(0).jjtGetChild(0); + ASTPrimaryExpression primaryExpression; + + if (statementGrandChild instanceof ASTPrimaryExpression) { + primaryExpression = (ASTPrimaryExpression) statementGrandChild; + } else { + List primaryExpressions = findFirstDegreeChildrenOfType(statementGrandChild, + ASTPrimaryExpression.class); + if (primaryExpressions.size() != 1) { + return super.visit(node, data); + } + primaryExpression = primaryExpressions.get(0); + } + + ASTPrimaryPrefix primaryPrefix = findFirstDegreeChildrenOfType(primaryExpression, ASTPrimaryPrefix.class) + .get(0); + if (!primaryPrefix.usesSuperModifier()) { + return super.visit(node, data); + } + + List primarySuffixList = findFirstDegreeChildrenOfType(primaryExpression, + ASTPrimarySuffix.class); + if (primarySuffixList.size() != 2) { + // extra method call on result of super method + return super.visit(node, data); + } + + ASTMethodDeclarator methodDeclarator = findFirstDegreeChildrenOfType(node, ASTMethodDeclarator.class).get(0); + ASTPrimarySuffix primarySuffix = primarySuffixList.get(0); + if (!primarySuffix.hasImageEqualTo(methodDeclarator.getImage())) { + return super.visit(node, data); + } + // Process arguments + primarySuffix = primarySuffixList.get(1); + ASTArguments arguments = (ASTArguments) primarySuffix.jjtGetChild(0); + ASTFormalParameters formalParameters = (ASTFormalParameters) methodDeclarator.jjtGetChild(0); + if (formalParameters.jjtGetNumChildren() != arguments.jjtGetNumChildren()) { + return super.visit(node, data); + } + + if (!ignoreAnnotations) { + ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.jjtGetParent(); + for (int i = 0; i < parent.jjtGetNumChildren(); i++) { + Node n = parent.jjtGetChild(i); + if (n instanceof ASTAnnotation) { + if (n.jjtGetChild(0) instanceof ASTMarkerAnnotation) { + // @Override is ignored + if ("Override".equals(((ASTName) n.jjtGetChild(0).jjtGetChild(0)).getImage())) { + continue; + } + } + return super.visit(node, data); + } + } + } + + if (arguments.jjtGetNumChildren() == 0) { + addViolation(data, node, getMessage()); + } else { + ASTArgumentList argumentList = (ASTArgumentList) arguments.jjtGetChild(0); + for (int i = 0; i < argumentList.jjtGetNumChildren(); i++) { + Node expressionChild = argumentList.jjtGetChild(i).jjtGetChild(0); + if (!(expressionChild instanceof ASTPrimaryExpression) || expressionChild.jjtGetNumChildren() != 1) { + // The arguments are not simply passed through + return super.visit(node, data); + } + + ASTPrimaryExpression argumentPrimaryExpression = (ASTPrimaryExpression) expressionChild; + ASTPrimaryPrefix argumentPrimaryPrefix = (ASTPrimaryPrefix) argumentPrimaryExpression.jjtGetChild(0); + if (argumentPrimaryPrefix.jjtGetNumChildren() == 0) { + // The arguments are not simply passed through (using "this" for instance) + return super.visit(node, data); + } + Node argumentPrimaryPrefixChild = argumentPrimaryPrefix.jjtGetChild(0); + if (!(argumentPrimaryPrefixChild instanceof ASTName)) { + // The arguments are not simply passed through + return super.visit(node, data); + } + + if (formalParameters.jjtGetNumChildren() < i + 1) { + return super.visit(node, data); // different number of args + } + + ASTName argumentName = (ASTName) argumentPrimaryPrefixChild; + ASTFormalParameter formalParameter = (ASTFormalParameter) formalParameters.jjtGetChild(i); + ASTVariableDeclaratorId variableId = findFirstDegreeChildrenOfType(formalParameter, + ASTVariableDeclaratorId.class).get(0); + if (!argumentName.hasImageEqualTo(variableId.getImage())) { + // The arguments are not simply passed through + return super.visit(node, data); + } + + } + // All arguments are passed through directly + addViolation(data, node, getMessage()); + } + return super.visit(node, data); + } + + public List findFirstDegreeChildrenOfType(Node n, Class targetType) { + List l = new ArrayList<>(); + lclFindChildrenOfType(n, targetType, l); + return l; + } + + private void lclFindChildrenOfType(Node node, Class targetType, List results) { + if (node.getClass().equals(targetType)) { + results.add((T) node); + } + + if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) { + return; + } + + if (node instanceof ASTClassOrInterfaceBodyDeclaration + && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) { + return; + } + + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + Node child = node.jjtGetChild(i); + if (child.getClass().equals(targetType)) { + results.add((T) child); + } + } + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedFormalParameterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedFormalParameterRule.java index 8ec1bb6c0b..12dc732475 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedFormalParameterRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedFormalParameterRule.java @@ -1,127 +1,127 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unusedcode; - -import java.io.InvalidObjectException; -import java.io.ObjectInputStream; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTNameList; -import net.sourceforge.pmd.lang.java.ast.ASTType; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -public class UnusedFormalParameterRule extends AbstractJavaRule { - - private static final BooleanProperty CHECKALL_DESCRIPTOR = new BooleanProperty("checkAll", - "Check all methods, including non-private ones", false, 1.0f); - - public UnusedFormalParameterRule() { - definePropertyDescriptor(CHECKALL_DESCRIPTOR); - } - - public Object visit(ASTConstructorDeclaration node, Object data) { - check(node, data); - return data; - } - - public Object visit(ASTMethodDeclaration node, Object data) { - if (!node.isPrivate() && !getProperty(CHECKALL_DESCRIPTOR)) { - return data; - } - if (!node.isNative() && !node.isAbstract() && !isSerializationMethod(node) && !hasOverrideAnnotation(node)) { - check(node, data); - } - return data; - } - - private boolean isSerializationMethod(ASTMethodDeclaration node) { - ASTMethodDeclarator declarator = node.getFirstDescendantOfType(ASTMethodDeclarator.class); - List parameters = declarator.findDescendantsOfType(ASTFormalParameter.class); - if (node.isPrivate() && "readObject".equals(node.getMethodName()) && parameters.size() == 1 - && throwsOneException(node, InvalidObjectException.class)) { - ASTType type = parameters.get(0).getTypeNode(); - if (type.getType() == ObjectInputStream.class - || ObjectInputStream.class.getSimpleName().equals(type.getTypeImage()) - || ObjectInputStream.class.getName().equals(type.getTypeImage())) { - return true; - } - } - return false; - } - - private boolean throwsOneException(ASTMethodDeclaration node, Class exception) { - ASTNameList throwsList = node.getThrows(); - if (throwsList != null && throwsList.jjtGetNumChildren() == 1) { - ASTName n = (ASTName) throwsList.jjtGetChild(0); - if (n.getType() == exception || exception.getSimpleName().equals(n.getImage()) - || exception.getName().equals(n.getImage())) { - return true; - } - } - return false; - } - - private void check(Node node, Object data) { - Node parent = node.jjtGetParent().jjtGetParent().jjtGetParent(); - if (parent instanceof ASTClassOrInterfaceDeclaration - && !((ASTClassOrInterfaceDeclaration) parent).isInterface()) { - Map> vars = ((JavaNode) node).getScope() - .getDeclarations(VariableNameDeclaration.class); - for (Map.Entry> entry : vars.entrySet()) { - VariableNameDeclaration nameDecl = entry.getKey(); - if (actuallyUsed(nameDecl, entry.getValue())) { - continue; - } - addViolation(data, nameDecl.getNode(), new Object[] { - node instanceof ASTMethodDeclaration ? "method" : "constructor", nameDecl.getImage(), }); - } - } - } - - private boolean actuallyUsed(VariableNameDeclaration nameDecl, List usages) { - for (NameOccurrence occ : usages) { - JavaNameOccurrence jocc = (JavaNameOccurrence) occ; - if (jocc.isOnLeftHandSide()) { - if (nameDecl.isArray() && jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) { - // array element access - return true; - } - continue; - } else { - return true; - } - } - return false; - } - - private boolean hasOverrideAnnotation(ASTMethodDeclaration node) { - int childIndex = node.jjtGetChildIndex(); - for (int i = 0; i < childIndex; i++) { - Node previousSibling = node.jjtGetParent().jjtGetChild(i); - List annotations = previousSibling.findDescendantsOfType(ASTMarkerAnnotation.class); - for (ASTMarkerAnnotation annotation : annotations) { - ASTName name = annotation.getFirstChildOfType(ASTName.class); - if (name != null && (name.hasImageEqualTo("Override") || name.hasImageEqualTo("java.lang.Override"))) { - return true; - } - } - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unusedcode; + +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTNameList; +import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +public class UnusedFormalParameterRule extends AbstractJavaRule { + + private static final BooleanProperty CHECKALL_DESCRIPTOR = new BooleanProperty("checkAll", + "Check all methods, including non-private ones", false, 1.0f); + + public UnusedFormalParameterRule() { + definePropertyDescriptor(CHECKALL_DESCRIPTOR); + } + + public Object visit(ASTConstructorDeclaration node, Object data) { + check(node, data); + return data; + } + + public Object visit(ASTMethodDeclaration node, Object data) { + if (!node.isPrivate() && !getProperty(CHECKALL_DESCRIPTOR)) { + return data; + } + if (!node.isNative() && !node.isAbstract() && !isSerializationMethod(node) && !hasOverrideAnnotation(node)) { + check(node, data); + } + return data; + } + + private boolean isSerializationMethod(ASTMethodDeclaration node) { + ASTMethodDeclarator declarator = node.getFirstDescendantOfType(ASTMethodDeclarator.class); + List parameters = declarator.findDescendantsOfType(ASTFormalParameter.class); + if (node.isPrivate() && "readObject".equals(node.getMethodName()) && parameters.size() == 1 + && throwsOneException(node, InvalidObjectException.class)) { + ASTType type = parameters.get(0).getTypeNode(); + if (type.getType() == ObjectInputStream.class + || ObjectInputStream.class.getSimpleName().equals(type.getTypeImage()) + || ObjectInputStream.class.getName().equals(type.getTypeImage())) { + return true; + } + } + return false; + } + + private boolean throwsOneException(ASTMethodDeclaration node, Class exception) { + ASTNameList throwsList = node.getThrows(); + if (throwsList != null && throwsList.jjtGetNumChildren() == 1) { + ASTName n = (ASTName) throwsList.jjtGetChild(0); + if (n.getType() == exception || exception.getSimpleName().equals(n.getImage()) + || exception.getName().equals(n.getImage())) { + return true; + } + } + return false; + } + + private void check(Node node, Object data) { + Node parent = node.jjtGetParent().jjtGetParent().jjtGetParent(); + if (parent instanceof ASTClassOrInterfaceDeclaration + && !((ASTClassOrInterfaceDeclaration) parent).isInterface()) { + Map> vars = ((JavaNode) node).getScope() + .getDeclarations(VariableNameDeclaration.class); + for (Map.Entry> entry : vars.entrySet()) { + VariableNameDeclaration nameDecl = entry.getKey(); + if (actuallyUsed(nameDecl, entry.getValue())) { + continue; + } + addViolation(data, nameDecl.getNode(), new Object[] { + node instanceof ASTMethodDeclaration ? "method" : "constructor", nameDecl.getImage(), }); + } + } + } + + private boolean actuallyUsed(VariableNameDeclaration nameDecl, List usages) { + for (NameOccurrence occ : usages) { + JavaNameOccurrence jocc = (JavaNameOccurrence) occ; + if (jocc.isOnLeftHandSide()) { + if (nameDecl.isArray() && jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) { + // array element access + return true; + } + continue; + } else { + return true; + } + } + return false; + } + + private boolean hasOverrideAnnotation(ASTMethodDeclaration node) { + int childIndex = node.jjtGetChildIndex(); + for (int i = 0; i < childIndex; i++) { + Node previousSibling = node.jjtGetParent().jjtGetChild(i); + List annotations = previousSibling.findDescendantsOfType(ASTMarkerAnnotation.class); + for (ASTMarkerAnnotation annotation : annotations) { + ASTName name = annotation.getFirstChildOfType(ASTName.class); + if (name != null && (name.hasImageEqualTo("Override") || name.hasImageEqualTo("java.lang.Override"))) { + return true; + } + } + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedLocalVariableRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedLocalVariableRule.java index 446d63d645..38f0c9225e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedLocalVariableRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedLocalVariableRule.java @@ -1,46 +1,46 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unusedcode; - -import java.util.List; - -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -public class UnusedLocalVariableRule extends AbstractJavaRule { - - public Object visit(ASTLocalVariableDeclaration decl, Object data) { - for (int i = 0; i < decl.jjtGetNumChildren(); i++) { - if (!(decl.jjtGetChild(i) instanceof ASTVariableDeclarator)) { - continue; - } - ASTVariableDeclaratorId node = (ASTVariableDeclaratorId) decl.jjtGetChild(i).jjtGetChild(0); - // TODO this isArray() check misses some cases - // need to add DFAish code to determine if an array - // is initialized locally or gotten from somewhere else - if (!node.getNameDeclaration().isArray() && !actuallyUsed(node.getUsages())) { - addViolation(data, node, node.getNameDeclaration().getImage()); - } - } - return data; - } - - private boolean actuallyUsed(List usages) { - for (NameOccurrence occ : usages) { - JavaNameOccurrence jocc = (JavaNameOccurrence) occ; - if (jocc.isOnLeftHandSide()) { - continue; - } else { - return true; - } - } - return false; - } - -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unusedcode; + +import java.util.List; + +import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +public class UnusedLocalVariableRule extends AbstractJavaRule { + + public Object visit(ASTLocalVariableDeclaration decl, Object data) { + for (int i = 0; i < decl.jjtGetNumChildren(); i++) { + if (!(decl.jjtGetChild(i) instanceof ASTVariableDeclarator)) { + continue; + } + ASTVariableDeclaratorId node = (ASTVariableDeclaratorId) decl.jjtGetChild(i).jjtGetChild(0); + // TODO this isArray() check misses some cases + // need to add DFAish code to determine if an array + // is initialized locally or gotten from somewhere else + if (!node.getNameDeclaration().isArray() && !actuallyUsed(node.getUsages())) { + addViolation(data, node, node.getNameDeclaration().getImage()); + } + } + return data; + } + + private boolean actuallyUsed(List usages) { + for (NameOccurrence occ : usages) { + JavaNameOccurrence jocc = (JavaNameOccurrence) occ; + if (jocc.isOnLeftHandSide()) { + continue; + } else { + return true; + } + } + return false; + } + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedModifierRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedModifierRule.java index 4f245860b1..ad078937e7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedModifierRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedModifierRule.java @@ -1,75 +1,75 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unusedcode; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class UnusedModifierRule extends AbstractJavaRule { - - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (!node.isNested()) { - return super.visit(node, data); - } - - ASTClassOrInterfaceDeclaration parentClassOrInterface = node - .getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); - ASTEnumDeclaration parentEnum = node.getFirstParentOfType(ASTEnumDeclaration.class); - - if (node.isInterface() && node.isPublic()) { - // a public interface - if (parentClassOrInterface != null && parentClassOrInterface.isInterface()) { - // within a interface - addViolation(data, node, getMessage()); - } - } - - if (node.isInterface() && node.isStatic()) { - // a static interface - if (parentClassOrInterface != null || parentEnum != null) { - // within a interface, class or enum - addViolation(data, node, getMessage()); - } - } - - if (!node.isInterface() && (node.isPublic() || node.isStatic())) { - // a public and/or static class - if (parentClassOrInterface != null && parentClassOrInterface.isInterface()) { - // within a interface - addViolation(data, node, getMessage()); - } - } - - return super.visit(node, data); - } - - public Object visit(ASTMethodDeclaration node, Object data) { - if (node.isSyntacticallyPublic() || node.isSyntacticallyAbstract()) { - check(node, data); - } - return super.visit(node, data); - } - - public Object visit(ASTFieldDeclaration node, Object data) { - if (node.isSyntacticallyPublic() || node.isSyntacticallyStatic() || node.isSyntacticallyFinal()) { - check(node, data); - } - return super.visit(node, data); - } - - private void check(Node fieldOrMethod, Object data) { - // third ancestor could be an AllocationExpression - // if this is a method in an anonymous inner class - Node parent = fieldOrMethod.jjtGetParent().jjtGetParent().jjtGetParent(); - if (parent instanceof ASTClassOrInterfaceDeclaration - && ((ASTClassOrInterfaceDeclaration) parent).isInterface()) { - addViolation(data, fieldOrMethod); - } - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unusedcode; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class UnusedModifierRule extends AbstractJavaRule { + + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (!node.isNested()) { + return super.visit(node, data); + } + + ASTClassOrInterfaceDeclaration parentClassOrInterface = node + .getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); + ASTEnumDeclaration parentEnum = node.getFirstParentOfType(ASTEnumDeclaration.class); + + if (node.isInterface() && node.isPublic()) { + // a public interface + if (parentClassOrInterface != null && parentClassOrInterface.isInterface()) { + // within a interface + addViolation(data, node, getMessage()); + } + } + + if (node.isInterface() && node.isStatic()) { + // a static interface + if (parentClassOrInterface != null || parentEnum != null) { + // within a interface, class or enum + addViolation(data, node, getMessage()); + } + } + + if (!node.isInterface() && (node.isPublic() || node.isStatic())) { + // a public and/or static class + if (parentClassOrInterface != null && parentClassOrInterface.isInterface()) { + // within a interface + addViolation(data, node, getMessage()); + } + } + + return super.visit(node, data); + } + + public Object visit(ASTMethodDeclaration node, Object data) { + if (node.isSyntacticallyPublic() || node.isSyntacticallyAbstract()) { + check(node, data); + } + return super.visit(node, data); + } + + public Object visit(ASTFieldDeclaration node, Object data) { + if (node.isSyntacticallyPublic() || node.isSyntacticallyStatic() || node.isSyntacticallyFinal()) { + check(node, data); + } + return super.visit(node, data); + } + + private void check(Node fieldOrMethod, Object data) { + // third ancestor could be an AllocationExpression + // if this is a method in an anonymous inner class + Node parent = fieldOrMethod.jjtGetParent().jjtGetParent().jjtGetParent(); + if (parent instanceof ASTClassOrInterfaceDeclaration + && ((ASTClassOrInterfaceDeclaration) parent).isInterface()) { + addViolation(data, fieldOrMethod); + } + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateFieldRule.java index 6e4216ef09..6d0a883630 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateFieldRule.java @@ -1,124 +1,124 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unusedcode; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTEnumBody; -import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; -import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.AccessNode; -import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.rule.AbstractLombokAwareRule; -import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.symboltable.NameDeclaration; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -public class UnusedPrivateFieldRule extends AbstractLombokAwareRule { - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - boolean classHasLombok = hasLombokAnnotation(node); - - Map> vars = node.getScope() - .getDeclarations(VariableNameDeclaration.class); - for (Map.Entry> entry : vars.entrySet()) { - VariableNameDeclaration decl = entry.getKey(); - AccessNode accessNodeParent = decl.getAccessNodeParent(); - if (!accessNodeParent.isPrivate() || isOK(decl.getImage()) || classHasLombok - || hasLombokAnnotation(accessNodeParent)) { - continue; - } - if (!actuallyUsed(entry.getValue())) { - if (!usedInOuterClass(node, decl) && !usedInOuterEnum(node, decl)) { - addViolation(data, decl.getNode(), decl.getImage()); - } - } - } - return super.visit(node, data); - } - - private boolean usedInOuterEnum(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) { - List outerEnums = node.getParentsOfType(ASTEnumDeclaration.class); - for (ASTEnumDeclaration outerEnum : outerEnums) { - ASTEnumBody enumBody = outerEnum.getFirstChildOfType(ASTEnumBody.class); - if (usedInOuter(decl, enumBody)) { - return true; - } - } - return false; - } - - /** - * Find out whether the variable is used in an outer class - */ - private boolean usedInOuterClass(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) { - List outerClasses = node.getParentsOfType(ASTClassOrInterfaceDeclaration.class); - for (ASTClassOrInterfaceDeclaration outerClass : outerClasses) { - ASTClassOrInterfaceBody classOrInterfaceBody = outerClass - .getFirstChildOfType(ASTClassOrInterfaceBody.class); - if (usedInOuter(decl, classOrInterfaceBody)) { - return true; - } - } - return false; - } - - private boolean usedInOuter(NameDeclaration decl, JavaNode body) { - List classOrInterfaceBodyDeclarations = body - .findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class); - List enumConstants = body.findChildrenOfType(ASTEnumConstant.class); - List nodes = new ArrayList<>(); - nodes.addAll(classOrInterfaceBodyDeclarations); - nodes.addAll(enumConstants); - - for (JavaNode node : nodes) { - List primarySuffixes = node.findDescendantsOfType(ASTPrimarySuffix.class); - for (ASTPrimarySuffix primarySuffix : primarySuffixes) { - if (decl.getImage().equals(primarySuffix.getImage())) { - return true; // No violation - } - } - - List primaryPrefixes = node.findDescendantsOfType(ASTPrimaryPrefix.class); - for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) { - ASTName name = primaryPrefix.getFirstDescendantOfType(ASTName.class); - - if (name != null) { - for (String id : name.getImage().split("\\.")) { - if (id.equals(decl.getImage())) { - return true; // No violation - } - } - } - } - } - return false; - } - - private boolean actuallyUsed(List usages) { - for (NameOccurrence nameOccurrence : usages) { - JavaNameOccurrence jNameOccurrence = (JavaNameOccurrence) nameOccurrence; - if (!jNameOccurrence.isOnLeftHandSide()) { - return true; - } - } - - return false; - } - - private boolean isOK(String image) { - return "serialVersionUID".equals(image) || "serialPersistentFields".equals(image) || "IDENT".equals(image); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unusedcode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumBody; +import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.rule.AbstractLombokAwareRule; +import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +public class UnusedPrivateFieldRule extends AbstractLombokAwareRule { + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + boolean classHasLombok = hasLombokAnnotation(node); + + Map> vars = node.getScope() + .getDeclarations(VariableNameDeclaration.class); + for (Map.Entry> entry : vars.entrySet()) { + VariableNameDeclaration decl = entry.getKey(); + AccessNode accessNodeParent = decl.getAccessNodeParent(); + if (!accessNodeParent.isPrivate() || isOK(decl.getImage()) || classHasLombok + || hasLombokAnnotation(accessNodeParent)) { + continue; + } + if (!actuallyUsed(entry.getValue())) { + if (!usedInOuterClass(node, decl) && !usedInOuterEnum(node, decl)) { + addViolation(data, decl.getNode(), decl.getImage()); + } + } + } + return super.visit(node, data); + } + + private boolean usedInOuterEnum(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) { + List outerEnums = node.getParentsOfType(ASTEnumDeclaration.class); + for (ASTEnumDeclaration outerEnum : outerEnums) { + ASTEnumBody enumBody = outerEnum.getFirstChildOfType(ASTEnumBody.class); + if (usedInOuter(decl, enumBody)) { + return true; + } + } + return false; + } + + /** + * Find out whether the variable is used in an outer class + */ + private boolean usedInOuterClass(ASTClassOrInterfaceDeclaration node, NameDeclaration decl) { + List outerClasses = node.getParentsOfType(ASTClassOrInterfaceDeclaration.class); + for (ASTClassOrInterfaceDeclaration outerClass : outerClasses) { + ASTClassOrInterfaceBody classOrInterfaceBody = outerClass + .getFirstChildOfType(ASTClassOrInterfaceBody.class); + if (usedInOuter(decl, classOrInterfaceBody)) { + return true; + } + } + return false; + } + + private boolean usedInOuter(NameDeclaration decl, JavaNode body) { + List classOrInterfaceBodyDeclarations = body + .findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class); + List enumConstants = body.findChildrenOfType(ASTEnumConstant.class); + List nodes = new ArrayList<>(); + nodes.addAll(classOrInterfaceBodyDeclarations); + nodes.addAll(enumConstants); + + for (JavaNode node : nodes) { + List primarySuffixes = node.findDescendantsOfType(ASTPrimarySuffix.class); + for (ASTPrimarySuffix primarySuffix : primarySuffixes) { + if (decl.getImage().equals(primarySuffix.getImage())) { + return true; // No violation + } + } + + List primaryPrefixes = node.findDescendantsOfType(ASTPrimaryPrefix.class); + for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) { + ASTName name = primaryPrefix.getFirstDescendantOfType(ASTName.class); + + if (name != null) { + for (String id : name.getImage().split("\\.")) { + if (id.equals(decl.getImage())) { + return true; // No violation + } + } + } + } + } + return false; + } + + private boolean actuallyUsed(List usages) { + for (NameOccurrence nameOccurrence : usages) { + JavaNameOccurrence jNameOccurrence = (JavaNameOccurrence) nameOccurrence; + if (!jNameOccurrence.isOnLeftHandSide()) { + return true; + } + } + + return false; + } + + private boolean isOK(String image) { + return "serialVersionUID".equals(image) || "serialPersistentFields".equals(image) || "IDENT".equals(image); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateMethodRule.java index 8aa9dda1bf..dab394e913 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/unusedcode/UnusedPrivateMethodRule.java @@ -1,110 +1,110 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.unusedcode; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTInitializer; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.AccessNode; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.ClassScope; -import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration; -import net.sourceforge.pmd.lang.symboltable.NameDeclaration; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -/** - * This rule detects private methods, that are not used and can therefore be - * deleted. - */ -public class UnusedPrivateMethodRule extends AbstractJavaRule { - - /** - * Visit each method declaration. - * - * @param node - * the method declaration - * @param data - * data - rule context - * @return data - */ - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - - Map> methods = node.getScope().getEnclosingScope(ClassScope.class) - .getMethodDeclarations(); - for (MethodNameDeclaration mnd : findUnique(methods)) { - List occs = methods.get(mnd); - if (!privateAndNotExcluded(mnd)) { - continue; - } - if (occs.isEmpty()) { - addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature()); - } else { - if (calledFromOutsideItself(occs, mnd)) { - addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature()); - } - - } - } - return data; - } - - private Set findUnique(Map> methods) { - // some rather hideous hackery here - // to work around the fact that PMD does not yet do full type analysis - // when it does, delete this - Set unique = new HashSet<>(); - Set sigs = new HashSet<>(); - for (MethodNameDeclaration mnd : methods.keySet()) { - String sig = mnd.getImage() + mnd.getParameterCount() + mnd.isVarargs(); - if (!sigs.contains(sig)) { - unique.add(mnd); - } - sigs.add(sig); - } - return unique; - } - - private boolean calledFromOutsideItself(List occs, NameDeclaration mnd) { - int callsFromOutsideMethod = 0; - for (NameOccurrence occ : occs) { - Node occNode = occ.getLocation(); - ASTConstructorDeclaration enclosingConstructor = occNode - .getFirstParentOfType(ASTConstructorDeclaration.class); - if (enclosingConstructor != null) { - callsFromOutsideMethod++; - break; // Do we miss unused private constructors here? - } - ASTInitializer enclosingInitializer = occNode.getFirstParentOfType(ASTInitializer.class); - if (enclosingInitializer != null) { - callsFromOutsideMethod++; - break; - } - - ASTMethodDeclaration enclosingMethod = occNode.getFirstParentOfType(ASTMethodDeclaration.class); - if (enclosingMethod == null || !mnd.getNode().jjtGetParent().equals(enclosingMethod)) { - callsFromOutsideMethod++; - } - } - return callsFromOutsideMethod == 0; - } - - private boolean privateAndNotExcluded(NameDeclaration mnd) { - ASTMethodDeclarator node = (ASTMethodDeclarator) mnd.getNode(); - return ((AccessNode) node.jjtGetParent()).isPrivate() && !node.hasImageEqualTo("readObject") - && !node.hasImageEqualTo("writeObject") && !node.hasImageEqualTo("readResolve") - && !node.hasImageEqualTo("writeReplace"); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.unusedcode; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTInitializer; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.ClassScope; +import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; + +/** + * This rule detects private methods, that are not used and can therefore be + * deleted. + */ +public class UnusedPrivateMethodRule extends AbstractJavaRule { + + /** + * Visit each method declaration. + * + * @param node + * the method declaration + * @param data + * data - rule context + * @return data + */ + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (node.isInterface()) { + return data; + } + + Map> methods = node.getScope().getEnclosingScope(ClassScope.class) + .getMethodDeclarations(); + for (MethodNameDeclaration mnd : findUnique(methods)) { + List occs = methods.get(mnd); + if (!privateAndNotExcluded(mnd)) { + continue; + } + if (occs.isEmpty()) { + addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature()); + } else { + if (calledFromOutsideItself(occs, mnd)) { + addViolation(data, mnd.getNode(), mnd.getImage() + mnd.getParameterDisplaySignature()); + } + + } + } + return data; + } + + private Set findUnique(Map> methods) { + // some rather hideous hackery here + // to work around the fact that PMD does not yet do full type analysis + // when it does, delete this + Set unique = new HashSet<>(); + Set sigs = new HashSet<>(); + for (MethodNameDeclaration mnd : methods.keySet()) { + String sig = mnd.getImage() + mnd.getParameterCount() + mnd.isVarargs(); + if (!sigs.contains(sig)) { + unique.add(mnd); + } + sigs.add(sig); + } + return unique; + } + + private boolean calledFromOutsideItself(List occs, NameDeclaration mnd) { + int callsFromOutsideMethod = 0; + for (NameOccurrence occ : occs) { + Node occNode = occ.getLocation(); + ASTConstructorDeclaration enclosingConstructor = occNode + .getFirstParentOfType(ASTConstructorDeclaration.class); + if (enclosingConstructor != null) { + callsFromOutsideMethod++; + break; // Do we miss unused private constructors here? + } + ASTInitializer enclosingInitializer = occNode.getFirstParentOfType(ASTInitializer.class); + if (enclosingInitializer != null) { + callsFromOutsideMethod++; + break; + } + + ASTMethodDeclaration enclosingMethod = occNode.getFirstParentOfType(ASTMethodDeclaration.class); + if (enclosingMethod == null || !mnd.getNode().jjtGetParent().equals(enclosingMethod)) { + callsFromOutsideMethod++; + } + } + return callsFromOutsideMethod == 0; + } + + private boolean privateAndNotExcluded(NameDeclaration mnd) { + ASTMethodDeclarator node = (ASTMethodDeclarator) mnd.getNode(); + return ((AccessNode) node.jjtGetParent()).isPrivate() && !node.hasImageEqualTo("readObject") + && !node.hasImageEqualTo("writeObject") && !node.hasImageEqualTo("readResolve") + && !node.hasImageEqualTo("writeReplace"); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java index 1978f2d58e..5be80324ac 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java @@ -1,65 +1,65 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.typeresolution; - -import java.util.Arrays; -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.TypeNode; -import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration; - -public final class TypeHelper { - - private TypeHelper() { - // utility class - } - - public static boolean isA(TypeNode n, Class clazz) { - return subclasses(n, clazz); - } - - public static boolean isEither(TypeNode n, Class class1, Class class2) { - return subclasses(n, class1) || subclasses(n, class2); - } - - public static boolean isA(TypedNameDeclaration vnd, Class clazz) { - Class type = vnd.getType(); - return type != null && type.equals(clazz) || type == null - && (clazz.getSimpleName().equals(vnd.getTypeImage()) || clazz.getName().equals(vnd.getTypeImage())); - } - - public static boolean isEither(TypedNameDeclaration vnd, Class class1, Class class2) { - return isA(vnd, class1) || isA(vnd, class2); - } - - public static boolean isNeither(TypedNameDeclaration vnd, Class class1, Class class2) { - return !isA(vnd, class1) && !isA(vnd, class2); - } - - public static boolean subclasses(TypeNode n, Class clazz) { - Class type = n.getType(); - if (type == null) { - return clazz.getSimpleName().equals(((Node) n).getImage()) || clazz.getName().equals(((Node) n).getImage()); - } - - if (type.equals(clazz)) { - return true; - } - - List> implementors = Arrays.asList(type.getInterfaces()); - if (implementors.contains(clazz)) { - return true; - } - Class superC = type.getSuperclass(); - while (superC != null && !superC.equals(Object.class)) { - if (superC.equals(clazz)) { - return true; - } - superC = superC.getSuperclass(); - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.typeresolution; + +import java.util.Arrays; +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.TypeNode; +import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration; + +public final class TypeHelper { + + private TypeHelper() { + // utility class + } + + public static boolean isA(TypeNode n, Class clazz) { + return subclasses(n, clazz); + } + + public static boolean isEither(TypeNode n, Class class1, Class class2) { + return subclasses(n, class1) || subclasses(n, class2); + } + + public static boolean isA(TypedNameDeclaration vnd, Class clazz) { + Class type = vnd.getType(); + return type != null && type.equals(clazz) || type == null + && (clazz.getSimpleName().equals(vnd.getTypeImage()) || clazz.getName().equals(vnd.getTypeImage())); + } + + public static boolean isEither(TypedNameDeclaration vnd, Class class1, Class class2) { + return isA(vnd, class1) || isA(vnd, class2); + } + + public static boolean isNeither(TypedNameDeclaration vnd, Class class1, Class class2) { + return !isA(vnd, class1) && !isA(vnd, class2); + } + + public static boolean subclasses(TypeNode n, Class clazz) { + Class type = n.getType(); + if (type == null) { + return clazz.getSimpleName().equals(((Node) n).getImage()) || clazz.getName().equals(((Node) n).getImage()); + } + + if (type.equals(clazz)) { + return true; + } + + List> implementors = Arrays.asList(type.getInterfaces()); + if (implementors.contains(clazz)) { + return true; + } + Class superC = type.getSuperclass(); + while (superC != null && !superC.equals(Object.class)) { + if (superC.equals(clazz)) { + return true; + } + superC = superC.getSuperclass(); + } + return false; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java index 9acf20ddf1..9e9a8ca2f5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java @@ -1,29 +1,29 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.xpath; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; - -import net.sf.saxon.expr.XPathContext; - -/** - * Exposes all Java Language specific functions for Saxon use. - */ -public final class JavaFunctions { - - private JavaFunctions() { - // utility class - } - - public static boolean typeof(XPathContext context, String nodeTypeName, String fullTypeName) { - return typeof(context, nodeTypeName, fullTypeName, null); - } - - public static boolean typeof(XPathContext context, String nodeTypeName, String fullTypeName, String shortTypeName) { - return TypeOfFunction.typeof((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), nodeTypeName, - fullTypeName, shortTypeName); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.xpath; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; + +import net.sf.saxon.expr.XPathContext; + +/** + * Exposes all Java Language specific functions for Saxon use. + */ +public final class JavaFunctions { + + private JavaFunctions() { + // utility class + } + + public static boolean typeof(XPathContext context, String nodeTypeName, String fullTypeName) { + return typeof(context, nodeTypeName, fullTypeName, null); + } + + public static boolean typeof(XPathContext context, String nodeTypeName, String fullTypeName, String shortTypeName) { + return TypeOfFunction.typeof((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), nodeTypeName, + fullTypeName, shortTypeName); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java index 48ec74d9e9..3901d5f7aa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java @@ -1,87 +1,87 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.xpath; - -import java.util.Arrays; -import java.util.List; - -import org.jaxen.Context; -import org.jaxen.Function; -import org.jaxen.FunctionCallException; -import org.jaxen.SimpleFunctionContext; -import org.jaxen.XPathFunctionContext; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.java.ast.TypeNode; - -public class TypeOfFunction implements Function { - - public static void registerSelfInSimpleContext() { - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeof", - new TypeOfFunction()); - } - - public Object call(Context context, List args) throws FunctionCallException { - - String nodeTypeName = null; - String fullTypeName = null; - String shortTypeName = null; - Attribute attr = null; - for (int i = 0; i < args.size(); i++) { - if (args.get(i) instanceof List) { - if (attr == null) { - attr = ((List) args.get(i)).get(0); - nodeTypeName = attr.getStringValue(); - } else { - throw new IllegalArgumentException( - "typeof function can take only a single argument which is an Attribute."); - } - } else { - if (fullTypeName == null) { - fullTypeName = (String) args.get(i); - } else if (shortTypeName == null) { - shortTypeName = (String) args.get(i); - } else { - break; - } - } - } - if (fullTypeName == null) { - throw new IllegalArgumentException( - "typeof function must be given at least one String argument for the fully qualified type name."); - } - Node n = (Node) context.getNodeSet().get(0); - return typeof(n, nodeTypeName, fullTypeName, shortTypeName); - } - - // TEST //ClassOrInterfaceType[typeof(@Image, 'java.lang.String')] - public static boolean typeof(Node n, String nodeTypeName, String fullTypeName, String shortTypeName) { - if (n instanceof TypeNode) { - Class type = ((TypeNode) n).getType(); - if (type == null) { - return nodeTypeName != null - && (nodeTypeName.equals(fullTypeName) || nodeTypeName.equals(shortTypeName)); - } - if (type.getName().equals(fullTypeName)) { - return true; - } - List> implementors = Arrays.asList(type.getInterfaces()); - if (implementors.contains(type)) { - return true; - } - Class superC = type.getSuperclass(); - while (superC != null && !superC.equals(Object.class)) { - if (superC.getName().equals(fullTypeName)) { - return true; - } - superC = superC.getSuperclass(); - } - } else { - throw new IllegalArgumentException("typeof function may only be called on a TypeNode."); - } - return false; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.xpath; + +import java.util.Arrays; +import java.util.List; + +import org.jaxen.Context; +import org.jaxen.Function; +import org.jaxen.FunctionCallException; +import org.jaxen.SimpleFunctionContext; +import org.jaxen.XPathFunctionContext; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.java.ast.TypeNode; + +public class TypeOfFunction implements Function { + + public static void registerSelfInSimpleContext() { + ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeof", + new TypeOfFunction()); + } + + public Object call(Context context, List args) throws FunctionCallException { + + String nodeTypeName = null; + String fullTypeName = null; + String shortTypeName = null; + Attribute attr = null; + for (int i = 0; i < args.size(); i++) { + if (args.get(i) instanceof List) { + if (attr == null) { + attr = ((List) args.get(i)).get(0); + nodeTypeName = attr.getStringValue(); + } else { + throw new IllegalArgumentException( + "typeof function can take only a single argument which is an Attribute."); + } + } else { + if (fullTypeName == null) { + fullTypeName = (String) args.get(i); + } else if (shortTypeName == null) { + shortTypeName = (String) args.get(i); + } else { + break; + } + } + } + if (fullTypeName == null) { + throw new IllegalArgumentException( + "typeof function must be given at least one String argument for the fully qualified type name."); + } + Node n = (Node) context.getNodeSet().get(0); + return typeof(n, nodeTypeName, fullTypeName, shortTypeName); + } + + // TEST //ClassOrInterfaceType[typeof(@Image, 'java.lang.String')] + public static boolean typeof(Node n, String nodeTypeName, String fullTypeName, String shortTypeName) { + if (n instanceof TypeNode) { + Class type = ((TypeNode) n).getType(); + if (type == null) { + return nodeTypeName != null + && (nodeTypeName.equals(fullTypeName) || nodeTypeName.equals(shortTypeName)); + } + if (type.getName().equals(fullTypeName)) { + return true; + } + List> implementors = Arrays.asList(type.getInterfaces()); + if (implementors.contains(type)) { + return true; + } + Class superC = type.getSuperclass(); + while (superC != null && !superC.equals(Object.class)) { + if (superC.getName().equals(fullTypeName)) { + return true; + } + superC = superC.getSuperclass(); + } + } else { + throw new IllegalArgumentException("typeof function may only be called on a TypeNode."); + } + return false; + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java index 22b64d93b4..a7bd84a484 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java @@ -1,60 +1,60 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import static org.junit.Assert.assertEquals; - -import java.io.File; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; -import net.sourceforge.pmd.lang.java.JavaLanguageModule; - -public class LanguageVersionDiscovererTest { - - /** - * Test on Java file with default options. - */ - @Test - public void testJavaFileUsingDefaults() { - LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer(); - File javaFile = new File("/path/to/MyClass.java"); - - LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); - assertEquals("LanguageVersion must be Java 1.8 !", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"), languageVersion); - } - - /** - * Test on Java file with Java version set to 1.4. - */ - @Test - public void testJavaFileUsing14() { - LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer(); - discoverer.setDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4")); - File javaFile = new File("/path/to/MyClass.java"); - - LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); - assertEquals("LanguageVersion must be Java 1.4!", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4"), languageVersion); - } - - @Test - public void testLanguageVersionDiscoverer() { - PMDConfiguration configuration = new PMDConfiguration(); - LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer(); - assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"), - languageVersionDiscoverer - .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); - configuration - .setDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5")); - assertEquals("Modified Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5"), - languageVersionDiscoverer - .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static org.junit.Assert.assertEquals; + +import java.io.File; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; + +public class LanguageVersionDiscovererTest { + + /** + * Test on Java file with default options. + */ + @Test + public void testJavaFileUsingDefaults() { + LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer(); + File javaFile = new File("/path/to/MyClass.java"); + + LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); + assertEquals("LanguageVersion must be Java 1.8 !", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"), languageVersion); + } + + /** + * Test on Java file with Java version set to 1.4. + */ + @Test + public void testJavaFileUsing14() { + LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer(); + discoverer.setDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4")); + File javaFile = new File("/path/to/MyClass.java"); + + LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); + assertEquals("LanguageVersion must be Java 1.4!", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4"), languageVersion); + } + + @Test + public void testLanguageVersionDiscoverer() { + PMDConfiguration configuration = new PMDConfiguration(); + LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer(); + assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"), + languageVersionDiscoverer + .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); + configuration + .setDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5")); + assertEquals("Modified Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5"), + languageVersionDiscoverer + .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java index 36abac6290..984a99b706 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java @@ -1,41 +1,41 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.runners.Parameterized.Parameters; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.java.JavaLanguageModule; - -public class LanguageVersionTest extends AbstractLanguageVersionTest { - - public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { - super(name, terseName, version, expected); - } - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.3", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.3"), }, - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.4", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4"), }, - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.5", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5"), }, - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.6", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.6"), }, - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.7", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.7"), }, - { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.8", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"), }, - - // this one won't be found: case sensitive! - { "JAVA", "JAVA", "1.7", null, }, }); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.runners.Parameterized.Parameters; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; + +public class LanguageVersionTest extends AbstractLanguageVersionTest { + + public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { + super(name, terseName, version, expected); + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.3", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.3"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.4", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.5", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.6", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.6"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.7", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.7"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.8", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"), }, + + // this one won't be found: case sensitive! + { "JAVA", "JAVA", "1.7", null, }, }); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationTest.java index 32b11c24e0..06174cd3ba 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolationTest.java @@ -1,111 +1,111 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule; - -import static org.junit.Assert.assertEquals; - -import java.io.StringReader; - -import org.junit.Test; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersionHandler; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.java.JavaLanguageModule; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.symboltable.ScopeAndDeclarationFinder; - -/** - * @author Philip Graf - */ -public class JavaRuleViolationTest { - /** - * Verifies that {@link JavaRuleViolation} sets the variable name for an - * {@link ASTFormalParameter} node. - */ - @Test - public void testASTFormalParameterVariableName() { - ASTCompilationUnit ast = parse("class Foo { void bar(int x) {} }"); - final ASTFormalParameter node = ast.getFirstDescendantOfType(ASTFormalParameter.class); - final RuleContext context = new RuleContext(); - final JavaRuleViolation violation = new JavaRuleViolation(null, context, node, null); - assertEquals("x", violation.getVariableName()); - } - - private ASTCompilationUnit parse(final String code) { - final LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME) - .getDefaultVersion().getLanguageVersionHandler(); - final ParserOptions options = languageVersionHandler.getDefaultParserOptions(); - final ASTCompilationUnit ast = (ASTCompilationUnit) languageVersionHandler.getParser(options).parse(null, - new StringReader(code)); - // set scope of AST nodes - ast.jjtAccept(new ScopeAndDeclarationFinder(), null); - return ast; - } - - /** - * Tests that the method name is taken correctly from the given node. - * - * @see #1250 - */ - @Test - public void testMethodName() { - ASTCompilationUnit ast = parse("class Foo { void bar(int x) {} }"); - ASTMethodDeclaration md = ast.getFirstDescendantOfType(ASTMethodDeclaration.class); - final RuleContext context = new RuleContext(); - final JavaRuleViolation violation = new JavaRuleViolation(null, context, md, null); - assertEquals("bar", violation.getMethodName()); - } - - /** - * Tests that the class name is taken correctly, even if the node is outside - * of a class scope, e.g. a import declaration. - * - * @see #1529 - */ - @Test - public void testPackageAndClassName() { - ASTCompilationUnit ast = parse("package pkg; import java.util.List; public class Foo { }"); - ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); - - JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); - assertEquals("pkg", violation.getPackageName()); - assertEquals("Foo", violation.getClassName()); - } - - @Test - public void testPackageAndEnumName() { - ASTCompilationUnit ast = parse("package pkg; import java.util.List; public enum FooE { }"); - ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); - - JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); - assertEquals("pkg", violation.getPackageName()); - assertEquals("FooE", violation.getClassName()); - } - - @Test - public void testDefaultPackageAndClassName() { - ASTCompilationUnit ast = parse("import java.util.List; public class Foo { }"); - ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); - - JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); - assertEquals("", violation.getPackageName()); - assertEquals("Foo", violation.getClassName()); - } - - @Test - public void testPackageAndMultipleClassesName() { - ASTCompilationUnit ast = parse("package pkg; import java.util.List; class Foo { } public class Bar { }"); - ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); - - JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); - assertEquals("pkg", violation.getPackageName()); - assertEquals("Bar", violation.getClassName()); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule; + +import static org.junit.Assert.assertEquals; + +import java.io.StringReader; + +import org.junit.Test; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; +import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.symboltable.ScopeAndDeclarationFinder; + +/** + * @author Philip Graf + */ +public class JavaRuleViolationTest { + /** + * Verifies that {@link JavaRuleViolation} sets the variable name for an + * {@link ASTFormalParameter} node. + */ + @Test + public void testASTFormalParameterVariableName() { + ASTCompilationUnit ast = parse("class Foo { void bar(int x) {} }"); + final ASTFormalParameter node = ast.getFirstDescendantOfType(ASTFormalParameter.class); + final RuleContext context = new RuleContext(); + final JavaRuleViolation violation = new JavaRuleViolation(null, context, node, null); + assertEquals("x", violation.getVariableName()); + } + + private ASTCompilationUnit parse(final String code) { + final LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME) + .getDefaultVersion().getLanguageVersionHandler(); + final ParserOptions options = languageVersionHandler.getDefaultParserOptions(); + final ASTCompilationUnit ast = (ASTCompilationUnit) languageVersionHandler.getParser(options).parse(null, + new StringReader(code)); + // set scope of AST nodes + ast.jjtAccept(new ScopeAndDeclarationFinder(), null); + return ast; + } + + /** + * Tests that the method name is taken correctly from the given node. + * + * @see #1250 + */ + @Test + public void testMethodName() { + ASTCompilationUnit ast = parse("class Foo { void bar(int x) {} }"); + ASTMethodDeclaration md = ast.getFirstDescendantOfType(ASTMethodDeclaration.class); + final RuleContext context = new RuleContext(); + final JavaRuleViolation violation = new JavaRuleViolation(null, context, md, null); + assertEquals("bar", violation.getMethodName()); + } + + /** + * Tests that the class name is taken correctly, even if the node is outside + * of a class scope, e.g. a import declaration. + * + * @see #1529 + */ + @Test + public void testPackageAndClassName() { + ASTCompilationUnit ast = parse("package pkg; import java.util.List; public class Foo { }"); + ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); + + JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); + assertEquals("pkg", violation.getPackageName()); + assertEquals("Foo", violation.getClassName()); + } + + @Test + public void testPackageAndEnumName() { + ASTCompilationUnit ast = parse("package pkg; import java.util.List; public enum FooE { }"); + ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); + + JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); + assertEquals("pkg", violation.getPackageName()); + assertEquals("FooE", violation.getClassName()); + } + + @Test + public void testDefaultPackageAndClassName() { + ASTCompilationUnit ast = parse("import java.util.List; public class Foo { }"); + ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); + + JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); + assertEquals("", violation.getPackageName()); + assertEquals("Foo", violation.getClassName()); + } + + @Test + public void testPackageAndMultipleClassesName() { + ASTCompilationUnit ast = parse("package pkg; import java.util.List; class Foo { } public class Bar { }"); + ASTImportDeclaration importNode = ast.getFirstDescendantOfType(ASTImportDeclaration.class); + + JavaRuleViolation violation = new JavaRuleViolation(null, new RuleContext(), importNode, null); + assertEquals("pkg", violation.getPackageName()); + assertEquals("Bar", violation.getClassName()); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousInnerClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousInnerClass.java index adff4b4d37..f6e9278610 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousInnerClass.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/AnonymousInnerClass.java @@ -1,22 +1,22 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -import java.util.AbstractList; -import java.util.List; - -public class AnonymousInnerClass { - List list = new AbstractList() { - @Override - public Object get(int index) { - return null; - } - - @Override - public int size() { - return 0; - } - }; -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +import java.util.AbstractList; +import java.util.List; + +public class AnonymousInnerClass { + List list = new AbstractList() { + @Override + public Object get(int index) { + return null; + } + + @Override + public int size() { + return 0; + } + }; +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ArrayListFound.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ArrayListFound.java index 9e61ff9f0a..96d89f9c77 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ArrayListFound.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ArrayListFound.java @@ -1,11 +1,11 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -import java.util.ArrayList; - -public class ArrayListFound { - ArrayList x; -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +import java.util.ArrayList; + +public class ArrayListFound { + ArrayList x; +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/DefaultJavaLangImport.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/DefaultJavaLangImport.java index af163d0734..f0a0f899c6 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/DefaultJavaLangImport.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/DefaultJavaLangImport.java @@ -1,12 +1,12 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -public class DefaultJavaLangImport { - @Override - public String toString() { - return "foo"; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +public class DefaultJavaLangImport { + @Override + public String toString() { + return "foo"; + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ExtraTopLevelClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ExtraTopLevelClass.java index c3b2625fd7..c287b6ed8d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ExtraTopLevelClass.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/ExtraTopLevelClass.java @@ -1,11 +1,11 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -public class ExtraTopLevelClass { -} - -class TheExtraTopLevelClass { // SUPPRESS CHECKSTYLE explicityl testing two classes in one file -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +public class ExtraTopLevelClass { +} + +class TheExtraTopLevelClass { // SUPPRESS CHECKSTYLE explicityl testing two classes in one file +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/InnerClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/InnerClass.java index 8bed2e9e16..fc2febc32a 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/InnerClass.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/InnerClass.java @@ -1,13 +1,13 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -public class InnerClass { - public class TheInnerClass { - } - - public void foo(TheInnerClass arg) { - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +public class InnerClass { + public class TheInnerClass { + } + + public void foo(TheInnerClass arg) { + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Literals.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Literals.java index 7dbd6c239e..82f8ac5620 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Literals.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Literals.java @@ -1,43 +1,43 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -public class Literals { - String s = "s"; - boolean boolean1 = false; - boolean boolean2 = true; - Object obj = null; - byte byte1 = 0; - byte byte2 = 0x0F; - byte byte3 = -007; - short short1 = 0; - short short2 = 0x0F; - short short3 = -007; - char char1 = 0; - char char2 = 0x0F; - char char3 = 007; - char char4 = 'a'; - int int1 = 0; - int int2 = 0x0F; - int int3 = -007; - int int4 = 'a'; - long long1 = 0; - long long2 = 0x0F; - long long3 = -007; - long long4 = 0L; - long long5 = 0x0Fl; // SUPPRESS CHECKSTYLE this explicitly tests lowercase l - long long6 = -007L; - long long7 = 'a'; - float float1 = 0.0f; - float float2 = -10e+01f; - float float3 = 0x08.08p3f; - float float4 = 0xFF; - float float5 = 'a'; - double double1 = 0.0; - double double2 = -10e+01; - double double3 = 0x08.08p3; - double double4 = 0xFF; - double double5 = 'a'; -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +public class Literals { + String s = "s"; + boolean boolean1 = false; + boolean boolean2 = true; + Object obj = null; + byte byte1 = 0; + byte byte2 = 0x0F; + byte byte3 = -007; + short short1 = 0; + short short2 = 0x0F; + short short3 = -007; + char char1 = 0; + char char2 = 0x0F; + char char3 = 007; + char char4 = 'a'; + int int1 = 0; + int int2 = 0x0F; + int int3 = -007; + int int4 = 'a'; + long long1 = 0; + long long2 = 0x0F; + long long3 = -007; + long long4 = 0L; + long long5 = 0x0Fl; // SUPPRESS CHECKSTYLE this explicitly tests lowercase l + long long6 = -007L; + long long7 = 'a'; + float float1 = 0.0f; + float float2 = -10e+01f; + float float3 = 0x08.08p3f; + float float4 = 0xFF; + float float5 = 'a'; + double double1 = 0.0; + double double2 = -10e+01; + double double3 = 0x08.08p3; + double double4 = 0xFF; + double double5 = 'a'; +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Operators.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Operators.java index bafc65e6fa..52f3a40400 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Operators.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Operators.java @@ -1,70 +1,70 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -import java.util.List; - -public class Operators { - public void unaryLogicalOperators() { - boolean t; - t = !true; - t = !false; - } - - public void binaryLogicalOperators() { - boolean t; - t = true | false; - t = true & false; - t = true ^ false; - t = true && false; - t = true || false; - t = 1 > 1; - t = 1 >= 1; - t = 1 == 1; - t = 1 != 1; - t = 1 <= 1; - t = 1 < 1; - t = this instanceof List; - t = this instanceof Operators; - } - - public void unaryNumericOperators() { - double t; - t = +1; - t = -1; - t++; - t--; - ++t; - --t; - } - - public void binaryNumericOperators() { - long t; - t = 1 + 1; - t = 1 - 1; - t = 1 / 1; - t = 1 * 1; - t = 1 % 1; - t = 1 << 1; - t = 1 >> 1; - t = 1 >>> 1; - } - - public void assignmentOperators() { - long t; - t = 1; - t *= 1; - t /= 1; - t %= 1; - t += 1; - t -= 1; - t <<= 1; - t >>= 1; - t >>>= 1; - t &= 1; - t ^= 1; - t |= 1; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +import java.util.List; + +public class Operators { + public void unaryLogicalOperators() { + boolean t; + t = !true; + t = !false; + } + + public void binaryLogicalOperators() { + boolean t; + t = true | false; + t = true & false; + t = true ^ false; + t = true && false; + t = true || false; + t = 1 > 1; + t = 1 >= 1; + t = 1 == 1; + t = 1 != 1; + t = 1 <= 1; + t = 1 < 1; + t = this instanceof List; + t = this instanceof Operators; + } + + public void unaryNumericOperators() { + double t; + t = +1; + t = -1; + t++; + t--; + ++t; + --t; + } + + public void binaryNumericOperators() { + long t; + t = 1 + 1; + t = 1 - 1; + t = 1 / 1; + t = 1 * 1; + t = 1 % 1; + t = 1 << 1; + t = 1 >> 1; + t = 1 >>> 1; + } + + public void assignmentOperators() { + long t; + t = 1; + t *= 1; + t /= 1; + t %= 1; + t += 1; + t -= 1; + t <<= 1; + t >>= 1; + t >>>= 1; + t &= 1; + t ^= 1; + t |= 1; + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Promotion.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Promotion.java index 8b08253053..ac977d97bf 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Promotion.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/Promotion.java @@ -1,81 +1,81 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.typeresolution.testdata; - -public class Promotion { - - public void unaryNumericPromotion() { - double t; - t = +((byte) 1); - t = +((short) 1); - t = +((char) 1); - t = +((int) 1); - t = +((long) 1); - t = +((float) 1); - t = +((double) 1); - } - - public void binaryNumericPromotion() { - double t; - t = ((byte) 1) + ((byte) 2); - t = ((byte) 1) + ((short) 2); - t = ((byte) 1) + ((char) 2); - t = ((byte) 1) + ((int) 2); - t = ((byte) 1) + ((long) 2); - t = ((byte) 1) + ((float) 2); - t = ((byte) 1) + ((double) 2); - t = ((short) 1) + ((byte) 2); - t = ((short) 1) + ((short) 2); - t = ((short) 1) + ((char) 2); - t = ((short) 1) + ((int) 2); - t = ((short) 1) + ((long) 2); - t = ((short) 1) + ((float) 2); - t = ((short) 1) + ((double) 2); - t = ((char) 1) + ((byte) 2); - t = ((char) 1) + ((short) 2); - t = ((char) 1) + ((char) 2); - t = ((char) 1) + ((int) 2); - t = ((char) 1) + ((long) 2); - t = ((char) 1) + ((float) 2); - t = ((char) 1) + ((double) 2); - t = ((int) 1) + ((byte) 2); - t = ((int) 1) + ((short) 2); - t = ((int) 1) + ((char) 2); - t = ((int) 1) + ((int) 2); - t = ((int) 1) + ((long) 2); - t = ((int) 1) + ((float) 2); - t = ((int) 1) + ((double) 2); - t = ((long) 1) + ((byte) 2); - t = ((long) 1) + ((short) 2); - t = ((long) 1) + ((char) 2); - t = ((long) 1) + ((int) 2); - t = ((long) 1) + ((long) 2); - t = ((long) 1) + ((float) 2); - t = ((long) 1) + ((double) 2); - t = ((float) 1) + ((byte) 2); - t = ((float) 1) + ((short) 2); - t = ((float) 1) + ((char) 2); - t = ((float) 1) + ((int) 2); - t = ((float) 1) + ((long) 2); - t = ((float) 1) + ((float) 2); - t = ((float) 1) + ((double) 2); - t = ((double) 1) + ((byte) 2); - t = ((double) 1) + ((short) 2); - t = ((double) 1) + ((char) 2); - t = ((double) 1) + ((int) 2); - t = ((double) 1) + ((long) 2); - t = ((double) 1) + ((float) 2); - t = ((double) 1) + ((double) 2); - } - - public void binaryStringPromotion() { - String t; - t = "" + 0; - t = 0 + ""; - t = "" + ""; - t = "" + null; - t = null + ""; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.typeresolution.testdata; + +public class Promotion { + + public void unaryNumericPromotion() { + double t; + t = +((byte) 1); + t = +((short) 1); + t = +((char) 1); + t = +((int) 1); + t = +((long) 1); + t = +((float) 1); + t = +((double) 1); + } + + public void binaryNumericPromotion() { + double t; + t = ((byte) 1) + ((byte) 2); + t = ((byte) 1) + ((short) 2); + t = ((byte) 1) + ((char) 2); + t = ((byte) 1) + ((int) 2); + t = ((byte) 1) + ((long) 2); + t = ((byte) 1) + ((float) 2); + t = ((byte) 1) + ((double) 2); + t = ((short) 1) + ((byte) 2); + t = ((short) 1) + ((short) 2); + t = ((short) 1) + ((char) 2); + t = ((short) 1) + ((int) 2); + t = ((short) 1) + ((long) 2); + t = ((short) 1) + ((float) 2); + t = ((short) 1) + ((double) 2); + t = ((char) 1) + ((byte) 2); + t = ((char) 1) + ((short) 2); + t = ((char) 1) + ((char) 2); + t = ((char) 1) + ((int) 2); + t = ((char) 1) + ((long) 2); + t = ((char) 1) + ((float) 2); + t = ((char) 1) + ((double) 2); + t = ((int) 1) + ((byte) 2); + t = ((int) 1) + ((short) 2); + t = ((int) 1) + ((char) 2); + t = ((int) 1) + ((int) 2); + t = ((int) 1) + ((long) 2); + t = ((int) 1) + ((float) 2); + t = ((int) 1) + ((double) 2); + t = ((long) 1) + ((byte) 2); + t = ((long) 1) + ((short) 2); + t = ((long) 1) + ((char) 2); + t = ((long) 1) + ((int) 2); + t = ((long) 1) + ((long) 2); + t = ((long) 1) + ((float) 2); + t = ((long) 1) + ((double) 2); + t = ((float) 1) + ((byte) 2); + t = ((float) 1) + ((short) 2); + t = ((float) 1) + ((char) 2); + t = ((float) 1) + ((int) 2); + t = ((float) 1) + ((long) 2); + t = ((float) 1) + ((float) 2); + t = ((float) 1) + ((double) 2); + t = ((double) 1) + ((byte) 2); + t = ((double) 1) + ((short) 2); + t = ((double) 1) + ((char) 2); + t = ((double) 1) + ((int) 2); + t = ((double) 1) + ((long) 2); + t = ((double) 1) + ((float) 2); + t = ((double) 1) + ((double) 2); + } + + public void binaryStringPromotion() { + String t; + t = "" + 0; + t = 0 + ""; + t = "" + ""; + t = "" + null; + t = null + ""; + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidBranchingStatementAsLastInLoop.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidBranchingStatementAsLastInLoop.xml index d45301e2bf..5ccf75d5cf 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidBranchingStatementAsLastInLoop.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidBranchingStatementAsLastInLoop.xml @@ -1,218 +1,218 @@ - - - - - - ok: no violations - 0 - - - - violations: break:for/do/while, continue:for/do/while and return:for/do/while - 9 - - - - violations: break:for/do/while - for|do|while - - - 3 - - - - violations: continue:for/do/while - - for|do|while - - 3 - - - - violations: return:for/do/while - - - for|do|while - 3 - - - - violations: break:for - for - - - 1 - - - - violations: break:do - do - - - 1 - - - - violations: break:while - while - - - 1 - - - - violations: continue:for - - for - - 1 - - - - violations: continue:do - - do - - 1 - - - - violations: continue:while - - while - - 1 - - - - violations: return:for - - - for - 1 - - - - violations: return:do - - - do - 1 - - - - violations: return:while - - - while - 1 - - - - - #1170 false positive with switch in loop - 0 - - - + + + + + + ok: no violations + 0 + + + + violations: break:for/do/while, continue:for/do/while and return:for/do/while + 9 + + + + violations: break:for/do/while + for|do|while + + + 3 + + + + violations: continue:for/do/while + + for|do|while + + 3 + + + + violations: return:for/do/while + + + for|do|while + 3 + + + + violations: break:for + for + + + 1 + + + + violations: break:do + do + + + 1 + + + + violations: break:while + while + + + 1 + + + + violations: continue:for + + for + + 1 + + + + violations: continue:do + + do + + 1 + + + + violations: continue:while + + while + + 1 + + + + violations: return:for + + + for + 1 + + + + violations: return:do + + + do + 1 + + + + violations: return:while + + + while + 1 + + + + + #1170 false positive with switch in loop + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidThreadGroup.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidThreadGroup.xml index 5f5119f049..5e644240e8 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidThreadGroup.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/basic/xml/AvoidThreadGroup.xml @@ -1,102 +1,102 @@ - - - - + + + - 1 - + 1 + - - - - 1 - - - - - 1 - - - - - 1 - - - - - 0 - - - - - 0 - - - - false positive, bug #1018 - 0 - - - + } +} + ]]> + + + + 1 + + + + + 1 + + + + + 1 + + + + + 0 + + + + + 0 + + + + false positive, bug #1018 + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/imports/xml/UnnecessaryFullyQualifiedName.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/imports/xml/UnnecessaryFullyQualifiedName.xml index c987b112fe..935963ea71 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/imports/xml/UnnecessaryFullyQualifiedName.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/imports/xml/UnnecessaryFullyQualifiedName.xml @@ -1,390 +1,390 @@ - - - - - 0 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - #1078 Package statement introduces false positive UnnecessaryFullyQualifiedName violation - 0 - - - - - #1404 Java8 'Unnecessary use of fully qualified name' in Streams Collector - 1 - 17 - - Unnecessary use of fully qualified name 'Collectors.toList' due to existing static import 'java.util.stream.Collectors.toList' - - - - - - #1436 UnnecessaryFullyQualifiedName false positive on clashing static imports with enums - 0 - - - - - #1546 part 1 UnnecessaryFullyQualifiedName doesn't take into consideration conflict resolution - 0 - - - - - #1546 part 2 UnnecessaryFullyQualifiedName doesn't take into consideration conflict resolution - 0 - - - - #1555 - UnnecessaryFullyQualifiedName for conflict resolution with inner class - 0 - - - + + + + + 0 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + #1078 Package statement introduces false positive UnnecessaryFullyQualifiedName violation + 0 + + + + + #1404 Java8 'Unnecessary use of fully qualified name' in Streams Collector + 1 + 17 + + Unnecessary use of fully qualified name 'Collectors.toList' due to existing static import 'java.util.stream.Collectors.toList' + + + + + + #1436 UnnecessaryFullyQualifiedName false positive on clashing static imports with enums + 0 + + + + + #1546 part 1 UnnecessaryFullyQualifiedName doesn't take into consideration conflict resolution + 0 + + + + + #1546 part 2 UnnecessaryFullyQualifiedName doesn't take into consideration conflict resolution + 0 + + + + #1555 - UnnecessaryFullyQualifiedName for conflict resolution with inner class + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/JUnitTestContainsTooManyAsserts.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/JUnitTestContainsTooManyAsserts.xml index 28d23c3296..379dc377fe 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/JUnitTestContainsTooManyAsserts.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/JUnitTestContainsTooManyAsserts.xml @@ -1,133 +1,133 @@ - - - - - 0 - - - - - 0 - - - - - 0 - - - - - 0 - - - - - 1 - - - - - 1 - - - - - 0 - 2 - - - - - 0 - 2 - - + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + 1 + + + + + 0 + 2 + + + + + 0 + 2 + + \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/UseAssertTrueInsteadOfAssertEquals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/UseAssertTrueInsteadOfAssertEquals.xml index fe15fbd905..0c965ec38f 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/UseAssertTrueInsteadOfAssertEquals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/junit/xml/UseAssertTrueInsteadOfAssertEquals.xml @@ -1,96 +1,96 @@ - - - - - 0 - - - - - 5 - - - - #1323 False positive case of UseAssertTrueInsteadOfAssertEquals - 0 - - - - - - - 8 - - - - - - - 0 - - + + + + + 0 + + + + + 5 + + + + #1323 False positive case of UseAssertTrueInsteadOfAssertEquals + 0 + + + + + + + 8 + + + + + + + 0 + + \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/optimizations/xml/RedundantFieldInitializer.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/optimizations/xml/RedundantFieldInitializer.xml index 72cd71aa88..18f7aa03d9 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/optimizations/xml/RedundantFieldInitializer.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/optimizations/xml/RedundantFieldInitializer.xml @@ -1,1315 +1,1315 @@ - - - - multiple declarations - 5 - - - - references - 7 - - - - arrays of primitives - 7 - - - - arrays of objects - 2 - - - - mixed arrays - 5 - - - - nested class - 4 - - - - boolean - 2 - - - - byte - 14 - - - - char - 14 - - - - short - 14 - - - - int - 14 - - - - long - 14 - - - - float - 22 - - - - double - 22 - - - - - #1298 Member variable int type with value 0xff000000 causes processing error - 0 - -public class LinePoint { - private int mColor = 0xFF000000; -} - - - - Java7 binary literals and underscores - 5 - 12,13,14,15,16 - -public class Bar { - private int x = 0b0101; - private int y = 0B0101; - private long xl = 0b0101l; - private long yl = 0B0101L; - - private int a = 12_34; - private int b = 0xff_00_00_00; - private long c = 0b11010010_01101001_10010100_10010010; - - // now problem cases - private int iszero1 = 0b0; - private int iszero2 = 0B0; - private long iszero3 = 0b0l; - private long iszero4 = 0B0L; - private int iszero5 = 0b0_______0; -} - - - - - #1418 RedundantFieldInitializer false positive with large long value - 0 - - - - - #1443 RedundantFieldInitializer: False positive for small floats - 0 - - - + + + + multiple declarations + 5 + + + + references + 7 + + + + arrays of primitives + 7 + + + + arrays of objects + 2 + + + + mixed arrays + 5 + + + + nested class + 4 + + + + boolean + 2 + + + + byte + 14 + + + + char + 14 + + + + short + 14 + + + + int + 14 + + + + long + 14 + + + + float + 22 + + + + double + 22 + + + + + #1298 Member variable int type with value 0xff000000 causes processing error + 0 + +public class LinePoint { + private int mColor = 0xFF000000; +} + + + + Java7 binary literals and underscores + 5 + 12,13,14,15,16 + +public class Bar { + private int x = 0b0101; + private int y = 0B0101; + private long xl = 0b0101l; + private long yl = 0B0101L; + + private int a = 12_34; + private int b = 0xff_00_00_00; + private long c = 0b11010010_01101001_10010100_10010010; + + // now problem cases + private int iszero1 = 0b0; + private int iszero2 = 0B0; + private long iszero3 = 0b0l; + private long iszero4 = 0B0L; + private int iszero5 = 0b0_______0; +} + + + + + #1418 RedundantFieldInitializer false positive with large long value + 0 + + + + + #1443 RedundantFieldInitializer: False positive for small floats + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/strictexception/xml/AvoidLosingExceptionInformation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/strictexception/xml/AvoidLosingExceptionInformation.xml index d99a11755a..71362fc8bc 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/strictexception/xml/AvoidLosingExceptionInformation.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/strictexception/xml/AvoidLosingExceptionInformation.xml @@ -1,100 +1,100 @@ - - - - - 1 - - - - - 0 - - - - - 0 - - - - - 2 - - - - - 5 - - - + + + + + 1 + + + + + 0 + + + + + 0 + + + + + 2 + + + + + 5 + + + diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java index 45c723c48d..cf21d6fca8 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java @@ -1,60 +1,60 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript; - -import java.io.Writer; - -import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; -import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.VisitorStarter; -import net.sourceforge.pmd.lang.XPathHandler; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; -import net.sourceforge.pmd.lang.ecmascript.ast.DumpFacade; -import net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptNode; -import net.sourceforge.pmd.lang.ecmascript.rule.EcmascriptRuleViolationFactory; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; - -import net.sf.saxon.sxpath.IndependentContext; - -/** - * Implementation of LanguageVersionHandler for the ECMAScript Version 3. - */ -public class Ecmascript3Handler extends AbstractLanguageVersionHandler { - - @Override - public XPathHandler getXPathHandler() { - return new AbstractASTXPathHandler() { - public void initialize() { - } - - public void initialize(IndependentContext context) { - } - }; - } - - public RuleViolationFactory getRuleViolationFactory() { - return EcmascriptRuleViolationFactory.INSTANCE; - } - - @Override - public ParserOptions getDefaultParserOptions() { - return new EcmascriptParserOptions(); - } - - public Parser getParser(ParserOptions parserOptions) { - return new Ecmascript3Parser(parserOptions); - } - - @Override - public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) { - return new VisitorStarter() { - public void start(Node rootNode) { - new DumpFacade().initializeWith(writer, prefix, recurse, (EcmascriptNode) rootNode); - } - }; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript; + +import java.io.Writer; + +import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.VisitorStarter; +import net.sourceforge.pmd.lang.XPathHandler; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler; +import net.sourceforge.pmd.lang.ecmascript.ast.DumpFacade; +import net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptNode; +import net.sourceforge.pmd.lang.ecmascript.rule.EcmascriptRuleViolationFactory; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +import net.sf.saxon.sxpath.IndependentContext; + +/** + * Implementation of LanguageVersionHandler for the ECMAScript Version 3. + */ +public class Ecmascript3Handler extends AbstractLanguageVersionHandler { + + @Override + public XPathHandler getXPathHandler() { + return new AbstractASTXPathHandler() { + public void initialize() { + } + + public void initialize(IndependentContext context) { + } + }; + } + + public RuleViolationFactory getRuleViolationFactory() { + return EcmascriptRuleViolationFactory.INSTANCE; + } + + @Override + public ParserOptions getDefaultParserOptions() { + return new EcmascriptParserOptions(); + } + + public Parser getParser(ParserOptions parserOptions) { + return new Ecmascript3Parser(parserOptions); + } + + @Override + public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) { + return new VisitorStarter() { + public void start(Node rootNode) { + new DumpFacade().initializeWith(writer, prefix, recurse, (EcmascriptNode) rootNode); + } + }; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java index 732235e793..5b3efb7eca 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java @@ -1,45 +1,45 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript; - -import java.io.Reader; -import java.util.Map; - -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.ParseException; -import net.sourceforge.pmd.lang.ecmascript5.Ecmascript5TokenManager; - -/** - * Adapter for the EcmascriptParser. - */ -public class Ecmascript3Parser extends AbstractParser { - private net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser ecmascriptParser; - - public Ecmascript3Parser(ParserOptions parserOptions) { - super(parserOptions); - ecmascriptParser = new net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser( - (EcmascriptParserOptions) parserOptions); - } - - @Override - public TokenManager createTokenManager(Reader source) { - return new Ecmascript5TokenManager(source); - } - - public boolean canParse() { - return true; - } - - public Node parse(String fileName, Reader source) throws ParseException { - return ecmascriptParser.parse(source); - } - - public Map getSuppressMap() { - return ecmascriptParser.getSuppressMap(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript; + +import java.io.Reader; +import java.util.Map; + +import net.sourceforge.pmd.lang.AbstractParser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.ParseException; +import net.sourceforge.pmd.lang.ecmascript5.Ecmascript5TokenManager; + +/** + * Adapter for the EcmascriptParser. + */ +public class Ecmascript3Parser extends AbstractParser { + private net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser ecmascriptParser; + + public Ecmascript3Parser(ParserOptions parserOptions) { + super(parserOptions); + ecmascriptParser = new net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser( + (EcmascriptParserOptions) parserOptions); + } + + @Override + public TokenManager createTokenManager(Reader source) { + return new Ecmascript5TokenManager(source); + } + + public boolean canParse() { + return true; + } + + public Node parse(String fileName, Reader source) throws ParseException { + return ecmascriptParser.parse(source); + } + + public Map getSuppressMap() { + return ecmascriptParser.getSuppressMap(); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptParserOptions.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptParserOptions.java index 9a4fd368fe..e40bb86fe3 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptParserOptions.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptParserOptions.java @@ -1,129 +1,129 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript; - -import org.mozilla.javascript.Context; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; -import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty; -import net.sourceforge.pmd.util.StringUtil; - -public class EcmascriptParserOptions extends ParserOptions { - - public enum Version { - VERSION_DEFAULT("default", Context.VERSION_DEFAULT), - VERSION_1_0("1.0", Context.VERSION_1_0), - VERSION_1_1("1.1", Context.VERSION_1_1), - VERSION_1_2("1.2", Context.VERSION_1_2), - VERSION_1_3("1.3", Context.VERSION_1_3), - VERSION_1_4("1.4", Context.VERSION_1_4), - VERSION_1_5("1.5", Context.VERSION_1_5), - VERSION_1_6("1.6", Context.VERSION_1_6), - VERSION_1_7("1.7", Context.VERSION_1_7), - VERSION_1_8("1.8", Context.VERSION_1_8); - - private final String name; - private final int version; - - Version(String name, int version) { - this.name = name; - this.version = version; - } - - public String getLabel() { - return name; - } - - public int getVersion() { - return version; - } - } - - private static final String[] VERSION_LABELS = new String[] { Version.VERSION_DEFAULT.getLabel(), - Version.VERSION_1_0.getLabel(), Version.VERSION_1_1.getLabel(), Version.VERSION_1_2.getLabel(), - Version.VERSION_1_3.getLabel(), Version.VERSION_1_4.getLabel(), Version.VERSION_1_5.getLabel(), - Version.VERSION_1_6.getLabel(), Version.VERSION_1_7.getLabel(), Version.VERSION_1_8.getLabel(), }; - - // Note: The UI order values are chosen to be larger than those built into - // XPathRule. - public static final BooleanProperty RECORDING_COMMENTS_DESCRIPTOR = new BooleanProperty("recordingComments", - "Specifies that comments are produced in the AST.", Boolean.TRUE, 3.0f); - public static final BooleanProperty RECORDING_LOCAL_JSDOC_COMMENTS_DESCRIPTOR = new BooleanProperty( - "recordingLocalJsDocComments", "Specifies that JsDoc comments are produced in the AST.", Boolean.TRUE, - 4.0f); - public static final EnumeratedProperty RHINO_LANGUAGE_VERSION = new EnumeratedProperty<>( - "rhinoLanguageVersion", - "Specifies the Rhino Language Version to use for parsing. Defaults to Rhino default.", VERSION_LABELS, - Version.values(), 0, 5.0f); - - private boolean recordingComments; - private boolean recordingLocalJsDocComments; - private Version rhinoLanguageVersion; - - public EcmascriptParserOptions() { - this.recordingComments = RECORDING_COMMENTS_DESCRIPTOR.defaultValue().booleanValue(); - this.recordingLocalJsDocComments = RECORDING_LOCAL_JSDOC_COMMENTS_DESCRIPTOR.defaultValue().booleanValue(); - this.rhinoLanguageVersion = (Version) RHINO_LANGUAGE_VERSION - .valueFrom((String) RHINO_LANGUAGE_VERSION.defaultValue()); - } - - public EcmascriptParserOptions(Rule rule) { - this.recordingComments = rule.getProperty(RECORDING_COMMENTS_DESCRIPTOR); - this.recordingLocalJsDocComments = rule.getProperty(RECORDING_LOCAL_JSDOC_COMMENTS_DESCRIPTOR); - this.rhinoLanguageVersion = (Version) RHINO_LANGUAGE_VERSION - .valueFrom((String) rule.getProperty(RHINO_LANGUAGE_VERSION)); - } - - public boolean isRecordingComments() { - return this.recordingComments; - } - - public void setRecordingComments(boolean recordingComments) { - this.recordingComments = recordingComments; - } - - public boolean isRecordingLocalJsDocComments() { - return this.recordingLocalJsDocComments; - } - - public void setRecordingLocalJsDocComments(boolean recordingLocalJsDocComments) { - this.recordingLocalJsDocComments = recordingLocalJsDocComments; - } - - public Version getRhinoLanguageVersion() { - return this.rhinoLanguageVersion; - } - - public void setRhinoLanguageVersion(Version rhinoLanguageVersion) { - this.rhinoLanguageVersion = rhinoLanguageVersion; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + (recordingComments ? 1231 : 1237); - result = prime * result + (recordingLocalJsDocComments ? 1231 : 1237); - result = prime * result + ((rhinoLanguageVersion == null) ? 0 : rhinoLanguageVersion.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final EcmascriptParserOptions that = (EcmascriptParserOptions) obj; - return StringUtil.isSame(this.suppressMarker, that.suppressMarker, false, false, false) - && this.recordingComments == that.recordingComments - && this.recordingLocalJsDocComments == that.recordingLocalJsDocComments - && this.rhinoLanguageVersion == that.rhinoLanguageVersion; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript; + +import org.mozilla.javascript.Context; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty; +import net.sourceforge.pmd.util.StringUtil; + +public class EcmascriptParserOptions extends ParserOptions { + + public enum Version { + VERSION_DEFAULT("default", Context.VERSION_DEFAULT), + VERSION_1_0("1.0", Context.VERSION_1_0), + VERSION_1_1("1.1", Context.VERSION_1_1), + VERSION_1_2("1.2", Context.VERSION_1_2), + VERSION_1_3("1.3", Context.VERSION_1_3), + VERSION_1_4("1.4", Context.VERSION_1_4), + VERSION_1_5("1.5", Context.VERSION_1_5), + VERSION_1_6("1.6", Context.VERSION_1_6), + VERSION_1_7("1.7", Context.VERSION_1_7), + VERSION_1_8("1.8", Context.VERSION_1_8); + + private final String name; + private final int version; + + Version(String name, int version) { + this.name = name; + this.version = version; + } + + public String getLabel() { + return name; + } + + public int getVersion() { + return version; + } + } + + private static final String[] VERSION_LABELS = new String[] { Version.VERSION_DEFAULT.getLabel(), + Version.VERSION_1_0.getLabel(), Version.VERSION_1_1.getLabel(), Version.VERSION_1_2.getLabel(), + Version.VERSION_1_3.getLabel(), Version.VERSION_1_4.getLabel(), Version.VERSION_1_5.getLabel(), + Version.VERSION_1_6.getLabel(), Version.VERSION_1_7.getLabel(), Version.VERSION_1_8.getLabel(), }; + + // Note: The UI order values are chosen to be larger than those built into + // XPathRule. + public static final BooleanProperty RECORDING_COMMENTS_DESCRIPTOR = new BooleanProperty("recordingComments", + "Specifies that comments are produced in the AST.", Boolean.TRUE, 3.0f); + public static final BooleanProperty RECORDING_LOCAL_JSDOC_COMMENTS_DESCRIPTOR = new BooleanProperty( + "recordingLocalJsDocComments", "Specifies that JsDoc comments are produced in the AST.", Boolean.TRUE, + 4.0f); + public static final EnumeratedProperty RHINO_LANGUAGE_VERSION = new EnumeratedProperty<>( + "rhinoLanguageVersion", + "Specifies the Rhino Language Version to use for parsing. Defaults to Rhino default.", VERSION_LABELS, + Version.values(), 0, 5.0f); + + private boolean recordingComments; + private boolean recordingLocalJsDocComments; + private Version rhinoLanguageVersion; + + public EcmascriptParserOptions() { + this.recordingComments = RECORDING_COMMENTS_DESCRIPTOR.defaultValue().booleanValue(); + this.recordingLocalJsDocComments = RECORDING_LOCAL_JSDOC_COMMENTS_DESCRIPTOR.defaultValue().booleanValue(); + this.rhinoLanguageVersion = (Version) RHINO_LANGUAGE_VERSION + .valueFrom((String) RHINO_LANGUAGE_VERSION.defaultValue()); + } + + public EcmascriptParserOptions(Rule rule) { + this.recordingComments = rule.getProperty(RECORDING_COMMENTS_DESCRIPTOR); + this.recordingLocalJsDocComments = rule.getProperty(RECORDING_LOCAL_JSDOC_COMMENTS_DESCRIPTOR); + this.rhinoLanguageVersion = (Version) RHINO_LANGUAGE_VERSION + .valueFrom((String) rule.getProperty(RHINO_LANGUAGE_VERSION)); + } + + public boolean isRecordingComments() { + return this.recordingComments; + } + + public void setRecordingComments(boolean recordingComments) { + this.recordingComments = recordingComments; + } + + public boolean isRecordingLocalJsDocComments() { + return this.recordingLocalJsDocComments; + } + + public void setRecordingLocalJsDocComments(boolean recordingLocalJsDocComments) { + this.recordingLocalJsDocComments = recordingLocalJsDocComments; + } + + public Version getRhinoLanguageVersion() { + return this.rhinoLanguageVersion; + } + + public void setRhinoLanguageVersion(Version rhinoLanguageVersion) { + this.rhinoLanguageVersion = rhinoLanguageVersion; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (recordingComments ? 1231 : 1237); + result = prime * result + (recordingLocalJsDocComments ? 1231 : 1237); + result = prime * result + ((rhinoLanguageVersion == null) ? 0 : rhinoLanguageVersion.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final EcmascriptParserOptions that = (EcmascriptParserOptions) obj; + return StringUtil.isSame(this.suppressMarker, that.suppressMarker, false, false, false) + && this.recordingComments == that.recordingComments + && this.recordingLocalJsDocComments == that.recordingLocalJsDocComments + && this.rhinoLanguageVersion == that.rhinoLanguageVersion; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehension.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehension.java index 190f8b8d2e..634825d4dc 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehension.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehension.java @@ -1,40 +1,40 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ArrayComprehension; - -public class ASTArrayComprehension extends AbstractEcmascriptNode { - public ASTArrayComprehension(ArrayComprehension arrayComprehension) { - super(arrayComprehension); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getResult() { - return (EcmascriptNode) jjtGetChild(0); - } - - public int getNumArrayComprehensionLoops() { - return node.getLoops().size(); - } - - public ASTArrayComprehensionLoop getArrayComprehensionLoop(int index) { - return (ASTArrayComprehensionLoop) jjtGetChild(index + 1); - } - - public boolean hasFilter() { - return node.getFilter() != null; - } - - public EcmascriptNode getFilter() { - return (EcmascriptNode) jjtGetChild(jjtGetNumChildren() - 1); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ArrayComprehension; + +public class ASTArrayComprehension extends AbstractEcmascriptNode { + public ASTArrayComprehension(ArrayComprehension arrayComprehension) { + super(arrayComprehension); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getResult() { + return (EcmascriptNode) jjtGetChild(0); + } + + public int getNumArrayComprehensionLoops() { + return node.getLoops().size(); + } + + public ASTArrayComprehensionLoop getArrayComprehensionLoop(int index) { + return (ASTArrayComprehensionLoop) jjtGetChild(index + 1); + } + + public boolean hasFilter() { + return node.getFilter() != null; + } + + public EcmascriptNode getFilter() { + return (EcmascriptNode) jjtGetChild(jjtGetNumChildren() - 1); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehensionLoop.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehensionLoop.java index bfaafa26a6..a19e5920b2 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehensionLoop.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayComprehensionLoop.java @@ -1,29 +1,29 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ArrayComprehensionLoop; - -public class ASTArrayComprehensionLoop extends AbstractEcmascriptNode { - - public ASTArrayComprehensionLoop(ArrayComprehensionLoop arrayComprehensionLoop) { - super(arrayComprehensionLoop); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getIterator() { - return (EcmascriptNode) jjtGetChild(0); - } - - public EcmascriptNode getIteratedObject() { - return (EcmascriptNode) jjtGetChild(1); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ArrayComprehensionLoop; + +public class ASTArrayComprehensionLoop extends AbstractEcmascriptNode { + + public ASTArrayComprehensionLoop(ArrayComprehensionLoop arrayComprehensionLoop) { + super(arrayComprehensionLoop); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getIterator() { + return (EcmascriptNode) jjtGetChild(0); + } + + public EcmascriptNode getIteratedObject() { + return (EcmascriptNode) jjtGetChild(1); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayLiteral.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayLiteral.java index 893bb2e034..24edf8904c 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayLiteral.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTArrayLiteral.java @@ -1,35 +1,35 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ArrayLiteral; - -public class ASTArrayLiteral extends AbstractEcmascriptNode - implements DestructuringNode, TrailingCommaNode { - private boolean trailingComma; - - public ASTArrayLiteral(ArrayLiteral arrayLiteral) { - super(arrayLiteral); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public boolean isDestructuring() { - return node.isDestructuring(); - } - - public boolean isTrailingComma() { - return trailingComma; - } - - public void setTrailingComma(boolean trailingComma) { - this.trailingComma = trailingComma; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ArrayLiteral; + +public class ASTArrayLiteral extends AbstractEcmascriptNode + implements DestructuringNode, TrailingCommaNode { + private boolean trailingComma; + + public ASTArrayLiteral(ArrayLiteral arrayLiteral) { + super(arrayLiteral); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public boolean isDestructuring() { + return node.isDestructuring(); + } + + public boolean isTrailingComma() { + return trailingComma; + } + + public void setTrailingComma(boolean trailingComma) { + this.trailingComma = trailingComma; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAssignment.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAssignment.java index 09a7ffc6b2..df21972ad1 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAssignment.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAssignment.java @@ -1,21 +1,21 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.Assignment; - -public class ASTAssignment extends AbstractInfixEcmascriptNode { - public ASTAssignment(Assignment asssignment) { - super(asssignment); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.Assignment; + +public class ASTAssignment extends AbstractInfixEcmascriptNode { + public ASTAssignment(Assignment asssignment) { + super(asssignment); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAstRoot.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAstRoot.java index 372f5e03df..1da66dbed0 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAstRoot.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTAstRoot.java @@ -1,29 +1,29 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.AstRoot; - -public class ASTAstRoot extends AbstractEcmascriptNode { - public ASTAstRoot(AstRoot astRoot) { - super(astRoot); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public int getNumComments() { - return node.getComments() != null ? node.getComments().size() : 0; - } - - public ASTComment getComment(int index) { - return (ASTComment) jjtGetChild(jjtGetNumChildren() - 1 - getNumComments() + index); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.AstRoot; + +public class ASTAstRoot extends AbstractEcmascriptNode { + public ASTAstRoot(AstRoot astRoot) { + super(astRoot); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public int getNumComments() { + return node.getComments() != null ? node.getComments().size() : 0; + } + + public ASTComment getComment(int index) { + return (ASTComment) jjtGetChild(jjtGetNumChildren() - 1 - getNumComments() + index); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBlock.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBlock.java index 8d7283d289..0664e036ee 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBlock.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBlock.java @@ -1,21 +1,21 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.Block; - -public class ASTBlock extends AbstractEcmascriptNode { - public ASTBlock(Block block) { - super(block); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.Block; + +public class ASTBlock extends AbstractEcmascriptNode { + public ASTBlock(Block block) { + super(block); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBreakStatement.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBreakStatement.java index d9eba6925f..385130951d 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBreakStatement.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTBreakStatement.java @@ -1,30 +1,30 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.BreakStatement; - -public class ASTBreakStatement extends AbstractEcmascriptNode { - public ASTBreakStatement(BreakStatement breakStatement) { - super(breakStatement); - super.setImage(breakStatement.getBreakLabel() != null ? breakStatement.getBreakLabel().getIdentifier() : null); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public boolean hasLabel() { - return node.getBreakLabel() != null; - } - - public ASTName getLabel() { - return (ASTName) jjtGetChild(0); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.BreakStatement; + +public class ASTBreakStatement extends AbstractEcmascriptNode { + public ASTBreakStatement(BreakStatement breakStatement) { + super(breakStatement); + super.setImage(breakStatement.getBreakLabel() != null ? breakStatement.getBreakLabel().getIdentifier() : null); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public boolean hasLabel() { + return node.getBreakLabel() != null; + } + + public ASTName getLabel() { + return (ASTName) jjtGetChild(0); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTCatchClause.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTCatchClause.java index a1ce78296c..07b08e5112 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTCatchClause.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTCatchClause.java @@ -1,37 +1,37 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.CatchClause; - -public class ASTCatchClause extends AbstractEcmascriptNode { - public ASTCatchClause(CatchClause catchClause) { - super(catchClause); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public ASTName getVariableName() { - return (ASTName) jjtGetChild(0); - } - - public boolean isIf() { - return node.getCatchCondition() != null; - } - - public EcmascriptNode getCatchCondition() { - return (EcmascriptNode) jjtGetChild(1); - } - - public ASTBlock getBlock() { - return (ASTBlock) jjtGetChild(jjtGetNumChildren() - 1); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.CatchClause; + +public class ASTCatchClause extends AbstractEcmascriptNode { + public ASTCatchClause(CatchClause catchClause) { + super(catchClause); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public ASTName getVariableName() { + return (ASTName) jjtGetChild(0); + } + + public boolean isIf() { + return node.getCatchCondition() != null; + } + + public EcmascriptNode getCatchCondition() { + return (EcmascriptNode) jjtGetChild(1); + } + + public ASTBlock getBlock() { + return (ASTBlock) jjtGetChild(jjtGetNumChildren() - 1); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTComment.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTComment.java index 25000ab9ba..35d8f676a0 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTComment.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTComment.java @@ -1,25 +1,25 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.Comment; - -public class ASTComment extends AbstractEcmascriptNode { - public ASTComment(Comment comment) { - super(comment); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public String getValue() { - return node.getValue(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.Comment; + +public class ASTComment extends AbstractEcmascriptNode { + public ASTComment(Comment comment) { + super(comment); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public String getValue() { + return node.getValue(); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTConditionalExpression.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTConditionalExpression.java index 687a1aa1ae..2d07a515ef 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTConditionalExpression.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTConditionalExpression.java @@ -1,33 +1,33 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ConditionalExpression; - -public class ASTConditionalExpression extends AbstractEcmascriptNode { - public ASTConditionalExpression(ConditionalExpression conditionalExpression) { - super(conditionalExpression); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getTestExpression() { - return (EcmascriptNode) jjtGetChild(0); - } - - public EcmascriptNode getTrueExpression() { - return (EcmascriptNode) jjtGetChild(1); - } - - public EcmascriptNode getFalseExpression() { - return (EcmascriptNode) jjtGetChild(2); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ConditionalExpression; + +public class ASTConditionalExpression extends AbstractEcmascriptNode { + public ASTConditionalExpression(ConditionalExpression conditionalExpression) { + super(conditionalExpression); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getTestExpression() { + return (EcmascriptNode) jjtGetChild(0); + } + + public EcmascriptNode getTrueExpression() { + return (EcmascriptNode) jjtGetChild(1); + } + + public EcmascriptNode getFalseExpression() { + return (EcmascriptNode) jjtGetChild(2); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTContinueStatement.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTContinueStatement.java index daf5b16d68..7946a193bf 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTContinueStatement.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTContinueStatement.java @@ -1,30 +1,30 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ContinueStatement; - -public class ASTContinueStatement extends AbstractEcmascriptNode { - public ASTContinueStatement(ContinueStatement continueStatement) { - super(continueStatement); - super.setImage(continueStatement.getLabel() != null ? continueStatement.getLabel().getIdentifier() : null); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public boolean hasLabel() { - return node.getLabel() != null; - } - - public ASTName getLabel() { - return (ASTName) jjtGetChild(0); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ContinueStatement; + +public class ASTContinueStatement extends AbstractEcmascriptNode { + public ASTContinueStatement(ContinueStatement continueStatement) { + super(continueStatement); + super.setImage(continueStatement.getLabel() != null ? continueStatement.getLabel().getIdentifier() : null); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public boolean hasLabel() { + return node.getLabel() != null; + } + + public ASTName getLabel() { + return (ASTName) jjtGetChild(0); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTDoLoop.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTDoLoop.java index 7d1560edab..4d19c65dc4 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTDoLoop.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTDoLoop.java @@ -1,29 +1,29 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.DoLoop; - -public class ASTDoLoop extends AbstractEcmascriptNode { - public ASTDoLoop(DoLoop doLoop) { - super(doLoop); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getBody() { - return (EcmascriptNode) jjtGetChild(0); - } - - public EcmascriptNode getCondition() { - return (EcmascriptNode) jjtGetChild(1); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.DoLoop; + +public class ASTDoLoop extends AbstractEcmascriptNode { + public ASTDoLoop(DoLoop doLoop) { + super(doLoop); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getBody() { + return (EcmascriptNode) jjtGetChild(0); + } + + public EcmascriptNode getCondition() { + return (EcmascriptNode) jjtGetChild(1); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTElementGet.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTElementGet.java index 9553bc86ee..b0aac4ff6f 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTElementGet.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTElementGet.java @@ -1,35 +1,35 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ElementGet; - -public class ASTElementGet extends AbstractEcmascriptNode { - public ASTElementGet(ElementGet elementGet) { - super(elementGet); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getTarget() { - if (jjtGetNumChildren() > 0) { - return (EcmascriptNode) jjtGetChild(0); - } - return null; - } - - public EcmascriptNode getElement() { - if (jjtGetNumChildren() > 1) { - return (EcmascriptNode) jjtGetChild(1); - } - return null; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ElementGet; + +public class ASTElementGet extends AbstractEcmascriptNode { + public ASTElementGet(ElementGet elementGet) { + super(elementGet); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getTarget() { + if (jjtGetNumChildren() > 0) { + return (EcmascriptNode) jjtGetChild(0); + } + return null; + } + + public EcmascriptNode getElement() { + if (jjtGetNumChildren() > 1) { + return (EcmascriptNode) jjtGetChild(1); + } + return null; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyExpression.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyExpression.java index 8b9671d826..e6c8a9ab40 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyExpression.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyExpression.java @@ -1,21 +1,21 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.EmptyExpression; - -public class ASTEmptyExpression extends AbstractEcmascriptNode { - public ASTEmptyExpression(EmptyExpression emptyExpression) { - super(emptyExpression); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.EmptyExpression; + +public class ASTEmptyExpression extends AbstractEcmascriptNode { + public ASTEmptyExpression(EmptyExpression emptyExpression) { + super(emptyExpression); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyStatement.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyStatement.java index 72789e22a4..7972311bc0 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyStatement.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTEmptyStatement.java @@ -1,18 +1,18 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.EmptyStatement; - -public class ASTEmptyStatement extends AbstractEcmascriptNode { - public ASTEmptyStatement(EmptyStatement emptyStatement) { - super(emptyStatement); - } - - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.EmptyStatement; + +public class ASTEmptyStatement extends AbstractEcmascriptNode { + public ASTEmptyStatement(EmptyStatement emptyStatement) { + super(emptyStatement); + } + + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTExpressionStatement.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTExpressionStatement.java index 27c7194e27..0757f9329d 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTExpressionStatement.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTExpressionStatement.java @@ -1,26 +1,26 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.Token; -import org.mozilla.javascript.ast.ExpressionStatement; - -public class ASTExpressionStatement extends AbstractEcmascriptNode { - public ASTExpressionStatement(ExpressionStatement expressionStatement) { - super(expressionStatement); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public boolean hasResult() { - return node.getType() == Token.EXPR_RESULT; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.Token; +import org.mozilla.javascript.ast.ExpressionStatement; + +public class ASTExpressionStatement extends AbstractEcmascriptNode { + public ASTExpressionStatement(ExpressionStatement expressionStatement) { + super(expressionStatement); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public boolean hasResult() { + return node.getType() == Token.EXPR_RESULT; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForInLoop.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForInLoop.java index 7af0b17a89..8f2d1c095e 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForInLoop.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForInLoop.java @@ -1,36 +1,36 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ForInLoop; - -public class ASTForInLoop extends AbstractEcmascriptNode { - public ASTForInLoop(ForInLoop forInLoop) { - super(forInLoop); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getIterator() { - return (EcmascriptNode) jjtGetChild(0); - } - - public EcmascriptNode getIteratedObject() { - return (EcmascriptNode) jjtGetChild(1); - } - - public EcmascriptNode getBody() { - return (EcmascriptNode) jjtGetChild(2); - } - - public boolean isForEach() { - return node.isForEach(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ForInLoop; + +public class ASTForInLoop extends AbstractEcmascriptNode { + public ASTForInLoop(ForInLoop forInLoop) { + super(forInLoop); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getIterator() { + return (EcmascriptNode) jjtGetChild(0); + } + + public EcmascriptNode getIteratedObject() { + return (EcmascriptNode) jjtGetChild(1); + } + + public EcmascriptNode getBody() { + return (EcmascriptNode) jjtGetChild(2); + } + + public boolean isForEach() { + return node.isForEach(); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForLoop.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForLoop.java index f0b1901b5e..c2ee8cd4a9 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForLoop.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTForLoop.java @@ -1,36 +1,36 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.ForLoop; - -public class ASTForLoop extends AbstractEcmascriptNode { - public ASTForLoop(ForLoop forLoop) { - super(forLoop); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getInitializer() { - return (EcmascriptNode) jjtGetChild(0); - } - - public EcmascriptNode getCondition() { - return (EcmascriptNode) jjtGetChild(1); - } - - public EcmascriptNode getIncrement() { - return (EcmascriptNode) jjtGetChild(2); - } - - public EcmascriptNode getBody() { - return (EcmascriptNode) jjtGetChild(3); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.ForLoop; + +public class ASTForLoop extends AbstractEcmascriptNode { + public ASTForLoop(ForLoop forLoop) { + super(forLoop); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getInitializer() { + return (EcmascriptNode) jjtGetChild(0); + } + + public EcmascriptNode getCondition() { + return (EcmascriptNode) jjtGetChild(1); + } + + public EcmascriptNode getIncrement() { + return (EcmascriptNode) jjtGetChild(2); + } + + public EcmascriptNode getBody() { + return (EcmascriptNode) jjtGetChild(3); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionCall.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionCall.java index 3dc8c4228d..508987f83d 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionCall.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionCall.java @@ -1,36 +1,36 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.FunctionCall; - -public class ASTFunctionCall extends AbstractEcmascriptNode { - public ASTFunctionCall(FunctionCall functionCall) { - super(functionCall); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public EcmascriptNode getTarget() { - return (EcmascriptNode) jjtGetChild(0); - } - - public int getNumArguments() { - return node.getArguments().size(); - } - - public EcmascriptNode getArgument(int index) { - return (EcmascriptNode) jjtGetChild(index + 1); - } - - public boolean hasArguments() { - return getNumArguments() != 0; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.FunctionCall; + +public class ASTFunctionCall extends AbstractEcmascriptNode { + public ASTFunctionCall(FunctionCall functionCall) { + super(functionCall); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public EcmascriptNode getTarget() { + return (EcmascriptNode) jjtGetChild(0); + } + + public int getNumArguments() { + return node.getArguments().size(); + } + + public EcmascriptNode getArgument(int index) { + return (EcmascriptNode) jjtGetChild(index + 1); + } + + public boolean hasArguments() { + return getNumArguments() != 0; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionNode.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionNode.java index 77ea92b8c2..6c7333efcd 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionNode.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTFunctionNode.java @@ -1,65 +1,65 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.FunctionNode; - -public class ASTFunctionNode extends AbstractEcmascriptNode { - public ASTFunctionNode(FunctionNode functionNode) { - super(functionNode); - super.setImage(functionNode.getName()); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public int getNumParams() { - return node.getParams().size(); - } - - public ASTName getFunctionName() { - if (node.getFunctionName() != null) { - return (ASTName) jjtGetChild(0); - } - return null; - } - - public EcmascriptNode getParam(int index) { - int paramIndex = index; - if (node.getFunctionName() != null) { - paramIndex = index + 1; - } - return (EcmascriptNode) jjtGetChild(paramIndex); - } - - public EcmascriptNode getBody() { - return (EcmascriptNode) jjtGetChild(jjtGetNumChildren() - 1); - } - - @Deprecated // use getBody() instead - public EcmascriptNode getBody(int index) { - return getBody(); - } - - public boolean isClosure() { - return node.isExpressionClosure(); - } - - public boolean isGetter() { - return node.isGetterMethod(); - } - - public boolean isSetter() { - return node.isSetterMethod(); - } - - public boolean isGetterOrSetter() { - return isGetter() || isSetter(); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.FunctionNode; + +public class ASTFunctionNode extends AbstractEcmascriptNode { + public ASTFunctionNode(FunctionNode functionNode) { + super(functionNode); + super.setImage(functionNode.getName()); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public int getNumParams() { + return node.getParams().size(); + } + + public ASTName getFunctionName() { + if (node.getFunctionName() != null) { + return (ASTName) jjtGetChild(0); + } + return null; + } + + public EcmascriptNode getParam(int index) { + int paramIndex = index; + if (node.getFunctionName() != null) { + paramIndex = index + 1; + } + return (EcmascriptNode) jjtGetChild(paramIndex); + } + + public EcmascriptNode getBody() { + return (EcmascriptNode) jjtGetChild(jjtGetNumChildren() - 1); + } + + @Deprecated // use getBody() instead + public EcmascriptNode getBody(int index) { + return getBody(); + } + + public boolean isClosure() { + return node.isExpressionClosure(); + } + + public boolean isGetter() { + return node.isGetterMethod(); + } + + public boolean isSetter() { + return node.isSetterMethod(); + } + + public boolean isGetterOrSetter() { + return isGetter() || isSetter(); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTIfStatement.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTIfStatement.java index 024bff9c75..d5f6f61c08 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTIfStatement.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTIfStatement.java @@ -1,36 +1,36 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.IfStatement; - -public class ASTIfStatement extends AbstractEcmascriptNode { - public ASTIfStatement(IfStatement ifStatement) { - super(ifStatement); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public boolean hasElse() { - return node.getElsePart() != null; - } - - public EcmascriptNode getCondition() { - return (EcmascriptNode) jjtGetChild(0); - } - - public EcmascriptNode getThen() { - return (EcmascriptNode) jjtGetChild(1); - } - - public EcmascriptNode getElse() { - return (EcmascriptNode) jjtGetChild(2); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.IfStatement; + +public class ASTIfStatement extends AbstractEcmascriptNode { + public ASTIfStatement(IfStatement ifStatement) { + super(ifStatement); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public boolean hasElse() { + return node.getElsePart() != null; + } + + public EcmascriptNode getCondition() { + return (EcmascriptNode) jjtGetChild(0); + } + + public EcmascriptNode getThen() { + return (EcmascriptNode) jjtGetChild(1); + } + + public EcmascriptNode getElse() { + return (EcmascriptNode) jjtGetChild(2); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTInfixExpression.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTInfixExpression.java index 3c88b38a11..7c1ae88805 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTInfixExpression.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTInfixExpression.java @@ -1,20 +1,20 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.InfixExpression; - -public class ASTInfixExpression extends AbstractInfixEcmascriptNode { - public ASTInfixExpression(InfixExpression infixExpression) { - super(infixExpression); - } - - /** - * Accept the visitor. - */ - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.ast.InfixExpression; + +public class ASTInfixExpression extends AbstractInfixEcmascriptNode { + public ASTInfixExpression(InfixExpression infixExpression) { + super(infixExpression); + } + + /** + * Accept the visitor. + */ + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTKeywordLiteral.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTKeywordLiteral.java index 33f73cac37..d69ce8034d 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTKeywordLiteral.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTKeywordLiteral.java @@ -1,39 +1,39 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.Token; -import org.mozilla.javascript.ast.KeywordLiteral; - -public class ASTKeywordLiteral extends AbstractEcmascriptNode { - public ASTKeywordLiteral(KeywordLiteral keywordLiteral) { - super(keywordLiteral); - super.setImage(Token.typeToName(keywordLiteral.getType()).toLowerCase()); - } - - /** - * Accept the visitor. - */ - @Override - public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } - - public boolean isBoolean() { - return node.isBooleanLiteral(); - } - - public boolean isThis() { - return node.getType() == Token.THIS; - } - - public boolean isNull() { - return node.getType() == Token.NULL; - } - - public boolean isDebugger() { - return node.getType() == Token.DEBUGGER; - } -} +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.ast; + +import org.mozilla.javascript.Token; +import org.mozilla.javascript.ast.KeywordLiteral; + +public class ASTKeywordLiteral extends AbstractEcmascriptNode { + public ASTKeywordLiteral(KeywordLiteral keywordLiteral) { + super(keywordLiteral); + super.setImage(Token.typeToName(keywordLiteral.getType()).toLowerCase()); + } + + /** + * Accept the visitor. + */ + @Override + public Object jjtAccept(EcmascriptParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public boolean isBoolean() { + return node.isBooleanLiteral(); + } + + public boolean isThis() { + return node.getType() == Token.THIS; + } + + public boolean isNull() { + return node.getType() == Token.NULL; + } + + public boolean isDebugger() { + return node.getType() == Token.DEBUGGER; + } +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTLabel.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTLabel.java index 7781ff7e96..876f4c25df 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTLabel.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/ASTLabel.java @@ -1,21 +1,21 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript.ast; - -import org.mozilla.javascript.ast.Label; - -public class ASTLabel extends AbstractEcmascriptNode