├── docs ├── _data │ ├── glossary.yml │ ├── terms.yml │ ├── definitions.yml │ ├── strings.yml │ ├── tags.yml │ └── alerts.yml ├── _layouts │ ├── none.html │ ├── page_print.html │ └── default_print.html ├── update.sh ├── Gemfile ├── images │ ├── favicon.ico │ ├── company_logo.png │ ├── company_logo_big.png │ └── detekt_in_action.png ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── _includes │ ├── inline_image.html │ ├── callout.html │ ├── note.html │ ├── tip.html │ ├── important.html │ ├── warning.html │ ├── archive.html │ ├── image.html │ ├── footer.html │ ├── custom │ │ ├── getting_started_series_next.html │ │ ├── usermap.html │ │ ├── getting_started_series.html │ │ └── series_acme.html │ ├── google_analytics.html │ ├── feedback.html │ └── toc.html ├── css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ └── boxshadowproperties.css ├── _tooltips │ ├── soccer.html │ ├── football.html │ ├── baseball.html │ └── basketball.html ├── 404.md ├── docker-compose.yml ├── pages │ ├── tags │ │ ├── tag_news.md │ │ └── tag_getting_started.md │ └── suppressing-rules.md ├── _posts │ └── 2018-02-11-website-online.md ├── var │ └── build.sh ├── tooltips.json ├── Dockerfile ├── sitemap.xml ├── js │ └── jquery.ba-throttle-debounce.min.js └── search.json ├── detekt-api ├── src │ ├── test │ │ ├── resources │ │ │ ├── empty.yml │ │ │ ├── oneitem.yml │ │ │ ├── FilteredClass.kt │ │ │ ├── SuppressedObject.kt │ │ │ ├── SuppressedByAllObject.kt │ │ │ ├── composite-test.yml │ │ │ ├── detekt.yml │ │ │ └── SuppressedElements.kt │ │ └── kotlin │ │ │ └── io │ │ │ └── gitlab │ │ │ └── arturbosch │ │ │ └── detekt │ │ │ └── api │ │ │ └── MetricSpec.kt │ └── main │ │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── api │ │ ├── Notification.kt │ │ ├── DetektVisitor.kt │ │ ├── Extension.kt │ │ ├── ConsoleReport.kt │ │ ├── Detektion.kt │ │ ├── ProjectMetric.kt │ │ ├── ThresholdRule.kt │ │ ├── SingleAssign.kt │ │ ├── AnnotationExcluder.kt │ │ ├── MultiRule.kt │ │ ├── CompositeConfig.kt │ │ ├── OutputReport.kt │ │ ├── SplitPattern.kt │ │ └── Entity.kt └── build.gradle.kts ├── detekt-cli └── src │ ├── test │ ├── resources │ │ ├── empty.txt │ │ ├── configs │ │ │ ├── one.yml │ │ │ ├── two.yml │ │ │ ├── three.yml │ │ │ ├── fail-fast-only.yml │ │ │ └── fail-fast-override.yml │ │ ├── invalid-smell-baseline.txt │ │ ├── META-INF │ │ │ └── services │ │ │ │ ├── io.gitlab.arturbosch.detekt.api.OutputReport │ │ │ │ ├── io.gitlab.arturbosch.detekt.api.RuleSetProvider │ │ │ │ └── io.gitlab.arturbosch.detekt.api.ConsoleReport │ │ ├── cases │ │ │ └── Poko.kt │ │ ├── findings-report.txt │ │ ├── complexity-report.txt │ │ └── smell-baseline.xml │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── cli │ │ ├── console │ │ └── ResourceReader.kt │ │ └── out │ │ └── TxtOutputReportTest.kt │ └── main │ ├── kotlin │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── cli │ │ ├── runners │ │ ├── Executable.kt │ │ └── ConfigExporter.kt │ │ ├── baseline │ │ ├── Listing.kt │ │ ├── internal │ │ │ └── package-info.java │ │ ├── Blacklist.kt │ │ ├── Whitelist.kt │ │ ├── Baseline.kt │ │ └── XmlExtensions.kt │ │ ├── LOG.kt │ │ ├── console │ │ ├── NotificationReport.kt │ │ ├── ComplexityReport.kt │ │ ├── ComplexityMetric.kt │ │ └── ProjectStatisticsReport.kt │ │ ├── out │ │ └── TxtOutputReport.kt │ │ ├── Junk.kt │ │ ├── DetektProgressListener.kt │ │ └── FilteredDetectionResult.kt │ └── resources │ ├── META-INF │ └── services │ │ ├── io.gitlab.arturbosch.detekt.api.OutputReport │ │ ├── io.gitlab.arturbosch.detekt.api.ConsoleReport │ │ └── io.gitlab.arturbosch.detekt.api.FileProcessListener │ └── default-html-report-template.html ├── detekt-rules ├── src │ ├── test │ │ ├── resources │ │ │ ├── cases │ │ │ │ ├── EmptyKtFile.kt │ │ │ │ ├── NewLineAtEndOfFile.kt │ │ │ │ ├── PreferToOverPairSyntaxNegative.kt │ │ │ │ ├── TrailingWhitespaceNegative.kt │ │ │ │ ├── EmptyDefaultConstructorPositive.kt │ │ │ │ ├── NoTabsNegative.kt │ │ │ │ ├── MultilineStringLiteralDuplication.kt │ │ │ │ ├── Default.kt │ │ │ │ ├── LongMethodNegative.kt │ │ │ │ ├── NoTabsPositive.kt │ │ │ │ ├── PreferToOverPairSyntaxPositive.kt │ │ │ │ ├── FunctionReturningConstantNegative.kt │ │ │ │ ├── TooGenericExceptionsOptions.kt │ │ │ │ ├── TooManyFunctionsTopLevel.kt │ │ │ │ ├── UnconditionalJumpStatementInLoopNegative.kt │ │ │ │ ├── ConstInObjects.kt │ │ │ │ ├── SwallowedExceptionPositive.kt │ │ │ │ ├── LabeledExpressionNegative.kt │ │ │ │ ├── EmptyDefaultConstructorNegative.kt │ │ │ │ ├── LongMethodPositive.kt │ │ │ │ ├── LoopWithTooManyJumpStatementsNegative.kt │ │ │ │ ├── CollapsibleIfsPositive.kt │ │ │ │ ├── SwallowedExceptionNegative.kt │ │ │ │ ├── TrailingWhitespacePositive.kt │ │ │ │ ├── MandatoryBracesIfStatementsNegative.kt │ │ │ │ ├── MandatoryBracesIfStatementsPositive.kt │ │ │ │ ├── ComplexInterfaceNegative.kt │ │ │ │ ├── DataClassContainsFunctionsPositive.kt │ │ │ │ ├── NestedClassVisibilityNegative.kt │ │ │ │ ├── MayBeConstNegative.kt │ │ │ │ ├── RethrowCaughtExceptionNegative.kt │ │ │ │ ├── EmptyIfPositive.kt │ │ │ │ ├── LoopWithTooManyJumpStatementsPositive.kt │ │ │ │ ├── DataClassContainsFunctionsNegative.kt │ │ │ │ ├── IteratorImplNegative.kt │ │ │ │ ├── SerializableNegative.kt │ │ │ │ ├── EmptyIfNegative.kt │ │ │ │ ├── CollapsibleIfsNegative.kt │ │ │ │ ├── OverloadedMethods.kt │ │ │ │ ├── ComplexInterfacePositive.kt │ │ │ │ ├── TooGenericExceptions.kt │ │ │ │ ├── ExceptionRaisedInMethodsNegative.kt │ │ │ │ ├── UnconditionalJumpStatementInLoopPositive.kt │ │ │ │ ├── RethrowCaughtExceptionPositive.kt │ │ │ │ ├── ProtectedMemberInFinalClassNegative.kt │ │ │ │ ├── EqualsAlwaysReturnsTrueOrFalseNegative.kt │ │ │ │ ├── NestedClassVisibilityPositive.kt │ │ │ │ ├── SerializablePositive.kt │ │ │ │ ├── TooManyFunctions.kt │ │ │ │ ├── UnnecessaryAbstractClassNegative.kt │ │ │ │ ├── ComplexClass.kt │ │ │ │ ├── Empty.kt │ │ │ │ ├── FunctionReturningConstantPositive.kt │ │ │ │ ├── UnnecessaryAbstractClassPositive.kt │ │ │ │ └── UseDataClassPositive.kt │ │ │ ├── deactivated-exceptions.yml │ │ │ ├── SuppressStringLiteralDuplication.kt │ │ │ └── deactivated-empty-blocks.yml │ │ └── kotlin │ │ │ └── io │ │ │ └── gitlab │ │ │ └── arturbosch │ │ │ └── detekt │ │ │ └── rules │ │ │ ├── documentation │ │ │ └── UndocumentedPublicFunctionSpec.kt │ │ │ ├── style │ │ │ ├── optional │ │ │ │ └── ConditionalPathVisitorTest.kt │ │ │ └── NestedClassesVisibilitySpec.kt │ │ │ ├── bugs │ │ │ ├── UnreachableCodeSpec.kt │ │ │ ├── ExplicitGarbageCollectionCallSpec.kt │ │ │ └── UnsafeCastSpec.kt │ │ │ ├── exceptions │ │ │ └── SwallowedExceptionSpec.kt │ │ │ ├── CommonSpec.kt │ │ │ ├── complexity │ │ │ ├── ComplexConditionSpec.kt │ │ │ ├── LongMethodSpec.kt │ │ │ └── LabeledExpressionSpec.kt │ │ │ ├── performance │ │ │ └── UnnecessaryTemporaryInstantiationSpec.kt │ │ │ ├── naming │ │ │ ├── PackageNamingSpec.kt │ │ │ └── EnumNamingSpec.kt │ │ │ └── empty │ │ │ └── EmptyIfBlockSpec.kt │ └── main │ │ ├── kotlin │ │ └── io │ │ │ └── gitlab │ │ │ └── arturbosch │ │ │ └── detekt │ │ │ └── rules │ │ │ ├── AllowedExceptionNamePattern.kt │ │ │ ├── IdentifierName.kt │ │ │ ├── Keywords.kt │ │ │ ├── naming │ │ │ └── util │ │ │ │ └── ExcludeClass.kt │ │ │ ├── documentation │ │ │ └── PrivateElementUtil.kt │ │ │ ├── StringExtensions.kt │ │ │ ├── empty │ │ │ ├── EmptyInitBlock.kt │ │ │ ├── EmptyElseBlock.kt │ │ │ ├── EmptyForBlock.kt │ │ │ ├── EmptySecondaryConstructor.kt │ │ │ ├── EmptyWhileBlock.kt │ │ │ ├── EmptyDoWhileBlock.kt │ │ │ ├── EmptyFinallyBlock.kt │ │ │ ├── EmptyKtFile.kt │ │ │ └── EmptyWhenBlock.kt │ │ │ ├── style │ │ │ ├── Junk.kt │ │ │ └── FileParsingRule.kt │ │ │ ├── MethodSignature.kt │ │ │ └── providers │ │ │ └── EmptyCodeProvider.kt │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── io.gitlab.arturbosch.detekt.api.RuleSetProvider └── build.gradle.kts ├── detekt-gradle-plugin ├── settings.gradle.kts ├── src │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── gitlab │ │ │ └── arturbosch │ │ │ └── detekt │ │ │ ├── BuildFailure.kt │ │ │ ├── extensions │ │ │ ├── DetektReportType.kt │ │ │ └── DetektReports.kt │ │ │ ├── KotlinExtension.kt │ │ │ └── invoke │ │ │ └── ProcessExecutor.kt │ └── test │ │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ ├── TestVersion.kt │ │ ├── Submodule.kt │ │ └── ProjectLayout.kt └── gradle │ └── wrapper │ └── gradle-wrapper.properties ├── detekt-watcher ├── src │ ├── test │ │ └── resources │ │ │ └── Default.kt │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ ├── io.gitlab.arturbosch.ksh.api.Prompt │ │ │ └── io.gitlab.arturbosch.ksh.api.ShellClass │ │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── watcher │ │ ├── config │ │ ├── ConfigProperties.kt │ │ ├── DetektPrompt.kt │ │ ├── DetektHome.kt │ │ └── DependencyInjection.kt │ │ ├── service │ │ ├── Models.kt │ │ └── DirectoryRegisteringVisitor.kt │ │ └── state │ │ └── Parameters.kt └── README.md ├── detekt-core ├── src │ ├── test │ │ ├── resources │ │ │ ├── cases │ │ │ │ ├── KotlinScript.kts │ │ │ │ ├── Test.kt │ │ │ │ └── Default.kt │ │ │ ├── empty │ │ │ │ ├── EmptyEnum.kt │ │ │ │ └── EmptyInterface.kt │ │ │ ├── sample-rule-set.jar │ │ │ ├── fields │ │ │ │ └── ClassWithFields.kt │ │ │ ├── META-INF │ │ │ │ └── services │ │ │ │ │ └── io.gitlab.arturbosch.detekt.api.RuleSetProvider │ │ │ ├── patterns │ │ │ │ ├── exclude-FindName.yml │ │ │ │ └── test-pattern.yml │ │ │ └── comments │ │ │ │ └── CommentsClass.kt │ │ └── kotlin │ │ │ └── io │ │ │ └── gitlab │ │ │ └── arturbosch │ │ │ └── detekt │ │ │ └── core │ │ │ ├── processors │ │ │ ├── LOCVisitorTest.kt │ │ │ ├── SLOCVisitorTest.kt │ │ │ ├── CLOCVisitorTest.kt │ │ │ ├── FieldCountVisitorTest.kt │ │ │ ├── MethodCountVisitorTest.kt │ │ │ ├── KtFileCountVisitorTest.kt │ │ │ └── PackageCountVisitorTest.kt │ │ │ ├── DetektSpec.kt │ │ │ ├── KtCompilerTest.kt │ │ │ ├── CustomRuleSetProviderSpec.kt │ │ │ └── DetektorTest.kt │ └── main │ │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── core │ │ ├── ModificationNotification.kt │ │ ├── processors │ │ ├── util │ │ │ └── Junk.kt │ │ ├── AbstractProjectMetricProcessor.kt │ │ ├── KtFileCountProcessor.kt │ │ ├── ProjectLOCProcessor.kt │ │ ├── ProjectLLOCProcessor.kt │ │ ├── ProjectComplexityProcessor.kt │ │ ├── AbstractProcessor.kt │ │ ├── ClassCountProcessor.kt │ │ ├── PropertyCountProcessor.kt │ │ └── FunctionCountProcessor.kt │ │ └── DebugUtils.kt └── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── detekt-formatting └── src │ ├── main │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ └── io.gitlab.arturbosch.detekt.api.RuleSetProvider │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── formatting │ │ ├── EditorConfigConstants.kt │ │ └── wrappers │ │ ├── Filename.kt │ │ ├── FinalNewline.kt │ │ ├── NoSemicolons.kt │ │ ├── NoUnusedImports.kt │ │ ├── PackageName.kt │ │ ├── ImportOrdering.kt │ │ ├── NoMultipleSpaces.kt │ │ ├── ChainWrapping.kt │ │ ├── CommentSpacing.kt │ │ ├── NoUnitReturn.kt │ │ ├── NoLineBreakAfterElse.kt │ │ ├── NoWildcardImports.kt │ │ ├── NoEmptyClassBody.kt │ │ ├── NoTrailingSpaces.kt │ │ ├── SpacingAroundColon.kt │ │ ├── SpacingAroundComma.kt │ │ ├── ModifierOrdering.kt │ │ ├── NoItParamInMultilineLambda.kt │ │ ├── SpacingAroundCurly.kt │ │ ├── StringTemplate.kt │ │ ├── NoBlankLineBeforeRbrace.kt │ │ ├── SpacingAroundKeyword.kt │ │ ├── SpacingAroundParens.kt │ │ ├── NoConsecutiveBlankLines.kt │ │ ├── SpacingAroundOperators.kt │ │ ├── NoLineBreakBeforeAssignment.kt │ │ └── SpacingAroundRangeOperator.kt │ └── test │ └── resources │ └── autocorrect │ ├── autocorrect-all-true.yml │ ├── autocorrect-rule-false.yml │ ├── autocorrect-ruleset-false.yml │ ├── autocorrect-toplevel-false.yml │ └── autocorrect-true-rule-active-false.yml ├── detekt-sample-extensions ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── services │ │ │ │ ├── io.gitlab.arturbosch.detekt.api.RuleSetProvider │ │ │ │ ├── io.gitlab.arturbosch.detekt.api.ConsoleReport │ │ │ │ ├── io.gitlab.arturbosch.detekt.api.OutputReport │ │ │ │ └── io.gitlab.arturbosch.detekt.api.FileProcessListener │ │ └── kotlin │ │ │ └── io │ │ │ └── gitlab │ │ │ └── arturbosch │ │ │ └── detekt │ │ │ └── sample │ │ │ └── extensions │ │ │ ├── reports │ │ │ ├── QualifiedNamesConsoleReport.kt │ │ │ ├── QualifiedNamesOutputReport.kt │ │ │ └── Reports.kt │ │ │ └── SampleProvider.kt │ └── test │ │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── sample │ │ └── extensions │ │ └── processors │ │ └── NumberOfLoopsProcessorSpec.kt └── build.gradle.kts ├── .gitattributes ├── detekt-test ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── io │ └── gitlab │ └── arturbosch │ └── detekt │ └── test │ ├── CompileExtensions.kt │ ├── RuleSetExtensions.kt │ └── Resources.kt ├── detekt-generator └── src │ ├── test │ ├── resources │ │ ├── RuleSetConfig.yml │ │ └── RuleSet.md │ └── kotlin │ │ └── io │ │ └── gitlab │ │ └── arturbosch │ │ └── detekt │ │ └── generator │ │ ├── util │ │ └── CollectorTestExtensions.kt │ │ └── printer │ │ ├── RuleSetPagePrinterSpec.kt │ │ └── ConfigPrinterSpec.kt │ └── main │ └── kotlin │ └── io │ └── gitlab │ └── arturbosch │ └── detekt │ └── generator │ ├── printer │ ├── DocumentationPrinter.kt │ └── rulesetpage │ │ └── RuleSetPage.kt │ ├── collection │ ├── exception │ │ ├── InvalidIssueDeclaration.kt │ │ ├── InvalidCodeExampleDocumentationException.kt │ │ └── InvalidDocumentationException.kt │ ├── Configuration.kt │ ├── Collector.kt │ ├── RuleCollector.kt │ └── Rule.kt │ ├── DetektProgressListener.kt │ └── out │ └── AbstractWriter.kt ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── questions.md │ ├── feature-request--not-related-to-rules-.md │ └── new-rule-or-changes-to-existing-rules.md └── PULL_REQUEST_TEMPLATE.md ├── gradle.properties ├── reports └── baseline.xml ├── settings.gradle.kts ├── commit-msg └── .travis.yml /docs/_data/glossary.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_data/terms.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_data/definitions.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /detekt-api/src/test/resources/empty.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /detekt-api/src/test/resources/oneitem.yml: -------------------------------------------------------------------------------- 1 | style: -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/empty.txt: -------------------------------------------------------------------------------- 1 | ... 2 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/configs/one.yml: -------------------------------------------------------------------------------- 1 | one: 1 -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/configs/two.yml: -------------------------------------------------------------------------------- 1 | two: 2 -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/EmptyKtFile.kt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_layouts/none.html: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | {{content}} -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/configs/three.yml: -------------------------------------------------------------------------------- 1 | three: 3 -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/configs/fail-fast-only.yml: -------------------------------------------------------------------------------- 1 | failFast: true -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/NewLineAtEndOfFile.kt: -------------------------------------------------------------------------------- 1 | class Test 2 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/invalid-smell-baseline.txt: -------------------------------------------------------------------------------- 1 | // empty on purpose 2 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | enableFeaturePreview("STABLE_PUBLISHING") 2 | -------------------------------------------------------------------------------- /docs/update.sh: -------------------------------------------------------------------------------- 1 | git add . 2 | git status 3 | git commit -m "content update" 4 | git push -------------------------------------------------------------------------------- /detekt-watcher/src/test/resources/Default.kt: -------------------------------------------------------------------------------- 1 | @Suppress("unused") 2 | private val x = 0 3 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/cases/KotlinScript.kts: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | println("Hello World") -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'github-pages', group: :jekyll_plugins 4 | -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /docs/images/company_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/images/company_logo.png -------------------------------------------------------------------------------- /docs/_includes/inline_image.html: -------------------------------------------------------------------------------- 1 | {{include.alt}} 2 | -------------------------------------------------------------------------------- /docs/css/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/css/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /docs/_tooltips/soccer.html: -------------------------------------------------------------------------------- 1 | --- 2 | doc_id: soccer 3 | product: mydoc 4 | --- 5 | 6 | {{site.data.definitions.soccer}} -------------------------------------------------------------------------------- /docs/images/company_logo_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/images/company_logo_big.png -------------------------------------------------------------------------------- /docs/images/detekt_in_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/images/detekt_in_action.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /detekt-core/src/test/resources/empty/EmptyEnum.kt: -------------------------------------------------------------------------------- 1 | package empty 2 | 3 | @Suppress("Unused") 4 | enum class EmptyEnum 5 | -------------------------------------------------------------------------------- /docs/_tooltips/football.html: -------------------------------------------------------------------------------- 1 | --- 2 | doc_id: football 3 | product: mydoc 4 | --- 5 | 6 | {{site.data.definitions.football}} -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/_includes/callout.html: -------------------------------------------------------------------------------- 1 |
{{include.content}}
2 | -------------------------------------------------------------------------------- /docs/_tooltips/baseball.html: -------------------------------------------------------------------------------- 1 | --- 2 | doc_id: baseball 3 | product: mydoc 4 | --- 5 | 6 | {{site.data.definitions.baseball}} 7 | -------------------------------------------------------------------------------- /docs/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /detekt-core/src/test/resources/empty/EmptyInterface.kt: -------------------------------------------------------------------------------- 1 | package empty 2 | 3 | @Suppress("Unused") 4 | interface EmptyInterface 5 | -------------------------------------------------------------------------------- /docs/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/_tooltips/basketball.html: -------------------------------------------------------------------------------- 1 | --- 2 | doc_id: basketball 3 | product: mydoc 4 | --- 5 | 6 | {{site.data.definitions.basketball}} 7 | -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/docs/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /detekt-api/src/test/resources/FilteredClass.kt: -------------------------------------------------------------------------------- 1 | @Suppress("unused") 2 | /** 3 | * @author Artur Bosch 4 | */ 5 | class FilteredClass { 6 | } 7 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/resources/META-INF/services/io.gitlab.arturbosch.ksh.api.Prompt: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.watcher.config.DetektPrompt 2 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.OutputReport: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.cli.out.TestOutputReport 2 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.cli.runners.TestProvider 2 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/cases/Test.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | @Suppress("Unused") 7 | class Test 8 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/sample-rule-set.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/detekt/master/detekt-core/src/test/resources/sample-rule-set.jar -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.ConsoleReport: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.cli.runners.TestConsoleReport 2 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/cases/Default.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | @Suppress("Unused") 7 | class Default 8 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/cases/Poko.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | class Poko { 4 | 5 | val name: String = "Poko" 6 | fun hello() = "Hello, $name" 7 | } 8 | -------------------------------------------------------------------------------- /docs/_data/strings.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | # placed here for translation purposes 4 | search_placeholder_text: search... 5 | search_no_results_text: No results found. 6 | -------------------------------------------------------------------------------- /docs/_includes/note.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/_includes/tip.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.formatting.FormattingProvider 2 | -------------------------------------------------------------------------------- /docs/_includes/important.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_includes/warning.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.sample.extensions.SampleProvider 2 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/fields/ClassWithFields.kt: -------------------------------------------------------------------------------- 1 | package fields 2 | 3 | @Suppress("unused") 4 | class ClassWithFields { 5 | 6 | private var x = 0 7 | val y = 0 8 | } 9 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.core.TestProvider 2 | io.gitlab.arturbosch.detekt.core.TestProvider2 -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.ConsoleReport: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.sample.extensions.reports.QualifiedNamesConsoleReport 2 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.OutputReport: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.sample.extensions.reports.QualifiedNamesOutputReport 2 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/BuildFailure.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt 2 | 3 | class BuildFailure(override val message: String?) : RuntimeException(message) 4 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/PreferToOverPairSyntaxNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "UNUSED_VARIABLE") 4 | fun preferToOverPairSyntaxNegative() { 5 | val pair = 1 to 2 6 | } 7 | -------------------------------------------------------------------------------- /docs/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Page Not Found" 3 | search: exclude 4 | --- 5 | 6 | Sorry, but the page you were trying to view does not exist. Try searching for it or looking at the URL to see if it looks correct. 7 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/AllowedExceptionNamePattern.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules 2 | 3 | internal const val ALLOWED_EXCEPTION_NAME = "^(_|(ignore|expected).*)" 4 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Notification.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | interface Notification { 7 | val message: String 8 | } 9 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/patterns/exclude-FindName.yml: -------------------------------------------------------------------------------- 1 | test-pattern: 2 | active: true 3 | patterns: 4 | - '.*/test/.*' 5 | - '.*Test.kt' 6 | exclude-rule-sets: 7 | exclude-rules: 8 | - 'FindName' 9 | -------------------------------------------------------------------------------- /detekt-formatting/src/test/resources/autocorrect/autocorrect-all-true.yml: -------------------------------------------------------------------------------- 1 | autoCorrect: true 2 | 3 | formatting: 4 | active: true 5 | autoCorrect: true 6 | ChainWrapping: 7 | active: true 8 | autoCorrect: true 9 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/TestVersion.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | const val VERSION_UNDER_TEST: String = "1.0.0.RC9.2" 7 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/runners/Executable.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.runners 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | interface Executable { 7 | fun execute() 8 | } 9 | -------------------------------------------------------------------------------- /detekt-formatting/src/test/resources/autocorrect/autocorrect-rule-false.yml: -------------------------------------------------------------------------------- 1 | autoCorrect: true 2 | 3 | formatting: 4 | active: true 5 | autoCorrect: true 6 | ChainWrapping: 7 | active: true 8 | autoCorrect: false 9 | -------------------------------------------------------------------------------- /detekt-formatting/src/test/resources/autocorrect/autocorrect-ruleset-false.yml: -------------------------------------------------------------------------------- 1 | autoCorrect: true 2 | 3 | formatting: 4 | active: true 5 | autoCorrect: false 6 | ChainWrapping: 7 | active: true 8 | autoCorrect: true 9 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/TrailingWhitespaceNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | class TrailingWhitespaceNegative { 5 | 6 | fun myFunction() { 7 | println("A message") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/findings-report.txt: -------------------------------------------------------------------------------- 1 | Ruleset: TestSmell - 10min debt 2 | TestSmell - [TestEntity] at TestFile.kt:1:1 3 | TestSmell - [TestEntity] at TestFile.kt:1:1 4 | Ruleset: EmptySmells 5 | 6 | Overall debt: 10min 7 | -------------------------------------------------------------------------------- /detekt-formatting/src/test/resources/autocorrect/autocorrect-toplevel-false.yml: -------------------------------------------------------------------------------- 1 | autoCorrect: false 2 | 3 | formatting: 4 | active: true 5 | autoCorrect: true 6 | ChainWrapping: 7 | active: true 8 | autoCorrect: true 9 | -------------------------------------------------------------------------------- /detekt-api/src/test/resources/SuppressedObject.kt: -------------------------------------------------------------------------------- 1 | @file:SuppressWarnings("Test") 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | object SuppressedObject { 7 | 8 | fun stuff() { 9 | println("FAILED TEST") 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /detekt-formatting/src/test/resources/autocorrect/autocorrect-true-rule-active-false.yml: -------------------------------------------------------------------------------- 1 | autoCorrect: true 2 | 3 | formatting: 4 | active: true 5 | autoCorrect: true 6 | ChainWrapping: 7 | active: false 8 | autoCorrect: true 9 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/EmptyDefaultConstructorPositive.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | class EmptyPrimaryConstructor constructor() 6 | 7 | class EmptyPublicPrimaryConstructor public constructor() 8 | -------------------------------------------------------------------------------- /detekt-api/src/test/resources/SuppressedByAllObject.kt: -------------------------------------------------------------------------------- 1 | @file:SuppressWarnings("ALL") 2 | 3 | /** 4 | * @author lummax 5 | */ 6 | object SuppressedByAllObject { 7 | 8 | fun stuff() { 9 | println("FAILED TEST") 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Always use crlf line endings Gradle .bat file 2 | gradlew.bat text eol=crlf 3 | 4 | # Mark Gradle wrapper as a binary 5 | gradle/wrapper/gradle-wrapper.jar binary 6 | 7 | *.md eol=lf 8 | *.html eol=lf 9 | *.yml eol=lf 10 | -------------------------------------------------------------------------------- /docs/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | server: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | image: result/latest 8 | ports: 9 | - "4000:4000" 10 | volumes: 11 | - ".:/src" -------------------------------------------------------------------------------- /docs/pages/tags/tag_news.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "News" 3 | tagName: news 4 | search: exclude 5 | permalink: tag_news.html 6 | sidebar: mydoc_sidebar 7 | folder: tags 8 | --- 9 | {% include taglogic.html %} 10 | 11 | {% include links.html %} 12 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/extensions/DetektReportType.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.extensions 2 | 3 | enum class DetektReportType(val extension: String) { 4 | 5 | XML("xml"), 6 | HTML("html") 7 | } 8 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/NoTabsNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | class NoTabsNegative { 4 | 5 | fun methodOk() { 6 | println("A message") 7 | } 8 | 9 | val str = "A \t tab " 10 | val multiStr = """A \t tab """ 11 | } 12 | -------------------------------------------------------------------------------- /detekt-cli/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.OutputReport: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.cli.out.TxtOutputReport 2 | io.gitlab.arturbosch.detekt.cli.out.XmlOutputReport 3 | io.gitlab.arturbosch.detekt.cli.out.HtmlOutputReport 4 | -------------------------------------------------------------------------------- /detekt-test/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val assertjVersion: String by project 2 | 3 | dependencies { 4 | implementation(kotlin("compiler-embeddable")) 5 | implementation(project(":detekt-core")) 6 | implementation("org.assertj:assertj-core:$assertjVersion") 7 | } 8 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/resources/META-INF/services/io.gitlab.arturbosch.ksh.api.ShellClass: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.watcher.commands.Project 2 | io.gitlab.arturbosch.detekt.watcher.commands.Watch 3 | io.gitlab.arturbosch.detekt.watcher.commands.Analyze 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /detekt-generator/src/test/resources/RuleSetConfig.yml: -------------------------------------------------------------------------------- 1 | style: 2 | active: true 3 | WildcardImport: 4 | active: true 5 | conf1: foo 6 | EqualsNull: 7 | active: false 8 | NoUnitKeyword: 9 | active: true 10 | autoCorrect: true 11 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/MultilineStringLiteralDuplication.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | // does not report because it treats the multiline string parts as one string 5 | val str = """ 6 | | 7 | | 8 | | 9 | """ 10 | -------------------------------------------------------------------------------- /docs/_data/tags.yml: -------------------------------------------------------------------------------- 1 | # Note: 2 | # If you are using the createtag script, don't leave an blank line at the end of this file. 3 | # In other words, the last line must be the last tag in the allowed-tags list. 4 | allowed-tags: 5 | - getting_started 6 | - news 7 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/patterns/test-pattern.yml: -------------------------------------------------------------------------------- 1 | test-pattern: 2 | active: true 3 | patterns: 4 | - '.*/test/.*' 5 | - '.*Test.kt' 6 | exclude-rule-sets: 7 | - 'Test' 8 | exclude-rules: 9 | - 'MagicNumber' 10 | - 'WildcardImport' 11 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/Submodule.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt 2 | 3 | data class Submodule( 4 | val name: String, 5 | val numberOfSourceFiles: Int, 6 | val detektConfig: String?, 7 | val srcDirs: List 8 | ) 9 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.FileProcessListener: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.sample.extensions.processors.QualifiedNameProcessor 2 | io.gitlab.arturbosch.detekt.sample.extensions.processors.NumberOfLoopsProcessor 3 | -------------------------------------------------------------------------------- /docs/_includes/archive.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | type: archive 4 | --- 5 | 6 |
7 |

{{ page.title }}

8 |
9 |
10 | 11 | {{ content }} 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/Default.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | import java.util.* 4 | 5 | /** 6 | * @author Artur Bosch 7 | */ 8 | @Suppress("unused") 9 | class Default { 10 | 11 | // declares unnecessary return of type "Unit" 12 | fun f(): Unit {} 13 | } 14 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/LongMethodNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | class LongMethodNegative { 6 | 7 | fun methodOk() { 8 | println() 9 | fun localMethodOk() { 10 | println() 11 | println() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/deactivated-exceptions.yml: -------------------------------------------------------------------------------- 1 | exceptions: 2 | active: true 3 | TooGenericExceptionCaught: 4 | active: true 5 | exceptionNames: 6 | - 7 | TooGenericExceptionThrown: 8 | active: true 9 | exceptionNames: 10 | - 11 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DocumentationPrinter.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.printer 2 | 3 | /** 4 | * @author Marvin Ramin 5 | */ 6 | interface DocumentationPrinter { 7 | fun print(item: T): String 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | insert_final_newline = true 6 | 7 | [*.{kt,groovy}] 8 | indent_style = tab 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.md] 15 | indent_style = space 16 | indent_size = 4 17 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/SuppressStringLiteralDuplication.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "UNUSED_PARAMETER", "UnusedEquals") 2 | 3 | @Suppress("StringLiteralDuplication") 4 | class Duplication { 5 | var s1 = "lorem" 6 | fun f(s: String = "lorem") { 7 | s1 == "lorem" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/pages/tags/tag_getting_started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting started pages" 3 | tagName: getting_started 4 | search: exclude 5 | permalink: tag_getting_started.html 6 | sidebar: mydoc_sidebar 7 | folder: tags 8 | --- 9 | {% include taglogic.html %} 10 | 11 | {% include links.html %} 12 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/NoTabsPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | class NoTabsPositive { 4 | fun methodOk() { // reports 3 5 | println("A message") 6 | 7 | } 8 | 9 | val str = "${ methodOk()}" // reports 1 10 | val multiStr = """${ methodOk()}""" // reports 1 11 | } 12 | -------------------------------------------------------------------------------- /docs/_posts/2018-02-11-website-online.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Website Online" 3 | published: true 4 | permalink: samplepost.html 5 | summary: "Documentation website launched together with RC7." 6 | tags: [news] 7 | --- 8 | As of today the website was launched! 9 | 10 | {% include links.html %} 11 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/configs/fail-fast-override.yml: -------------------------------------------------------------------------------- 1 | failFast: true 2 | 3 | build: 4 | warningThreshold: 1 5 | failThreshold: 1 6 | maxIssues: 1 7 | 8 | style: 9 | MaxLineLength: 10 | maxLineLength: 100 11 | 12 | comments: 13 | CommentOverPrivateMethod: 14 | active: false 15 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/PreferToOverPairSyntaxPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "UNUSED_VARIABLE") 4 | fun preferToOverPairSyntaxPositive() { 5 | val pair1 = Pair(1, 2) 6 | 7 | val pair2: Pair = Pair(1, 2) 8 | 9 | val pair3 = Pair(Pair(1, 2), Pair(3, 4)) 10 | } 11 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/DetektVisitor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import org.jetbrains.kotlin.psi.KtTreeVisitorVoid 4 | 5 | /** 6 | * Base visitor for detekt rules. 7 | * 8 | * @author Artur Bosch 9 | */ 10 | open class DetektVisitor : KtTreeVisitorVoid() 11 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/exception/InvalidIssueDeclaration.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection.exception 2 | 3 | class InvalidIssueDeclaration(attributeName: String) 4 | : RuntimeException("Invalid issue declaration attribute $attributeName.") 5 | -------------------------------------------------------------------------------- /docs/var/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | apt-get update && \ 3 | apt-get install -y libfontconfig zip npm git apt-transport-https ca-certificates curl openssl && \ 4 | npm i -g npm && \ 5 | npm cache clean -f && \ 6 | npm install -g n && \ 7 | n stable && \ 8 | node --version && \ 9 | npm --version && \ 10 | bundle install -------------------------------------------------------------------------------- /detekt-api/src/test/resources/composite-test.yml: -------------------------------------------------------------------------------- 1 | style: 2 | WildcardImport: 3 | active: false 4 | NoElseInWhenExpression: 5 | active: false 6 | MagicNumber: 7 | ignoreHashCodeFunction: true 8 | ignorePropertyDeclaration: true 9 | ignoreAnnotation: true 10 | ignoreNumbers: '-1,0,1,2,100,1000' 11 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Configuration.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection 2 | 3 | /** 4 | * @author Marvin Ramin 5 | */ 6 | data class Configuration( 7 | val name: String, 8 | val description: String, 9 | val defaultValue: String 10 | ) 11 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/FunctionReturningConstantNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | fun functionNotReturningConstant1() = 1 + 1 6 | 7 | fun functionNotReturningConstant2(): Int { 8 | return 1 + 1 9 | } 10 | 11 | fun functionNotReturningConstantString1(str: String) = "str: $str" 12 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/baseline/Listing.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.baseline 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | interface Listing { 7 | 8 | val timestamp: String 9 | val ids: Set 10 | 11 | fun withNewTimestamp(timestamp: String, list: T): T 12 | } 13 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/baseline/internal/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * IntendingXMLStreamWriter adapted from com.sun.xml.internal.txw2.output 3 | * to work on Java9 without extra module dependencies. 4 | * 5 | * @author Artur Bosch 6 | */ 7 | package io.gitlab.arturbosch.detekt.cli.baseline.internal; 8 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Collector.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection 2 | 3 | import org.jetbrains.kotlin.psi.KtFile 4 | 5 | /** 6 | * @author Marvin Ramin 7 | */ 8 | interface Collector { 9 | val items: List 10 | 11 | fun visit(file: KtFile) 12 | } 13 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/IdentifierName.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules 2 | 3 | import org.jetbrains.kotlin.name.SpecialNames 4 | import org.jetbrains.kotlin.psi.KtNamedDeclaration 5 | 6 | internal fun KtNamedDeclaration.identifierName() = nameIdentifier?.text ?: SpecialNames.NO_NAME_PROVIDED.asString() 7 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/Keywords.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules 2 | 3 | /** 4 | * This file contains common literals of keywords, library functions and other idioms of Kotlin language 5 | * 6 | * @author mishkun 7 | */ 8 | 9 | const val IT_LITERAL = "it" 10 | const val LET_LITERAL = "let" 11 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Extension.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | @Suppress("EmptyFunctionBlock") 7 | interface Extension { 8 | val id: String get() = javaClass.simpleName 9 | val priority: Int get() = -1 10 | 11 | fun init(config: Config) {} 12 | } 13 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/KotlinExtension.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt 2 | 3 | import io.gitlab.arturbosch.detekt.extensions.DetektExtension 4 | import org.gradle.api.Project 5 | 6 | fun Project.detekt(configure: DetektExtension.() -> Unit) = 7 | extensions.configure(DetektExtension::class.java, configure) 8 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/EditorConfigConstants.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | const val DEFAULT_INDENT = 4 7 | const val DEFAULT_CONTINUATION_INDENT = 4 8 | const val ANDROID_MAX_LINE_LENGTH = 100 9 | const val DEFAULT_IDEA_LINE_LENGTH = 120 10 | -------------------------------------------------------------------------------- /docs/tooltips.json: -------------------------------------------------------------------------------- 1 | --- 2 | layout: null 3 | search: exclude 4 | --- 5 | 6 | { 7 | "entries": 8 | [ 9 | {% for page in site.tooltips %} 10 | { 11 | "doc_id": "{{ page.doc_id }}", 12 | "body": "{{ page.content | strip_newlines | replace: '\', '\\\\' | replace: '"', '\\"' }}" 13 | } {% unless forloop.last %},{% endunless %} 14 | {% endfor %} 15 | ] 16 | } 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/questions.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Questions 3 | about: Ask questions about detekt, clarify behavior of features, anything that is unclear 4 | 5 | --- 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/exception/InvalidCodeExampleDocumentationException.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection.exception 2 | 3 | class InvalidCodeExampleDocumentationException(ruleName: String) 4 | : RuntimeException("Invalid rule documentation for noncompliant and compliant code examples in $ruleName.") 5 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/TooGenericExceptionsOptions.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | class TooGenericExceptionsOptions { 6 | 7 | fun f() { 8 | try { 9 | throw Throwable() 10 | } catch (myIgnore: MyTooGenericException) { 11 | throw Error() 12 | } 13 | } 14 | } 15 | 16 | class MyTooGenericException : RuntimeException() 17 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/complexity-report.txt: -------------------------------------------------------------------------------- 1 | Complexity Report: 2 | - 10 lines of code (loc) 3 | - 6 source lines of code (sloc) 4 | - 5 logical lines of code (lloc) 5 | - 4 comment lines of code (cloc) 6 | - 2 McCabe complexity (mcc) 7 | - 1 number of total code smells 8 | - 66 % comment source ratio 9 | - 400 mcc per 1000 lloc 10 | - 200 code smells per 1000 lloc 11 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | detektVersion=1.0.0.RC9.2 2 | usedDetektVersion=1.0.0.RC9.2 3 | ktlintVersion=0.29.0 4 | spekVersion=1.2.1 5 | junitPlatformVersion=1.3.1 6 | yamlVersion=1.23 7 | jcommanderVersion=1.74 8 | assertjVersion=3.11.1 9 | kshVersion=0.1.1 10 | reflectionsVersion=0.9.11 11 | 12 | systemProp.sonar.host.url=http://localhost:9000 13 | systemProp.detektVersion=detektVersion 14 | -------------------------------------------------------------------------------- /detekt-cli/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.ConsoleReport: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.cli.console.BuildFailureReport 2 | io.gitlab.arturbosch.detekt.cli.console.ComplexityReport 3 | io.gitlab.arturbosch.detekt.cli.console.FindingsReport 4 | io.gitlab.arturbosch.detekt.cli.console.NotificationReport 5 | io.gitlab.arturbosch.detekt.cli.console.ProjectStatisticsReport 6 | -------------------------------------------------------------------------------- /detekt-cli/src/test/resources/smell-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LongParameterList:Signature 5 | LongMethod:Signature 6 | 7 | 8 | FeatureEnvy:Signature 9 | 10 | 11 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/TooManyFunctionsTopLevel.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | fun f1() {} 6 | fun f2() {} 7 | fun f3() {} 8 | fun f4() {} 9 | fun f5() {} 10 | fun f6() {} 11 | fun f7() {} 12 | fun f8() {} 13 | fun f9() {} 14 | fun f10() {} 15 | fun f11() {} 16 | fun f12() {} 17 | fun f13() {} 18 | fun f14() {} 19 | fun f15() {} 20 | fun f16() {} 21 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/config/ConfigProperties.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.config 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | const val DETEKT_YAML_CONFIG_PATHS = "detekt.watcher.config.paths" 7 | const val WATCHER_CHANGE_NOTIFICATION = "detekt.watcher.change.notification" 8 | const val WATCHER_CHANGE_TIMEOUT = "detekt.watcher.change.timeout" 9 | -------------------------------------------------------------------------------- /docs/_includes/image.html: -------------------------------------------------------------------------------- 1 |
{% if {{include.url}} %}{% endif %}{{include.alt}}{% if {{include.url}} %}{% endif %}{% if {{include.caption}} %}
{{include.caption}}
{% endif %}
2 | -------------------------------------------------------------------------------- /docs/_layouts/page_print.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default_print 3 | comments: true 4 | --- 5 |
6 |

{{ page.title }}

7 |
8 | 9 |
10 | 11 | {% if page.summary %} 12 |
{{page.summary}}
13 | {% endif %} 14 | {{ content }} 15 |
16 | -------------------------------------------------------------------------------- /detekt-core/src/test/resources/comments/CommentsClass.kt: -------------------------------------------------------------------------------- 1 | package comments 2 | 3 | @Suppress("Unused") 4 | class CommentsClass { 5 | 6 | /** 7 | * Doc comment 8 | * 9 | * @param args 10 | */ 11 | fun x(args: String) { // comment total: 10 12 | /* 13 | comment 14 | */ 15 | //Comment 16 | 17 | println(args) 18 | 19 | println("/* no comment */") 20 | println("// no comment //") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/exception/InvalidDocumentationException.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection.exception 2 | 3 | /** 4 | * Thrown to indicate that rule documentation in KDoc is missing or invalid. 5 | * 6 | * @author Marvin Ramin 7 | */ 8 | class InvalidDocumentationException(message: String) 9 | : RuntimeException(message) 10 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/UnconditionalJumpStatementInLoopNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | fun jumpStatementNestedOk() { 6 | for (i in 1..2) { 7 | try { 8 | break 9 | } finally { 10 | } 11 | } 12 | } 13 | 14 | fun jumpStatementInIf() { 15 | for (i in 1..2) { 16 | if (i > 1) { 17 | break 18 | } 19 | if (i > 1) println() else break 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/rulesetpage/RuleSetPage.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.printer.rulesetpage 2 | 3 | import io.gitlab.arturbosch.detekt.generator.collection.Rule 4 | import io.gitlab.arturbosch.detekt.generator.collection.RuleSetProvider 5 | 6 | data class RuleSetPage( 7 | val ruleSet: RuleSetProvider, 8 | val rules: List 9 | ) 10 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/ConstInObjects.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | object Root { 5 | 6 | const val ROOT_CONST = 1 7 | 8 | object A1 { 9 | val ACONST = ROOT_CONST + 1 // reports 1 10 | const val ACONST_1 = 1 11 | 12 | object B1 { 13 | val BCONST = ACONST_1 + 1 // reports 1 14 | } 15 | } 16 | 17 | object A2 { 18 | val ACONST = ROOT_CONST + 1 // reports 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/SwallowedExceptionPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | import java.io.IOException 4 | 5 | fun swallowedExceptions() { 6 | try { 7 | } catch(e: Exception) { 8 | throw IOException(e.message) // violation 9 | } catch(e: Exception) { 10 | throw Exception(IOException(e.toString())) // violation 11 | } catch(e: Exception) { 12 | throw IOException(e.message) // violation 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /detekt-cli/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/console/ResourceReader.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.console 2 | 3 | import io.gitlab.arturbosch.detekt.test.resource 4 | import java.nio.file.Files 5 | import java.nio.file.Paths 6 | 7 | internal fun readResource(filename: String): String { 8 | val path = Paths.get(resource(filename)) 9 | return Files.readAllLines(path).joinToString("\n").trimEnd() 10 | } 11 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/LabeledExpressionNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "UNUSED_VARIABLE") 4 | class LabeledOuterNegative { 5 | 6 | inner class Inner1 { 7 | 8 | fun foo() { 9 | val foo = this@LabeledOuterNegative 10 | } 11 | 12 | inner class Inner2 { 13 | fun foo() { 14 | val foo = this@LabeledOuterNegative 15 | val foo2 = this@Inner1 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/EmptyDefaultConstructorNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "UNUSED_PARAMETER") 2 | 3 | package cases 4 | 5 | class PrimaryConstructorWithParameter constructor(x: Int) 6 | 7 | class PrimaryConstructorWithAnnotation @SafeVarargs constructor() 8 | 9 | class PrivatePrimaryConstructor private constructor() 10 | 11 | class EmptyConstructorIsCalled() { 12 | 13 | constructor(i: Int) : this() 14 | } 15 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/service/Models.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.service 2 | 3 | import java.nio.file.Path 4 | import java.nio.file.WatchEvent 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | data class WatchedDir(val valid: Boolean, 10 | val dir: Path, 11 | val events: List) 12 | 13 | data class PathEvent(val path: Path, val kind: WatchEvent.Kind<*>) 14 | -------------------------------------------------------------------------------- /docs/_includes/footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 |
9 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/ModificationNotification.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core 2 | 3 | import io.gitlab.arturbosch.detekt.api.Notification 4 | import java.nio.file.Path 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | class ModificationNotification(path: Path) : Notification { 10 | 11 | override val message: String = "File $path was modified." 12 | override fun toString(): String = message 13 | } 14 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/LongMethodPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | @Suppress("unused") 7 | class LongMethodPositive { 8 | 9 | // reports 1 - too many statements 10 | fun longMethod() { 11 | println() 12 | println() 13 | println() 14 | 15 | // reports 1 - too many statements 16 | fun nestedLongMethod() { 17 | println() 18 | println() 19 | println() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/LoopWithTooManyJumpStatementsNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | fun onlyOneJump() { 6 | for (i in 1..2) { 7 | if (i > 1) break 8 | } 9 | } 10 | 11 | fun jumpsInNestedLoops() { 12 | for (i in 1..2) { 13 | if (i > 1) break 14 | // jump statements of the inner loop must not be counted in the outer loop 15 | while (i > 1) { 16 | if (i > 1) continue 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | A similar PR may already be submitted! 2 | Please search among the [Pull requests](https://github.com/arturbosch/detekt/pulls) before creating one. 3 | 4 | Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. Link to relevant issues if possible. 5 | 6 | For more information, see the [CONTRIBUTING guide](https://github.com/arturbosch/detekt/blob/master/CONTRIBUTING.md). 7 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/ConsoleReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import java.io.PrintStream 4 | 5 | /** 6 | * @author Artur Bosch 7 | */ 8 | abstract class ConsoleReport : Extension { 9 | 10 | fun print(printer: PrintStream, detektion: Detektion) { 11 | render(detektion)?.let { 12 | printer.println(it) 13 | } 14 | } 15 | 16 | abstract fun render(detektion: Detektion): String? 17 | } 18 | -------------------------------------------------------------------------------- /detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/util/CollectorTestExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.util 2 | 3 | import io.gitlab.arturbosch.detekt.generator.collection.Collector 4 | import io.gitlab.arturbosch.detekt.test.KtTestCompiler 5 | 6 | fun Collector.run(code: String): List { 7 | val ktFile = KtTestCompiler.compileFromContent(code.trimIndent()) 8 | visit(ktFile) 9 | return items 10 | } 11 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/CollapsibleIfsPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "ConstantConditionIf", "SimplifyBooleanWithConstants") 4 | fun collapsibleIfsPositive() { 5 | 6 | if (true) { // reports 1 - if statements could be merged 7 | if (1 == 1) {} 8 | // a comment 9 | } 10 | 11 | if (true) { 12 | if (1 == 1) { // reports 1 - if statements could be merged 13 | if (2 == 2) {} 14 | } 15 | println() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/SwallowedExceptionNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | import java.io.IOException 4 | 5 | fun noSwallowedException() { 6 | try { 7 | } catch (e: Exception) { 8 | println() 9 | } catch (e: Exception) { 10 | throw IOException() 11 | } catch(e: Exception) { 12 | throw IOException(e.message, e) 13 | } catch(e: Exception) { 14 | throw IOException(e) 15 | } catch (e: Exception) { 16 | throw Exception(e) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/_includes/custom/getting_started_series_next.html: -------------------------------------------------------------------------------- 1 |

{% assign series_pages = site.tags.series_acme %} 2 | {% for p in pages %} 3 | {% if p.series == "Getting Started" %} 4 | {% assign nextTopic = page.weight | plus: "1" %} 5 | {% if p.weight == nextTopic %} 6 | 7 | {% endif %} 8 | {% endif %} 9 | {% endfor %} 10 |

-------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/util/ExcludeClass.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.naming.util 2 | 3 | import io.gitlab.arturbosch.detekt.rules.identifierName 4 | import org.jetbrains.kotlin.psi.KtDeclaration 5 | import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject 6 | 7 | internal fun KtDeclaration.isContainingExcludedClass(pattern: Regex) = 8 | containingClassOrObject?.identifierName()?.matches(pattern) == true 9 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/TrailingWhitespacePositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | // reports 1 - line with just one space 4 | 5 | // reports 1 - a comment with trailing space 6 | // A comment 7 | // reports 1 8 | class TrailingWhitespacePositive { 9 | // reports 1 - line with just one tab 10 | 11 | // reports 1 12 | fun myFunction() { 13 | // reports 1 - line with 1 trailing tab 14 | println("A message") 15 | // reports 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/PrivateElementUtil.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.documentation 2 | 3 | import org.jetbrains.kotlin.lexer.KtTokens 4 | import org.jetbrains.kotlin.psi.KtDeclaration 5 | 6 | internal fun KtDeclaration.hasCommentInPrivateMember(): Boolean { 7 | val modifiers = this.modifierList 8 | return modifiers != null && docComment != null && modifiers.hasModifier(KtTokens.PRIVATE_KEYWORD) 9 | } 10 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/MandatoryBracesIfStatementsNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "ConstantConditionIf") 4 | fun mandatoryBracesIfStatementNegative() { 5 | if (true) { 6 | println() 7 | } 8 | 9 | if (true) 10 | { 11 | println() 12 | } 13 | 14 | if (true) println() 15 | 16 | if (true) { println() } 17 | 18 | if (true) println() else println() 19 | 20 | if (true) println() else if (false) println() else println() 21 | } 22 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/MandatoryBracesIfStatementsPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "ConstantConditionIf", "CascadeIf") 4 | fun mandatoryBracesIfStatementPositive() { 5 | if (true) 6 | println() 7 | 8 | if (true) 9 | println() 10 | else 11 | println() 12 | 13 | if (true) 14 | println() 15 | else if (false) 16 | println() 17 | else 18 | println() 19 | 20 | if (true) { 21 | println() 22 | } else 23 | println() 24 | } 25 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/ComplexInterfaceNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "UNUSED_VARIABLE") 2 | 3 | package cases 4 | 5 | interface InterfaceOk1 { 6 | fun f1() 7 | fun fImpl() { 8 | val x = 0 // should not report 9 | } 10 | val i1: Int 11 | // a comment shouldn't be detected 12 | } 13 | 14 | interface InterfaceOk2 { 15 | fun f1() 16 | 17 | companion object { 18 | fun sf() = 0 19 | const val c = 0 20 | } 21 | } 22 | 23 | interface EmptyInterface 24 | -------------------------------------------------------------------------------- /detekt-test/src/main/kotlin/io/gitlab/arturbosch/detekt/test/CompileExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.test 2 | 3 | import java.nio.file.Path 4 | 5 | /** 6 | * Use this method if you define a kt file/class as a plain string in your test. 7 | */ 8 | fun compileContentForTest(content: String) = KtTestCompiler.compileFromContent(content) 9 | 10 | /** 11 | * Use this method if you test a kt file/class in the test resources. 12 | */ 13 | fun compileForTest(path: Path) = KtTestCompiler.compile(path) 14 | -------------------------------------------------------------------------------- /reports/baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LargeClass:MagicNumberSpec.kt$MagicNumberSpec : Spek 6 | LargeClass:UnusedPrivateMemberSpec.kt$UnusedPrivateMemberSpec : SubjectSpek 7 | TooManyFunctions:LargeClass.kt$LargeClass : ThresholdRule 8 | TooManyFunctions:UnusedPrivateMember.kt$UnusedPrivateMember : Rule 9 | 10 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/DataClassContainsFunctionsPositive.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | // reports 2 - for each defined function in the data class 6 | data class DataClassWithFunctions(val i: Int) { 7 | 8 | fun f1() {} 9 | fun f2() {} 10 | 11 | // reports 1 - for each defined conversion function in the data class 12 | data class NestedDataClassWithConversionFunction(val i : Int) { 13 | fun toDataClassWithOverriddenMethods() = DataClassWithOverriddenMethods(i) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/NestedClassVisibilityNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | internal class NestedClassVisibilityNegative { 6 | 7 | // enums with public visibility are excluded 8 | enum class NestedEnum { One, Two } 9 | 10 | private interface PrivateTest 11 | internal interface InternalTest 12 | 13 | // should not detect companion object 14 | companion object C 15 | } 16 | 17 | private class PrivateClassWithNestedElements { 18 | 19 | class Inner 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/kotlin/io/gitlab/arturbosch/detekt/sample/extensions/reports/QualifiedNamesConsoleReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.sample.extensions.reports 2 | 3 | import io.gitlab.arturbosch.detekt.api.ConsoleReport 4 | import io.gitlab.arturbosch.detekt.api.Detektion 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | class QualifiedNamesConsoleReport : ConsoleReport() { 10 | 11 | override fun render(detektion: Detektion): String? { 12 | return qualifiedNamesReport(detektion) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/LOG.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli 2 | 3 | import java.io.PrintStream 4 | 5 | /** 6 | * @author Artur Bosch 7 | */ 8 | object LOG { 9 | 10 | var printer: PrintStream = System.out 11 | var active: Boolean = false 12 | 13 | fun debug(message: String) { 14 | if (active) { 15 | printer.println(message) 16 | } 17 | } 18 | 19 | fun debug(message: () -> String) { 20 | if (active) { 21 | printer.println(message.invoke()) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/baseline/Blacklist.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.baseline 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | data class Blacklist(override val ids: Set, 7 | override val timestamp: String) : Listing { 8 | 9 | override fun withNewTimestamp(timestamp: String, 10 | list: Blacklist) = Blacklist(list.ids, timestamp) 11 | 12 | override fun toString(): String { 13 | return "Blacklist(ids=$ids, timestamp='$timestamp')" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/baseline/Whitelist.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.baseline 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | data class Whitelist(override val ids: Set, 7 | override val timestamp: String) : Listing { 8 | 9 | override fun withNewTimestamp(timestamp: String, 10 | list: Whitelist) = Whitelist(list.ids, timestamp) 11 | 12 | override fun toString(): String { 13 | return "Blacklist(ids=$ids, timestamp='$timestamp')" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/StringExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules 2 | 3 | import java.net.MalformedURLException 4 | import java.net.URISyntaxException 5 | import java.net.URL 6 | 7 | internal fun String.lastArgumentMatchesUrl(): Boolean { 8 | val lastArgument = trimEnd().split(Regex("\\s+")).last() 9 | return try { 10 | URL(lastArgument).toURI() 11 | true 12 | } catch (e: MalformedURLException) { 13 | false 14 | } catch (e: URISyntaxException) { 15 | false 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/config/DetektPrompt.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.config 2 | 3 | import io.gitlab.arturbosch.ksh.api.Prompt 4 | import io.gitlab.arturbosch.kutils.get 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | class DetektPrompt( 10 | config: DetektHome = Injekt.get() 11 | ) : Prompt { 12 | 13 | override val applicationName: String = APP_NAME 14 | override val historyFile: String = config.historyFile 15 | override fun message(): String = "$APP_NAME> " 16 | } 17 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/MayBeConstNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | 4 | /** 5 | * @author Artur Bosch 6 | */ 7 | class MyClass { 8 | companion object { 9 | val const = "${MyClass::class.java.name}.EXTRA_DETAILS" 10 | private val A = "asdf=${AnotherClass.staticVariable}" 11 | } 12 | } 13 | 14 | class AnotherClass { 15 | companion object { 16 | const val staticVariable = "" 17 | } 18 | } 19 | 20 | var test_var = "test" 21 | val code = """ 22 | object Test { 23 | val TEST = "Test $test_var" 24 | } 25 | """ 26 | 27 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/RethrowCaughtExceptionNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | fun rethrowCaughtExceptionNegative() { 5 | try { 6 | } catch (e: IllegalStateException) { 7 | throw IllegalArgumentException(e) // e encapsulated in a new exception is allowed 8 | } 9 | try { 10 | } catch (e: IllegalStateException) { 11 | print(e) // logging an exception is allowed 12 | } 13 | try { 14 | } catch (e: IllegalStateException) { 15 | print(e) // logging an exception is allowed 16 | throw e 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/RuleCollector.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection 2 | 3 | import org.jetbrains.kotlin.psi.KtFile 4 | 5 | /** 6 | * @author Marvin Ramin 7 | */ 8 | class RuleCollector : Collector { 9 | override val items = mutableListOf() 10 | 11 | override fun visit(file: KtFile) { 12 | val visitor = RuleVisitor() 13 | file.accept(visitor) 14 | 15 | if (visitor.containsRule) { 16 | items.add(visitor.getRule()) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/EmptyIfPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | class EmptyIfPositive { 5 | 6 | private var i = 0 7 | 8 | // reports 1 9 | fun trailingSemicolon1() { 10 | if (i == 0) ; 11 | i++ 12 | } 13 | 14 | // reports 1 15 | fun trailingSemicolon2() { 16 | if (i == 0); 17 | i++ 18 | } 19 | 20 | // reports 1 21 | fun semicolonOnNewLine() { 22 | if (i == 0) 23 | ; 24 | i++ 25 | } 26 | 27 | // reports 1 28 | fun semicolonAndBraces() { 29 | if (i == 0) ; { 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/Detektion.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 4 | 5 | /** 6 | * @author Artur Bosch 7 | */ 8 | interface Detektion { 9 | val findings: Map> 10 | val notifications: Collection 11 | val metrics: Collection 12 | 13 | fun getData(key: Key): V? 14 | fun addData(key: Key, value: V) 15 | fun add(notification: Notification) 16 | fun add(projectMetric: ProjectMetric) 17 | } 18 | -------------------------------------------------------------------------------- /detekt-api/src/test/resources/detekt.yml: -------------------------------------------------------------------------------- 1 | code-smell: 2 | LongMethod: 3 | active: true 4 | threshold: 20 5 | LongParameterList: 6 | active: false 7 | threshold: 5 8 | LargeClass: 9 | active: false 10 | threshold: 70 11 | InnerMap: 12 | Inner1: 13 | active: true 14 | Inner2: 15 | active: true 16 | 17 | style: 18 | WildcardImport: 19 | active: true 20 | NoElseInWhenExpression: 21 | active: true 22 | MagicNumber: 23 | active: true 24 | ignoreNumbers: '-1,0,1,2' 25 | 26 | comments: 27 | active: false 28 | -------------------------------------------------------------------------------- /detekt-test/src/main/kotlin/io/gitlab/arturbosch/detekt/test/RuleSetExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.test 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import io.gitlab.arturbosch.detekt.api.RuleSetProvider 5 | 6 | /** 7 | * Creates a RuleSet instance of given RuleSetProvider. 8 | */ 9 | inline fun loadRuleSet(config: Config = Config.empty) = 10 | (T::class.java.constructors[0].newInstance() as? T)?.buildRuleset(config) 11 | ?: throw IllegalStateException("Could not load RuleSet for '${T::class.java}'") 12 | -------------------------------------------------------------------------------- /docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.1 2 | MAINTAINER mrafayaleem@gmail.com 3 | 4 | RUN apt-get clean \ 5 | && mv /var/lib/apt/lists /var/lib/apt/lists.broke \ 6 | && mkdir -p /var/lib/apt/lists/partial 7 | 8 | RUN apt-get update 9 | 10 | RUN apt-get install -y \ 11 | node \ 12 | python-pygments \ 13 | && apt-get clean \ 14 | && rm -rf /var/lib/apt/lists/ 15 | 16 | WORKDIR /tmp 17 | ADD Gemfile /tmp/ 18 | ADD Gemfile.lock /tmp/ 19 | RUN bundle install 20 | 21 | VOLUME /src 22 | EXPOSE 4000 23 | 24 | WORKDIR /src 25 | ENTRYPOINT ["jekyll", "serve", "-H", "0.0.0.0"] -------------------------------------------------------------------------------- /docs/_layouts/default_print.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% include head_print.html %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | {{content}} 18 |
19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/console/NotificationReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.console 2 | 3 | import io.gitlab.arturbosch.detekt.api.ConsoleReport 4 | import io.gitlab.arturbosch.detekt.api.Detektion 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | class NotificationReport : ConsoleReport() { 10 | 11 | override val priority: Int = 50 12 | 13 | override fun render(detektion: Detektion): String? { 14 | val notifications = detektion.notifications 15 | return notifications.joinToString("\n") { it.message } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/_includes/google_analytics.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% if site.google_analytics %} 4 | 5 | 6 | {% endif %} -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | search: exclude 4 | --- 5 | 6 | 7 | 8 | {% for post in site.posts %} 9 | {% unless post.search == "exclude" %} 10 | 11 | {{site.url}}{{post.url}} 12 | 13 | {% endunless %} 14 | {% endfor %} 15 | 16 | 17 | {% for page in site.pages %} 18 | {% unless page.search == "exclude" %} 19 | 20 | {{site.url}}{{ page.url}} 21 | 22 | {% endunless %} 23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Rule.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.collection 2 | 3 | /** 4 | * @author Marvin Ramin 5 | */ 6 | data class Rule( 7 | val name: String, 8 | val description: String, 9 | val nonCompliantCodeExample: String, 10 | val compliantCodeExample: String, 11 | val active: Boolean, 12 | var severity: String, 13 | var debt: String, 14 | var aliases: String?, 15 | val parent: String, 16 | val configuration: List = listOf(), 17 | val autoCorrect: Boolean = false 18 | ) 19 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/LoopWithTooManyJumpStatementsPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "ConstantConditionIf") 4 | fun tooManyJumpStatements() { 5 | val i = 0 6 | 7 | // reports 1 - too many jump statements 8 | for (j in 1..2) { 9 | if (i > 1) { 10 | break 11 | } else { 12 | continue 13 | } 14 | } 15 | 16 | // reports 1 - too many jump statements 17 | while (i < 2) { 18 | if (i > 1) break else continue 19 | } 20 | 21 | // reports 1 - too many jump statements 22 | do { 23 | if (i > 1) break else continue 24 | } while (i < 2) 25 | } 26 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/config/DetektHome.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.config 2 | 3 | import io.gitlab.arturbosch.kutils.ApplicationHomeFolder 4 | import java.nio.file.Path 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | class DetektHome(home: Path) : ApplicationHomeFolder(home) { 10 | 11 | internal val configFile: Path = resolveFile(CONFIG_FILE, shouldCreate = true) 12 | internal val historyFile: String = System.getProperty(USER_HOME) + HISTORY_FILE 13 | 14 | init { 15 | addPropertiesFromFile(configFile) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /detekt-api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | configurations.testImplementation.extendsFrom(configurations.kotlinTest) 2 | 3 | val yamlVersion: String by project 4 | val junitPlatformVersion: String by project 5 | val spekVersion: String by project 6 | 7 | dependencies { 8 | implementation("org.yaml:snakeyaml:$yamlVersion") 9 | implementation(kotlin("compiler-embeddable")) 10 | 11 | testImplementation(project(":detekt-test")) 12 | 13 | testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junitPlatformVersion") 14 | testRuntimeOnly("org.jetbrains.spek:spek-junit-platform-engine:$spekVersion") 15 | } 16 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/console/ComplexityReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.console 2 | 3 | import io.gitlab.arturbosch.detekt.api.ConsoleReport 4 | import io.gitlab.arturbosch.detekt.api.Detektion 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | class ComplexityReport : ConsoleReport() { 10 | 11 | override val priority: Int = 20 12 | 13 | override fun render(detektion: Detektion): String? { 14 | val complexityReportGenerator = ComplexityReportGenerator.create(detektion) 15 | return complexityReportGenerator.generate() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/css/boxshadowproperties.css: -------------------------------------------------------------------------------- 1 | /* box-shadow fonts return errors with prince, so extracting here to put in web output only */ 2 | 3 | #search-demo-container ul#results-container { 4 | box-shadow: 2px 3px 2px #dedede; 5 | } 6 | 7 | 8 | hr.shaded { 9 | box-shadow: inset 0 6px 6px -6px rgba(0,0,0,0.5); 10 | } 11 | 12 | .videoThumbs img { 13 | box-shadow: 2px 2px 1px #f0f0f0; 14 | } 15 | 16 | .box { 17 | box-shadow: 2px 2px 4px #dedede; 18 | } 19 | 20 | @media (max-width: 1200px) { 21 | .navbar-collapse { 22 | box-shadow: inset 0 1px 0 rgba(255,255,255,0.1); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /detekt-rules/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.rules.providers.ComplexityProvider 2 | io.gitlab.arturbosch.detekt.rules.providers.StyleGuideProvider 3 | io.gitlab.arturbosch.detekt.rules.providers.CommentSmellProvider 4 | io.gitlab.arturbosch.detekt.rules.providers.EmptyCodeProvider 5 | io.gitlab.arturbosch.detekt.rules.providers.PerformanceProvider 6 | io.gitlab.arturbosch.detekt.rules.providers.PotentialBugProvider 7 | io.gitlab.arturbosch.detekt.rules.providers.ExceptionsProvider 8 | io.gitlab.arturbosch.detekt.rules.providers.NamingProvider 9 | -------------------------------------------------------------------------------- /detekt-test/src/main/kotlin/io/gitlab/arturbosch/detekt/test/Resources.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.test 2 | 3 | import io.gitlab.arturbosch.detekt.api.YamlConfig 4 | import java.net.URI 5 | 6 | internal object Resources 7 | 8 | fun resource(name: String): URI { 9 | val explicitName = if (name.startsWith("/")) name else "/$name" 10 | val resource = Resources::class.java.getResource(explicitName) 11 | requireNotNull(resource) { "Make sure the resource '$name' exists!" } 12 | return resource.toURI() 13 | } 14 | 15 | fun yamlConfig(name: String) = YamlConfig.loadResource(resource(name).toURL()) 16 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/DetektProgressListener.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator 2 | 3 | import io.gitlab.arturbosch.detekt.api.FileProcessListener 4 | import org.jetbrains.kotlin.psi.KtFile 5 | 6 | /** 7 | * @author Marvin Ramin 8 | */ 9 | class DetektProgressListener : FileProcessListener { 10 | 11 | override fun onStart(files: List) { 12 | val name = if (files.size == 1) "file" else "files" 13 | print("Analyzing ${files.size} kotlin $name: ") 14 | } 15 | 16 | override fun onProcess(file: KtFile) { 17 | print(".") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/DataClassContainsFunctionsNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "RedundantOverride") 2 | 3 | package cases 4 | 5 | data class ValidDataClass(val i: Int) 6 | 7 | data class DataClassWithOverriddenMethods(val i: Int) { 8 | 9 | override fun hashCode(): Int { 10 | return super.hashCode() 11 | } 12 | 13 | override fun equals(other: Any?): Boolean { 14 | return super.equals(other) 15 | } 16 | 17 | override fun toString(): String { 18 | return super.toString() 19 | } 20 | } 21 | 22 | class ClassWithRegularFunctions { 23 | 24 | fun f1() {} 25 | fun f2() {} 26 | } 27 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/ProjectMetric.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | /** 4 | * Anything that can be expressed as a number value for projects. 5 | * 6 | * @author Artur Bosch 7 | */ 8 | open class ProjectMetric(val type: String, 9 | val value: Int, 10 | val priority: Int = -1, 11 | val isDouble: Boolean = false, 12 | val conversionFactor: Int = DEFAULT_FLOAT_CONVERSION_FACTOR) { 13 | 14 | override fun toString(): String = "$type: ${if (isDouble) 15 | (value.toDouble() / conversionFactor).toString() else value.toString()}" 16 | } 17 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/ThresholdRule.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | /** 4 | * Provides a threshold attribute for this rule, which is specified manually for default values 5 | * but can be also obtained from within a configuration object. 6 | */ 7 | abstract class ThresholdRule(config: Config, private val defaultThreshold: Int) : Rule(config) { 8 | /** 9 | * The used threshold for this rule is loaded from the configuration or used from the constructor value. 10 | */ 11 | protected val threshold get() = valueOrDefault("threshold", defaultThreshold) 12 | } 13 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/IteratorImplNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "UNUSED_PARAMETER") 2 | 3 | package cases 4 | 5 | import java.util.NoSuchElementException 6 | 7 | class IteratorImplOk : Iterator { 8 | 9 | override fun hasNext(): Boolean { 10 | return true 11 | } 12 | 13 | override fun next(): String { 14 | if (!hasNext()) throw NoSuchElementException() 15 | return "" 16 | } 17 | 18 | // next method overload should not be reported 19 | private fun next(i: Int) { 20 | } 21 | } 22 | 23 | class NoIteratorImpl 24 | 25 | abstract class AbstractIteratorNotOverridden : Iterator 26 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/config/DependencyInjection.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.config 2 | 3 | import io.gitlab.arturbosch.kutils.DefaultInjektor 4 | import io.gitlab.arturbosch.kutils.Injektor 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | internal class DependencyInjection : DefaultInjektor() 10 | 11 | val Injekt: Injektor = DependencyInjection() 12 | 13 | const val USER_HOME = "user.home" 14 | const val APP_NAME = "detekt" 15 | const val HOME_DIR = ".$APP_NAME" 16 | const val CONFIG_FILE = "config.properties" 17 | const val HISTORY_FILE = "/$HOME_DIR/history" 18 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/out/TxtOutputReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.out 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import io.gitlab.arturbosch.detekt.api.OutputReport 5 | 6 | /** 7 | * @author Marvin Ramin 8 | */ 9 | class TxtOutputReport : OutputReport() { 10 | 11 | override val ending: String = "txt" 12 | 13 | override val name = "plain text report" 14 | 15 | override fun render(detektion: Detektion): String { 16 | val smells = detektion.findings.flatMap { it.value } 17 | return smells.joinToString("\n") { it.compactWithSignature() } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/SerializableNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | import java.io.Serializable 6 | 7 | class CorrectSerializable1 : Serializable { 8 | companion object { 9 | const val serialVersionUID = 1L 10 | } 11 | } 12 | 13 | class CorrectSerializable2 : Serializable { 14 | companion object { 15 | const val serialVersionUID: Long = 1 16 | } 17 | } 18 | 19 | class CorrectSerializable3 : Serializable { 20 | companion object { 21 | const val serialVersionUID = -1L 22 | } 23 | } 24 | 25 | class NoSerializableClass 26 | 27 | interface SerializableInterface : Serializable 28 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/kotlin/io/gitlab/arturbosch/detekt/sample/extensions/reports/QualifiedNamesOutputReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.sample.extensions.reports 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import io.gitlab.arturbosch.detekt.api.OutputReport 5 | 6 | /** 7 | * @author Artur Bosch 8 | * @author Marvin Ramin 9 | */ 10 | class QualifiedNamesOutputReport : OutputReport() { 11 | 12 | var fileName: String = "fqNames" 13 | override val ending: String = "txt" 14 | 15 | override fun render(detektion: Detektion): String? { 16 | return qualifiedNamesReport(detektion) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/test/kotlin/io/gitlab/arturbosch/detekt/ProjectLayout.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt 2 | 3 | data class ProjectLayout( 4 | val numberOfSourceFilesInRootPerSourceDir: Int, 5 | val submodules: List = emptyList(), 6 | val srcDirs: List = listOf("src/main/java") 7 | ) { 8 | 9 | fun withSubmodule(name: String, 10 | numberOfSourceFilesInRootPerSourceDir: Int, 11 | detektConfig: String? = null, 12 | srcDirs: List = this.srcDirs 13 | ) = copy(submodules = (submodules + listOf(Submodule(name, numberOfSourceFilesInRootPerSourceDir, detektConfig, srcDirs)))) 14 | } 15 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "detekt" 2 | include("detekt-api", 3 | "detekt-core", 4 | "detekt-rules", 5 | "detekt-cli", 6 | "detekt-test", 7 | "detekt-sample-extensions", 8 | "detekt-generator", 9 | "detekt-watcher", 10 | "detekt-formatting") 11 | 12 | includeBuild("detekt-gradle-plugin") 13 | 14 | pluginManagement { 15 | resolutionStrategy { 16 | eachPlugin { 17 | if (requested.id.id == "io.gitlab.arturbosch.detekt") { 18 | useModule("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1") // version ignored for composite build 19 | } 20 | } 21 | } 22 | } 23 | 24 | enableFeaturePreview("STABLE_PUBLISHING") 25 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Junk.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli 2 | 3 | import io.gitlab.arturbosch.detekt.api.Finding 4 | import java.util.HashMap 5 | 6 | val Finding.baselineId: String 7 | get() = this.id + ":" + this.signature 8 | 9 | const val SEPARATOR_COMMA = "," 10 | const val SEPARATOR_SEMICOLON = ";" 11 | 12 | inline fun Collection.toHashMap( 13 | keyFunction: (T) -> K, 14 | valueFunction: (T) -> V 15 | ): HashMap { 16 | val result = HashMap() 17 | for (element in this) { 18 | result[keyFunction(element)] = valueFunction(element) 19 | } 20 | return result 21 | } 22 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/runners/ConfigExporter.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.runners 2 | 3 | import io.gitlab.arturbosch.detekt.cli.ClasspathResourceConverter 4 | import io.gitlab.arturbosch.detekt.cli.DEFAULT_CONFIG 5 | import java.io.File 6 | 7 | /** 8 | * @author lummax 9 | */ 10 | class ConfigExporter : Executable { 11 | 12 | override fun execute() { 13 | val defaultConfig = ClasspathResourceConverter().convert(DEFAULT_CONFIG).openStream() 14 | defaultConfig.copyTo(File(DEFAULT_CONFIG).outputStream()) 15 | println("\nSuccessfully copied $DEFAULT_CONFIG to project location.") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/EmptyIfNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | class EmptyIfNegative { 5 | 6 | private var i = 0 7 | 8 | // normal if with braces 9 | fun negative1() { 10 | if (i == 0) { 11 | i++ 12 | } 13 | } 14 | 15 | // normal if without braces 16 | fun negative2() { 17 | if (i == 0) i++ 18 | } 19 | 20 | // if then with semicolon but nonempty else body 21 | fun negative3() { 22 | if (i == 0) ; 23 | else i++ 24 | } 25 | 26 | // multiple if thens with semicolon but nonempty else body 27 | fun negative4() { 28 | if (i == 0) ; 29 | else if (i == 1) ; 30 | else i++ 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/util/Junk.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors.util 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import org.jetbrains.kotlin.psi.KtElement 5 | 6 | /** 7 | * @author Artur Bosch 8 | */ 9 | inline fun KtElement.collectByType(): List { 10 | val list = mutableListOf() 11 | this.accept(object : DetektVisitor() { 12 | override fun visitKtElement(element: KtElement) { 13 | if (element is T) { 14 | list.add(element) 15 | } 16 | element.children.forEach { it.accept(this) } 17 | } 18 | }) 19 | return list 20 | } 21 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/processors/LOCVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.core.path 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions 6 | import org.jetbrains.spek.api.Spek 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | class LOCVisitorTest : Spek({ 10 | 11 | it("defaultClass") { 12 | val file = compileForTest(path.resolve("Default.kt")) 13 | val loc = with(file) { 14 | accept(LOCVisitor()) 15 | getUserData(linesKey) 16 | } 17 | Assertions.assertThat(loc).isEqualTo(8) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyInitBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtClassInitializer 5 | 6 | /** 7 | * Reports empty `init` expressions. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author schalkms 11 | * @author Marvin Ramin 12 | */ 13 | class EmptyInitBlock(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitClassInitializer(initializer: KtClassInitializer) { 16 | initializer.body?.addFindingIfBlockExprIsEmpty() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/CollapsibleIfsNegative.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "ConstantConditionIf", "SimplifyBooleanWithConstants", "RedundantSemicolon") 4 | fun collapsibleIfsNegative() { 5 | 6 | if (true) {} 7 | else if (1 == 1) { 8 | if (true) {} 9 | } 10 | 11 | if (true) { 12 | if (1 == 1) {} 13 | } else {} 14 | 15 | if (true) { 16 | if (1 == 1) {} 17 | } else if (false) {} 18 | else {} 19 | 20 | 21 | if (true) { 22 | if (1 == 1) ; 23 | println() 24 | } 25 | 26 | if (true) { 27 | if (1 == 1) { 28 | } else {} 29 | } 30 | 31 | if (true) { 32 | if (1 == 1) { 33 | } else if (2 == 2) {} 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/baseline/Baseline.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.baseline 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | data class Baseline(val blacklist: Blacklist, val whitelist: Whitelist) { 7 | 8 | override fun toString(): String { 9 | return "Baseline(blacklist=$blacklist, whitelist=$whitelist)" 10 | } 11 | } 12 | 13 | const val SMELL_BASELINE = "SmellBaseline" 14 | const val BLACKLIST = "Blacklist" 15 | const val WHITELIST = "Whitelist" 16 | const val TIMESTAMP = "timestamp" 17 | const val ID = "ID" 18 | 19 | class InvalidBaselineState(msg: String, error: Throwable) : IllegalStateException(msg, error) 20 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/processors/SLOCVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.core.path 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions 6 | import org.jetbrains.spek.api.Spek 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | class SLOCVisitorTest : Spek({ 10 | 11 | it("defaultClass") { 12 | val file = compileForTest(path.resolve("Default.kt")) 13 | val loc = with(file) { 14 | accept(SLOCVisitor()) 15 | getUserData(sourceLinesKey) 16 | } 17 | Assertions.assertThat(loc).isEqualTo(3) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/DetektSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.jetbrains.spek.api.Spek 5 | import org.jetbrains.spek.api.dsl.describe 6 | import org.jetbrains.spek.api.dsl.it 7 | 8 | /** 9 | * @author Artur Bosch 10 | */ 11 | class DetektSpec : Spek({ 12 | 13 | describe("default providers must be registered in META-INF/services") { 14 | 15 | val detekt = DetektFacade.create(ProcessingSettings(path)) 16 | 17 | it("should detect findings from more than one provider") { 18 | assertThat(detekt.run().findings).isNotEmpty 19 | } 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /docs/_includes/feedback.html: -------------------------------------------------------------------------------- 1 |
  • 2 | {% if site.feedback_text %} 3 | {% assign feedback_text = site.feedback_text %} 4 | {% else %} 5 | {% assign feedback_text = "Feedback" %} 6 | {% endif %} 7 | 8 | {% if site.feedback_link %} 9 | 10 | {% else %} 11 | 12 | {% endif %} 13 |
  • 14 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/OverloadedMethods.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "UNUSED_PARAMETER") 2 | 3 | package cases 4 | 5 | class OverloadedMethods { 6 | 7 | // reports 1 - x() method overload count exceeds threshold 8 | fun x() {} 9 | fun x(i: Int) {} 10 | fun x(i: Int, j: Int) {} 11 | 12 | private class InnerClass { 13 | 14 | // reports 1 - x() method overload count exceeds threshold 15 | fun x() {} 16 | fun x(i: Int) {} 17 | fun x(i: Int, j: Int) {} 18 | } 19 | } 20 | 21 | // reports 1 - overloadedMethod() method overload count exceeds threshold 22 | fun overloadedMethod() {} 23 | fun overloadedMethod(i: Int) {} 24 | fun overloadedMethod(i: Int, j: Int) {} 25 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyElseBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtIfExpression 5 | 6 | /** 7 | * Reports empty `else` blocks. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author Artur Bosch 11 | * @author Marvin Ramin 12 | */ 13 | class EmptyElseBlock(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitIfExpression(expression: KtIfExpression) { 16 | super.visitIfExpression(expression) 17 | expression.`else`?.addFindingIfBlockExprIsEmpty() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyForBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtForExpression 5 | 6 | /** 7 | * Reports empty `for` loops. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author Artur Bosch 11 | * @author Marvin Ramin 12 | */ 13 | class EmptyForBlock(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitForExpression(expression: KtForExpression) { 16 | super.visitForExpression(expression) 17 | expression.body?.addFindingIfBlockExprIsEmpty() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/ComplexInterfacePositive.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | // reports 1 - too many members 6 | interface TooLargeInterface { 7 | fun f1() 8 | fun f2() 9 | val i1: Int 10 | fun fImpl() { } 11 | } 12 | 13 | // reports 1 - too many members 14 | class ClassWithNestedInterface { 15 | 16 | interface TooLargeNestedInterface { 17 | fun f1() 18 | fun f2() 19 | val i1: Int 20 | fun fImpl() { } 21 | } 22 | } 23 | 24 | // reports 1 - too many members 25 | interface TooLargeInterfaceWithStaticDeclarations { 26 | fun f1() 27 | 28 | companion object { 29 | fun sf() = 0 30 | const val c = 0 31 | val si = 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/SingleAssign.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import kotlin.reflect.KProperty 4 | 5 | /** 6 | * @author Artur Bosch 7 | */ 8 | class SingleAssign { 9 | 10 | private lateinit var _value: T 11 | 12 | operator fun getValue(thisRef: Any?, property: KProperty<*>): T { 13 | check(this::_value.isInitialized) { "Property ${property.name} has not been assigned yet!" } 14 | return _value 15 | } 16 | 17 | operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { 18 | check(!this::_value.isInitialized) { "Property ${property.name} has already been assigned!" } 19 | _value = value 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /detekt-core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | configurations.testImplementation.extendsFrom(configurations.kotlinTest) 2 | 3 | val junitPlatformVersion: String by project 4 | val spekVersion: String by project 5 | val reflectionsVersion: String by project 6 | 7 | dependencies { 8 | implementation(kotlin("compiler-embeddable")) 9 | api(project(":detekt-api")) 10 | 11 | testImplementation(project(":detekt-rules")) 12 | testImplementation(project(":detekt-test")) 13 | testImplementation("org.reflections:reflections:$reflectionsVersion") 14 | testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junitPlatformVersion") 15 | testRuntimeOnly("org.jetbrains.spek:spek-junit-platform-engine:$spekVersion") 16 | } 17 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/AbstractProjectMetricProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import io.gitlab.arturbosch.detekt.api.ProjectMetric 5 | import org.jetbrains.kotlin.psi.KtFile 6 | 7 | /** 8 | * @author Artur Bosch 9 | */ 10 | abstract class AbstractProjectMetricProcessor : AbstractProcessor() { 11 | 12 | val type: String get() = key.toString() 13 | 14 | override fun onFinish(files: List, result: Detektion) { 15 | val count = files 16 | .mapNotNull { it.getUserData(key) } 17 | .sum() 18 | result.add(ProjectMetric(type, count)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/Filename.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.FilenameRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @author Artur Bosch 12 | */ 13 | class Filename(config: Config) : FormattingRule(config) { 14 | 15 | override val wrapping = FilenameRule() 16 | override val issue = issueFor("Checks if top level class matches the filename") 17 | } 18 | -------------------------------------------------------------------------------- /detekt-cli/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/out/TxtOutputReportTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.out 2 | 3 | import io.gitlab.arturbosch.detekt.cli.TestDetektion 4 | import io.gitlab.arturbosch.detekt.cli.createFinding 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.Spek 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | class TxtOutputReportTest : Spek({ 10 | 11 | it("render") { 12 | val report = TxtOutputReport() 13 | val detektion = TestDetektion(createFinding()) 14 | val renderedText = "TestSmell - [TestEntity] at TestFile.kt:1:1 - Signature=S1" 15 | assertThat(report.render(detektion)).isEqualTo(renderedText) 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/KtFileCountProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 5 | import org.jetbrains.kotlin.psi.KtFile 6 | 7 | class KtFileCountProcessor : AbstractProjectMetricProcessor() { 8 | 9 | override val visitor = KtFileCountVisitor() 10 | override val key = numberOfFilesKey 11 | } 12 | 13 | val numberOfFilesKey = Key("number of kt files") 14 | 15 | class KtFileCountVisitor : DetektVisitor() { 16 | override fun visitKtFile(file: KtFile) { 17 | file.putUserData(numberOfFilesKey, 1) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/processors/CLOCVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.core.path 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.Spek 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | class CLOCVisitorTest : Spek({ 10 | 11 | it("commentCases") { 12 | val file = compileForTest(path.resolve("../comments/CommentsClass.kt")) 13 | val commentLines = with(file) { 14 | accept(CLOCVisitor()) 15 | getUserData(commentLinesKey) 16 | } 17 | assertThat(commentLines).isEqualTo(10) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/DetektProgressListener.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import io.gitlab.arturbosch.detekt.api.FileProcessListener 5 | import org.jetbrains.kotlin.psi.KtFile 6 | 7 | /** 8 | * @author Artur Bosch 9 | */ 10 | class DetektProgressListener : FileProcessListener { 11 | 12 | override fun onProcess(file: KtFile) { 13 | kotlin.io.print(".") 14 | } 15 | 16 | override fun onFinish(files: List, result: Detektion) { 17 | val middlePart = if (files.size == 1) "file was" else "files were" 18 | kotlin.io.println("\n\n${files.size} kotlin $middlePart analyzed.") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptySecondaryConstructor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtSecondaryConstructor 5 | 6 | /** 7 | * Reports empty secondary constructors. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author schalkms 11 | * @author Marvin Ramin 12 | */ 13 | class EmptySecondaryConstructor(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) { 16 | constructor.bodyExpression?.addFindingIfBlockExprIsEmpty() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyWhileBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtWhileExpression 5 | 6 | /** 7 | * Reports empty `while` expressions. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author Artur Bosch 11 | * @author Marvin Ramin 12 | */ 13 | class EmptyWhileBlock(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitWhileExpression(expression: KtWhileExpression) { 16 | super.visitWhileExpression(expression) 17 | expression.body?.addFindingIfBlockExprIsEmpty() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/Junk.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.style 2 | 3 | import org.jetbrains.kotlin.com.intellij.openapi.util.TextRange 4 | import org.jetbrains.kotlin.com.intellij.psi.PsiElement 5 | import org.jetbrains.kotlin.psi.KtAnnotated 6 | import org.jetbrains.kotlin.psi.KtFile 7 | import org.jetbrains.kotlin.psi.psiUtil.elementsInRange 8 | 9 | internal fun findAnnotatedStatementInLine(file: KtFile, offset: Int, line: String): PsiElement? { 10 | return file.elementsInRange(TextRange.create(offset - line.length, offset)) 11 | .mapNotNull { it as? KtAnnotated ?: if (it.parent is KtAnnotated) it.parent else null } 12 | .firstOrNull() 13 | } 14 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/TooGenericExceptions.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | /** 5 | * @author Artur Bosch 6 | */ 7 | class TooGenericExceptions { 8 | 9 | fun main() { 10 | try { 11 | throw Throwable() 12 | } catch (e: ArrayIndexOutOfBoundsException) { 13 | throw Error() 14 | } catch (e: Error) { 15 | throw Exception() 16 | } catch (e: Exception) { 17 | } catch (e: IllegalMonitorStateException) { 18 | } catch (e: IndexOutOfBoundsException) { 19 | throw RuntimeException() 20 | } catch (e: Throwable) { 21 | } catch (e: RuntimeException) { 22 | throw NullPointerException() 23 | } catch (e: NullPointerException) { 24 | 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/ProjectLOCProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 5 | import org.jetbrains.kotlin.psi.KtFile 6 | 7 | class ProjectLOCProcessor : AbstractProcessor() { 8 | 9 | override val visitor: DetektVisitor = LOCVisitor() 10 | override val key = linesKey 11 | } 12 | 13 | class LOCVisitor : DetektVisitor() { 14 | 15 | override fun visitKtFile(file: KtFile) { 16 | val lines = file.text.count { it == '\n' } + 1 17 | file.putUserData(linesKey, lines) 18 | } 19 | } 20 | 21 | val linesKey = Key("loc") 22 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/baseline/XmlExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.baseline 2 | 3 | import javax.xml.stream.XMLStreamWriter 4 | 5 | fun XMLStreamWriter.document(init: XMLStreamWriter.() -> Unit) = apply { 6 | writeStartDocument() 7 | init() 8 | writeEndDocument() 9 | } 10 | 11 | fun XMLStreamWriter.tag(name: String, init: XMLStreamWriter.() -> Unit) = apply { 12 | writeStartElement(name) 13 | init() 14 | writeEndElement() 15 | } 16 | 17 | fun XMLStreamWriter.tag(name: String, content: String) { 18 | tag(name) { 19 | writeCharacters(content) 20 | } 21 | } 22 | 23 | fun XMLStreamWriter.attribute(name: String, value: String) = writeAttribute(name, value) 24 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/processors/FieldCountVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.core.path 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.Spek 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | class FieldCountVisitorTest : Spek({ 10 | 11 | it("defaultFieldCount") { 12 | val file = compileForTest(path.resolve("../fields/ClassWithFields.kt")) 13 | val count = with(file) { 14 | accept(PropertyCountVisitor()) 15 | getUserData(numberOfFieldsKey) 16 | } 17 | assertThat(count).isEqualTo(2) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyDoWhileBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtDoWhileExpression 5 | 6 | /** 7 | * Reports empty `do`/`while` loops. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author Artur Bosch 11 | * @author Marvin Ramin 12 | */ 13 | class EmptyDoWhileBlock(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitDoWhileExpression(expression: KtDoWhileExpression) { 16 | super.visitDoWhileExpression(expression) 17 | expression.body?.addFindingIfBlockExprIsEmpty() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/KtCompilerTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.jetbrains.spek.api.Spek 5 | import org.jetbrains.spek.api.dsl.it 6 | 7 | /** 8 | * @author Artur Bosch 9 | */ 10 | class KtCompilerTest : Spek({ 11 | 12 | it("ktFileHasExtraUserData") { 13 | val ktCompiler = KtCompiler() 14 | 15 | val ktFile = ktCompiler.compile(path, path.resolve("Default.kt")) 16 | 17 | assertThat(ktFile.getUserData(KtCompiler.LINE_SEPARATOR)).isEqualTo("\n") 18 | assertThat(ktFile.getUserData(KtCompiler.RELATIVE_PATH)) 19 | .isEqualTo(path.fileName.resolve("Default.kt").toString()) 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyFinallyBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import org.jetbrains.kotlin.psi.KtFinallySection 5 | 6 | /** 7 | * Reports empty `finally` blocks. Empty blocks of code serve no purpose and should be removed. 8 | * 9 | * @active since v1.0.0 10 | * @author Artur Bosch 11 | * @author Marvin Ramin 12 | */ 13 | class EmptyFinallyBlock(config: Config) : EmptyRule(config) { 14 | 15 | override fun visitFinallySection(finallySection: KtFinallySection) { 16 | super.visitFinallySection(finallySection) 17 | finallySection.finalExpression?.addFindingIfBlockExprIsEmpty() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/FinalNewline.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.FinalNewlineRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class FinalNewline(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = FinalNewlineRule() 17 | override val issue = issueFor("Detects missing final newlines") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoSemicolons.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoSemicolonsRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoSemicolons(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoSemicolonsRule() 17 | override val issue = issueFor("Detects semicolons") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/FilteredDetectionResult.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import io.gitlab.arturbosch.detekt.api.Finding 5 | import io.gitlab.arturbosch.detekt.cli.baseline.BaselineFacade 6 | 7 | /** 8 | * @author Artur Bosch 9 | */ 10 | class FilteredDetectionResult(detektion: Detektion, baselineFacade: BaselineFacade) : Detektion by detektion { 11 | 12 | private val filteredFindings: Map> 13 | 14 | init { 15 | filteredFindings = detektion.findings 16 | .map { (key, value) -> key to baselineFacade.filter(value) } 17 | .toMap() 18 | } 19 | 20 | override val findings = filteredFindings 21 | } 22 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoUnusedImports.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoUnusedImportsRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoUnusedImports(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoUnusedImportsRule() 17 | override val issue = issueFor("Detects unused imports") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/build.gradle.kts: -------------------------------------------------------------------------------- 1 | configurations.testImplementation.extendsFrom(configurations.kotlinTest) 2 | 3 | tasks["build"].finalizedBy(":detekt-generator:generateDocumentation") 4 | 5 | val junitPlatformVersion: String by project 6 | val spekVersion: String by project 7 | val reflectionsVersion: String by project 8 | 9 | dependencies { 10 | implementation(project(":detekt-api")) 11 | implementation(kotlin("compiler-embeddable")) 12 | 13 | testImplementation("org.reflections:reflections:$reflectionsVersion") 14 | testImplementation(project(":detekt-test")) 15 | testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junitPlatformVersion") 16 | testRuntimeOnly("org.jetbrains.spek:spek-junit-platform-engine:$spekVersion") 17 | } 18 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/PackageName.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.PackageNameRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Matthew Haughton 13 | */ 14 | class PackageName(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = PackageNameRule() 17 | override val issue = issueFor("Checks package name is formatted correctly") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/documentation/UndocumentedPublicFunctionSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.documentation 2 | 3 | import io.gitlab.arturbosch.detekt.rules.Case 4 | import io.gitlab.arturbosch.detekt.test.lint 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.dsl.it 7 | import org.jetbrains.spek.subject.SubjectSpek 8 | 9 | /** 10 | * @author Artur Bosch 11 | */ 12 | class UndocumentedPublicFunctionSpec : SubjectSpek({ 13 | subject { UndocumentedPublicFunction() } 14 | 15 | it("finds three undocumented functions") { 16 | subject.lint(Case.Comments.path()) 17 | assertThat(subject.findings).hasSize(3) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/deactivated-empty-blocks.yml: -------------------------------------------------------------------------------- 1 | empty-blocks: 2 | active: true 3 | EmptyCatchBlock: 4 | active: false 5 | EmptyClassBlock: 6 | active: false 7 | EmptyDefaultConstructor: 8 | active: false 9 | EmptyDoWhileBlock: 10 | active: false 11 | EmptyElseBlock: 12 | active: false 13 | EmptyFinallyBlock: 14 | active: false 15 | EmptyForBlock: 16 | active: false 17 | EmptyFunctionBlock: 18 | active: false 19 | EmptyIfBlock: 20 | active: false 21 | EmptyInitBlock: 22 | active: false 23 | EmptyKtFile: 24 | active: false 25 | EmptySecondaryConstructor: 26 | active: false 27 | EmptyWhenBlock: 28 | active: false 29 | EmptyWhileBlock: 30 | active: false 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request--not-related-to-rules-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request (not related to rules) 3 | about: Suggest new features/changes to detekt 4 | 5 | --- 6 | 7 | Your feature request may already be reported! 8 | Please search in the [issues](https://github.com/arturbosch/detekt/issues) before creating a new one. 9 | 10 | ## Expected Behavior 11 | 12 | 13 | ## Current Behavior 14 | 15 | 16 | ## Context 17 | 18 | 19 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/AnnotationExcluder.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import org.jetbrains.kotlin.psi.KtAnnotationEntry 4 | import org.jetbrains.kotlin.psi.KtFile 5 | 6 | class AnnotationExcluder( 7 | root: KtFile, 8 | private val excludes: SplitPattern) { 9 | 10 | private var resolvedAnnotations = root.importList 11 | ?.imports 12 | ?.filterNot { it.isAllUnder } 13 | ?.mapNotNull { it.importedFqName?.asString() } 14 | ?.map { Pair(it.split(".").last(), it) } 15 | ?.toMap() 16 | 17 | fun shouldExclude(annotations: List) = 18 | annotations.mapNotNull { resolvedAnnotations?.get(it.typeReference?.text) } 19 | .any { excludes.contains(it) } 20 | } 21 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/ImportOrdering.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.ImportOrderingRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class ImportOrdering(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = ImportOrderingRule() 17 | override val issue = issueFor("Detects imports in non default order") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoMultipleSpaces.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoMultipleSpacesRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoMultipleSpaces(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoMultipleSpacesRule() 17 | override val issue = issueFor("Reports multiple space usages") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/ChainWrapping.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.ChainWrappingRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class ChainWrapping(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = ChainWrappingRule() 17 | override val issue = issueFor("Checks if condition chaining is wrapped right") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/CommentSpacing.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.CommentSpacingRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class CommentSpacing(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = CommentSpacingRule() 17 | override val issue = issueFor("Checks if comments have the right spacing") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoUnitReturn.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoUnitReturnRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoUnitReturn(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoUnitReturnRule() 17 | override val issue = issueFor("Detects optional 'Unit' return types") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoLineBreakAfterElse.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoLineBreakAfterElseRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoLineBreakAfterElse(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoLineBreakAfterElseRule() 17 | override val issue = issueFor("Reports line breaks after else") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoWildcardImports.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoWildcardImportsRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoWildcardImports(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoWildcardImportsRule() 17 | override val issue = issueFor("Detects wildcast import usages") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoEmptyClassBody.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoEmptyClassBodyRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoEmptyClassBody(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoEmptyClassBodyRule() 17 | override val issue = issueFor("Reports empty class bodies") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoTrailingSpaces.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoTrailingSpacesRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoTrailingSpaces(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoTrailingSpacesRule() 17 | override val issue = issueFor("Detects trailing spaces") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundColon.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundColonRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class SpacingAroundColon(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundColonRule() 17 | override val issue = issueFor("Reports spaces around colons") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundComma.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundCommaRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class SpacingAroundComma(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundCommaRule() 17 | override val issue = issueFor("Reports spaces around commas") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-generator/src/test/resources/RuleSet.md: -------------------------------------------------------------------------------- 1 | style rule set 2 | 3 | ### WildcardImport 4 | 5 | a wildcard import 6 | 7 | **Severity**: Defect 8 | 9 | **Debt**: 10min 10 | 11 | **Aliases**: alias1, alias2 12 | 13 | #### Configuration options: 14 | 15 | * `conf1` (default: `foo`) 16 | 17 | a config option 18 | 19 | #### Noncompliant Code: 20 | 21 | ```kotlin 22 | import foo.* 23 | ``` 24 | 25 | #### Compliant Code: 26 | 27 | ```kotlin 28 | import foo.bar 29 | ``` 30 | 31 | ### EqualsNull 32 | 33 | equals null 34 | 35 | ### NoUnitKeyword 36 | 37 | removes :Unit 38 | 39 | **Debt**: 5m 40 | 41 | #### Noncompliant Code: 42 | 43 | ```kotlin 44 | fun stuff(): Unit {} 45 | ``` 46 | 47 | #### Compliant Code: 48 | 49 | ```kotlin 50 | fun stuff() {} 51 | ``` 52 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/ExceptionRaisedInMethodsNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "ConstantConditionIf", "RedundantOverride") 2 | 3 | package cases 4 | 5 | open class NoExceptionRaisedInMethods { 6 | 7 | init { 8 | throw IllegalStateException() 9 | } 10 | 11 | override fun toString(): String { 12 | return super.toString() 13 | } 14 | 15 | override fun hashCode(): Int { 16 | return super.hashCode() 17 | } 18 | 19 | override fun equals(other: Any?): Boolean { 20 | return super.equals(other) 21 | } 22 | 23 | companion object { 24 | init { 25 | throw IllegalStateException() 26 | } 27 | } 28 | 29 | fun doSomeEqualsComparison() { 30 | throw IllegalStateException() 31 | } 32 | 33 | protected fun finalize() { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/UnconditionalJumpStatementInLoopPositive.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "UNREACHABLE_CODE") 2 | 3 | package cases 4 | 5 | fun unconditionalJumpStatementsInLoop() { // reports 5 - 1 for every jump statement 6 | for (i in 1..2) break 7 | for (i in 1..2) continue 8 | for (i in 1..2) return 9 | while (true) break 10 | do { 11 | break 12 | } while (true) 13 | } 14 | 15 | fun unconditionalJumpStatementsInLoop2() { 16 | for (i in 1..2) { 17 | break // reports 1 - dead code 18 | print("") 19 | } 20 | for (i in 1..2) { 21 | print("") 22 | break // reports 1 23 | } 24 | } 25 | 26 | fun unconditionalJumpStatementInNestedLoop() { // reports 1 27 | for (i in 1..2) { 28 | for (j in 1..2) { 29 | break 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docs/_includes/custom/usermap.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 |
    5 | 6 |
    7 | 8 |
    9 | 10 |
    11 | 12 |
    13 | 14 |
    15 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/ModifierOrdering.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.ModifierOrderRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class ModifierOrdering(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = ModifierOrderRule() 17 | override val issue = issueFor("Detects modifiers in non default order") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoItParamInMultilineLambda.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoItParamInMultilineLambdaRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @author Artur Bosch 12 | */ 13 | class NoItParamInMultilineLambda(config: Config) : FormattingRule(config) { 14 | 15 | override val wrapping = NoItParamInMultilineLambdaRule() 16 | override val issue = issueFor("Reports 'it' variable usages in multiline lambdas") 17 | } 18 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundCurly.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundCurlyRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class SpacingAroundCurly(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundCurlyRule() 17 | override val issue = issueFor("Reports spaces around curly braces") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/StringTemplate.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.StringTemplateRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class StringTemplate(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = StringTemplateRule() 17 | override val issue = issueFor("Detects simplifications in template strings") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/RethrowCaughtExceptionPositive.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused", "UNREACHABLE_CODE", "UNUSED_EXPRESSION") 4 | fun rethrowCaughtExceptionPositive() { 5 | try { 6 | } catch (e: IllegalStateException) { 7 | throw e // reports 1 - the same exception is rethrown 8 | } 9 | try { 10 | } catch (e: IllegalStateException) { 11 | throw e // reports 1 - dead code after the same exception is rethrown 12 | print("log") 13 | } 14 | try { 15 | } catch (e: IllegalStateException) { 16 | print("log") // reports 1 - exception is not logged 17 | throw e 18 | } 19 | try { 20 | } catch (e: IllegalStateException) { 21 | print(e.message) // reports 1 - logs only the exception message, exception is lost 22 | throw e 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoBlankLineBeforeRbrace.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoBlankLineBeforeRbraceRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoBlankLineBeforeRbrace(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoBlankLineBeforeRbraceRule() 17 | override val issue = issueFor("Detects blank lines before rbraces") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundKeyword.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundKeywordRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class SpacingAroundKeyword(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundKeywordRule() 17 | override val issue = issueFor("Reports spaces around keywords") 18 | } 19 | -------------------------------------------------------------------------------- /docs/js/jquery.ba-throttle-debounce.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery throttle / debounce - v1.1 - 3/7/2010 3 | * http://benalman.com/projects/jquery-throttle-debounce-plugin/ 4 | * 5 | * Copyright (c) 2010 "Cowboy" Ben Alman 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://benalman.com/about/license/ 8 | */ 9 | (function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this); -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundParens.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundParensRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Matthew Haughton 13 | */ 14 | class SpacingAroundParens(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundParensRule() 17 | override val issue = issueFor("Reports spaces around parentheses") 18 | } 19 | -------------------------------------------------------------------------------- /docs/_includes/toc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 |
    22 | -------------------------------------------------------------------------------- /commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This hook script checks the commit log message. 4 | # Called by "git commit" with one argument, the name of the file that has the commit message. 5 | 6 | msg=$1 7 | 8 | # checks if the first character of the commit message is an uppercase letter 9 | uppercase='^[A-Z]' 10 | if ! head -1 "$msg" | grep -Eq "$uppercase"; then 11 | echo "Aborting commit. The commit message does not start with an uppercase letter." >&2 12 | exit 1 13 | fi 14 | 15 | # checks if the second line of the commit message is empty 16 | len=`awk 'END{print NR}' $msg` 17 | if [ "$len" -ge 2 ]; then 18 | line=`sed -n 2p $msg` 19 | if [ "$line" != "" ]; then 20 | echo "Aborting commit. The commit message does not have a empty second line." >&2 21 | exit 1 22 | fi 23 | fi 24 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoConsecutiveBlankLines.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoConsecutiveBlankLinesRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoConsecutiveBlankLines(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoConsecutiveBlankLinesRule() 17 | override val issue = issueFor("Reports consecutive blank lines") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundOperators.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundOperatorsRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class SpacingAroundOperators(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundOperatorsRule() 17 | override val issue = issueFor("Reports spaces around operators") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/NoLineBreakBeforeAssignment.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.NoLineBreakBeforeAssignmentRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class NoLineBreakBeforeAssignment(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = NoLineBreakBeforeAssignmentRule() 17 | override val issue = issueFor("Reports line breaks after else") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/MethodSignature.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules 2 | 3 | import org.jetbrains.kotlin.psi.KtFunction 4 | import org.jetbrains.kotlin.psi.KtNamedFunction 5 | 6 | fun KtFunction.isEqualsFunction() = 7 | this.name == "equals" && hasCorrectEqualsParameter() && this.isOverridden() 8 | 9 | fun KtFunction.isHashCodeFunction() = 10 | this.name == "hashCode" && this.valueParameters.isEmpty() && this.isOverridden() 11 | 12 | private val knownAnys = setOf("Any?", "kotlin.Any?") 13 | fun KtFunction.hasCorrectEqualsParameter() = 14 | this.valueParameters.firstOrNull()?.typeReference?.text in knownAnys 15 | 16 | fun KtNamedFunction.isMainFunction() = 17 | this.name == "main" && this.isPublicNotOverridden() && this.isTopLevel 18 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/optional/ConditionalPathVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.style.optional 2 | 3 | import io.gitlab.arturbosch.detekt.rules.Case 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.Spek 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | /** 10 | * @author Artur Bosch 11 | */ 12 | class ConditionalPathVisitorTest : Spek({ 13 | 14 | it("pathCount") { 15 | var counter = 0 16 | 17 | val visitor = ConditionalPathVisitor { 18 | counter++ 19 | } 20 | 21 | val ktFile = compileForTest(Case.ConditionalPath.path()) 22 | 23 | ktFile.accept(visitor) 24 | 25 | assertThat(counter).isEqualTo(5) 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/ProtectedMemberInFinalClassNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "RedundantVisibilityModifier", "ProtectedInFinal", "ConvertSecondaryConstructorToPrimary") 2 | 3 | package cases 4 | 5 | class NoProtectedMembersInFinalClass : BaseClass() { 6 | 7 | private val i = 0 8 | 9 | // should not report protected = private visibility 10 | protected override val abstractProp = 0 11 | 12 | // should not report protected = private visibility 13 | protected override fun abstractFunction() { 14 | } 15 | } 16 | 17 | abstract class BaseClass { 18 | 19 | protected abstract val abstractProp: Int 20 | protected abstract fun abstractFunction() 21 | 22 | protected object InnerObject 23 | } 24 | 25 | sealed class SealedClass { 26 | 27 | protected fun a() {} 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /detekt-sample-extensions/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val assertjVersion: String by project 2 | val usedDetektVersion: String by project 3 | val junitPlatformVersion: String by project 4 | val spekVersion: String by project 5 | 6 | dependencies { 7 | implementation("io.gitlab.arturbosch.detekt:detekt-api:$usedDetektVersion") 8 | 9 | testImplementation("io.gitlab.arturbosch.detekt:detekt-test:$usedDetektVersion") 10 | testImplementation("org.assertj:assertj-core:$assertjVersion") 11 | testImplementation("org.jetbrains.spek:spek-api:$spekVersion") 12 | testImplementation("org.jetbrains.spek:spek-subject-extension:$spekVersion") 13 | 14 | testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junitPlatformVersion") 15 | testRuntimeOnly("org.jetbrains.spek:spek-junit-platform-engine:$spekVersion") 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - openjdk8 4 | - openjdk9 5 | - openjdk10 6 | - openjdk11 7 | script: 8 | - ./gradlew build -PwarningsAsErrors=true 9 | - ./gradlew shadowJar 10 | - java -jar ./detekt-cli/build/libs/detekt-cli-*-all.jar --help 11 | - java -jar ./detekt-cli/build/libs/detekt-cli-*-all.jar -i . --baseline ./reports/baseline.xml -f ".*/resources/.*,.*/build/.*" -c ./detekt-cli/src/main/resources/default-detekt-config.yml,./reports/failfast.yml 12 | - ./gradlew verifyGeneratorOutput 13 | after_success: 14 | - .buildscript/deploy_snapshot.sh 15 | before_cache: 16 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 17 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 18 | cache: 19 | directories: 20 | - $HOME/.gradle/caches/ 21 | - $HOME/.gradle/wrapper/ 22 | -------------------------------------------------------------------------------- /detekt-formatting/src/main/kotlin/io/gitlab/arturbosch/detekt/formatting/wrappers/SpacingAroundRangeOperator.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.formatting.wrappers 2 | 3 | import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundRangeOperatorRule 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.formatting.FormattingRule 6 | 7 | /** 8 | * See ktlint-website for documentation. 9 | * 10 | * @active since v1.0.0 11 | * @autoCorrect since v1.0.0 12 | * @author Artur Bosch 13 | */ 14 | class SpacingAroundRangeOperator(config: Config) : FormattingRule(config) { 15 | 16 | override val wrapping = SpacingAroundRangeOperatorRule() 17 | override val issue = issueFor("Reports spaces around range operator") 18 | } 19 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/UnreachableCodeSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.bugs 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import io.gitlab.arturbosch.detekt.rules.Case 5 | import io.gitlab.arturbosch.detekt.test.lint 6 | import org.assertj.core.api.Assertions.assertThat 7 | import org.jetbrains.spek.api.dsl.given 8 | import org.jetbrains.spek.api.dsl.it 9 | import org.jetbrains.spek.subject.SubjectSpek 10 | 11 | class UnreachableCodeSpec : SubjectSpek({ 12 | subject { UnreachableCode(Config.empty) } 13 | 14 | given("several unreachable statements") { 15 | 16 | it("reports unreachable code") { 17 | val path = Case.UnreachableCode.path() 18 | assertThat(subject.lint(path)).hasSize(6) 19 | } 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/EqualsAlwaysReturnsTrueOrFalseNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("EqualsOrHashCode", "unused", "UNREACHABLE_CODE") 2 | 3 | package cases 4 | 5 | class EqualsReturnsTrueOrFalse { 6 | 7 | override fun equals(other: Any?): Boolean { 8 | if (other is Int) { 9 | return true 10 | } 11 | return false 12 | } 13 | } 14 | 15 | class CorrectEquals { 16 | 17 | override fun equals(other: Any?): Boolean { 18 | return this.toString() == other.toString() 19 | } 20 | } 21 | 22 | fun equals(other: Any?): Boolean { 23 | return false 24 | } 25 | 26 | class NotOverridingEquals { 27 | 28 | fun equal(other: Any?): Boolean { 29 | return true 30 | } 31 | } 32 | 33 | class WrongEqualsParameterList { 34 | 35 | fun equals(other: Any, i: Int): Boolean { 36 | return true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/kotlin/io/gitlab/arturbosch/detekt/sample/extensions/SampleProvider.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.sample.extensions 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import io.gitlab.arturbosch.detekt.api.RuleSet 5 | import io.gitlab.arturbosch.detekt.api.RuleSetProvider 6 | import io.gitlab.arturbosch.detekt.sample.extensions.rules.TooManyFunctions 7 | import io.gitlab.arturbosch.detekt.sample.extensions.rules.TooManyFunctionsTwo 8 | 9 | /** 10 | * @author Artur Bosch 11 | */ 12 | class SampleProvider : RuleSetProvider { 13 | 14 | override val ruleSetId: String = "sample" 15 | 16 | override fun instance(config: Config): RuleSet { 17 | return RuleSet(ruleSetId, listOf( 18 | TooManyFunctions(), 19 | TooManyFunctionsTwo(config) 20 | )) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/_includes/custom/getting_started_series.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 | 18 |
    19 |
    -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/MultiRule.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import org.jetbrains.kotlin.psi.KtFile 4 | 5 | abstract class MultiRule : BaseRule() { 6 | 7 | abstract val rules: List 8 | var activeRules: Set by SingleAssign() 9 | var ruleFilters: Set = emptySet() 10 | 11 | override fun visitCondition(root: KtFile) = true 12 | 13 | override fun preVisit(root: KtFile) { 14 | activeRules = rules.filterTo(HashSet()) { 15 | it.ruleId !in ruleFilters && it.visitCondition(root) 16 | } 17 | } 18 | 19 | override fun postVisit(root: KtFile) { 20 | report(activeRules.flatMap { it.findings }) 21 | } 22 | 23 | fun T.runIfActive(block: T.() -> Unit) { 24 | if (this in activeRules) { 25 | block() 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/ProjectLLOCProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import io.gitlab.arturbosch.detekt.core.processors.util.LLOC 5 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 6 | import org.jetbrains.kotlin.psi.KtFile 7 | 8 | class ProjectLLOCProcessor : AbstractProcessor() { 9 | 10 | override val visitor = LLOCVisitor() 11 | override val key = logicalLinesKey 12 | } 13 | 14 | val logicalLinesKey = Key("lloc") 15 | 16 | class LLOCVisitor : DetektVisitor() { 17 | 18 | override fun visitKtFile(file: KtFile) { 19 | val lines = file.text.split("\n") 20 | val value = LLOC.analyze(lines) 21 | file.putUserData(logicalLinesKey, value) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyKtFile.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.CodeSmell 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.api.Entity 6 | import org.jetbrains.kotlin.psi.KtFile 7 | 8 | /** 9 | * Reports empty Kotlin (.kt) files. Empty blocks of code serve no purpose and should be removed. 10 | * 11 | * @active since v1.0.0 12 | * @author schalkms 13 | * @author Marvin Ramin 14 | */ 15 | class EmptyKtFile(config: Config) : EmptyRule(config) { 16 | 17 | override fun visitKtFile(file: KtFile) { 18 | if (file.text.isNullOrBlank()) { 19 | report(CodeSmell(issue, Entity.from(file), "The empty Kotlin file ${file.name} can be removed.")) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/search.json: -------------------------------------------------------------------------------- 1 | --- 2 | title: search 3 | layout: none 4 | search: exclude 5 | --- 6 | 7 | [ 8 | {% for page in site.pages %} 9 | {% unless page.search == "exclude" %} 10 | { 11 | "title": "{{ page.title | escape }}", 12 | "tags": "{{ page.tags }}", 13 | "keywords": "{{page.keywords}}", 14 | "url": "{{ page.url | remove: "/"}}", 15 | "summary": "{{page.summary | strip }}" 16 | } 17 | {% unless forloop.last and site.posts.size < 1 %},{% endunless %} 18 | {% endunless %} 19 | {% endfor %} 20 | 21 | {% for post in site.posts %} 22 | 23 | { 24 | "title": "{{ post.title | escape }}", 25 | "tags": "{{ post.tags }}", 26 | "keywords": "{{post.keywords}}", 27 | "url": "{{ post.url | remove: "/" }}", 28 | "summary": "{{post.summary | strip }}" 29 | } 30 | {% unless forloop.last %},{% endunless %} 31 | {% endfor %} 32 | 33 | ] 34 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/CompositeConfig.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | class CompositeConfig(private val lookFirst: Config, private val lookSecond: Config) : Config { 7 | 8 | override fun subConfig(key: String): Config { 9 | return CompositeConfig(lookFirst.subConfig(key), lookSecond.subConfig(key)) 10 | } 11 | 12 | override fun valueOrDefault(key: String, default: T): T { 13 | return lookFirst.valueOrNull(key) ?: lookSecond.valueOrDefault(key, default) 14 | } 15 | 16 | override fun valueOrNull(key: String): T? { 17 | return lookFirst.valueOrNull(key) ?: lookSecond.valueOrNull(key) 18 | } 19 | 20 | override fun toString() = "CompositeConfig(lookFirst=$lookFirst, lookSecond=$lookSecond)" 21 | } 22 | -------------------------------------------------------------------------------- /docs/_includes/custom/series_acme.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 | 18 |
    19 |
    -------------------------------------------------------------------------------- /detekt-api/src/test/kotlin/io/gitlab/arturbosch/detekt/api/MetricSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.assertj.core.api.Assertions.assertThatIllegalStateException 5 | import org.jetbrains.spek.api.Spek 6 | import org.jetbrains.spek.api.dsl.it 7 | 8 | /** 9 | * @author Artur Bosch 10 | */ 11 | class MetricSpec : Spek({ 12 | 13 | it("should convert double values to int") { 14 | val metric = Metric("LOC", 0.33, 0.10, 100) 15 | assertThat(metric.doubleValue()).isEqualTo(0.33) 16 | assertThat(metric.doubleThreshold()).isEqualTo(0.10) 17 | } 18 | 19 | it("should throw error if double value is asked for int metric") { 20 | assertThatIllegalStateException().isThrownBy { 21 | Metric("LOC", 100, 50).doubleValue() 22 | } 23 | } 24 | }) 25 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/providers/EmptyCodeProvider.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.providers 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import io.gitlab.arturbosch.detekt.api.RuleSet 5 | import io.gitlab.arturbosch.detekt.api.RuleSetProvider 6 | import io.gitlab.arturbosch.detekt.rules.empty.EmptyBlocks 7 | 8 | /** 9 | * The empty-blocks ruleset contains rules that will report empty blocks of code 10 | * which should be avoided. 11 | * 12 | * @active since v1.0.0 13 | * @author Artur Bosch 14 | */ 15 | class EmptyCodeProvider : RuleSetProvider { 16 | 17 | override val ruleSetId: String = "empty-blocks" 18 | 19 | override fun instance(config: Config): RuleSet { 20 | return RuleSet(ruleSetId, listOf( 21 | EmptyBlocks(config) 22 | )) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /detekt-cli/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.FileProcessListener: -------------------------------------------------------------------------------- 1 | io.gitlab.arturbosch.detekt.cli.DetektProgressListener 2 | io.gitlab.arturbosch.detekt.core.processors.KtFileCountProcessor 3 | io.gitlab.arturbosch.detekt.core.processors.PackageCountProcessor 4 | io.gitlab.arturbosch.detekt.core.processors.ClassCountProcessor 5 | io.gitlab.arturbosch.detekt.core.processors.FunctionCountProcessor 6 | io.gitlab.arturbosch.detekt.core.processors.PropertyCountProcessor 7 | io.gitlab.arturbosch.detekt.core.processors.ProjectComplexityProcessor 8 | io.gitlab.arturbosch.detekt.core.processors.ProjectLLOCProcessor 9 | io.gitlab.arturbosch.detekt.core.processors.ProjectCLOCProcessor 10 | io.gitlab.arturbosch.detekt.core.processors.ProjectLOCProcessor 11 | io.gitlab.arturbosch.detekt.core.processors.ProjectSLOCProcessor 12 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/NestedClassVisibilityPositive.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "RedundantVisibilityModifier") 2 | 3 | package cases 4 | 5 | internal class NestedClassesVisibilityPositive { 6 | 7 | // reports 1 - public visibility 8 | public class NestedPublicClass1 9 | // reports 1 - public visibility 10 | class NestedPublicClass2 11 | // reports 1 - public visibility 12 | interface NestedPublicInterface 13 | 14 | // reports 1 - public visibility 15 | object A 16 | 17 | // reports 1 - public visibility 18 | public class NestedClassWithNestedCLass { 19 | 20 | // classes with a nesting depth higher than 1 are excluded 21 | public class NestedClass 22 | } 23 | } 24 | 25 | internal enum class NestedEnumsVisibility { 26 | 27 | A; 28 | 29 | class Inner // reports 1 - public visibility inside enum class 30 | } 31 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/ProjectComplexityProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import io.gitlab.arturbosch.detekt.api.internal.McCabeVisitor 5 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 6 | import org.jetbrains.kotlin.psi.KtFile 7 | 8 | class ProjectComplexityProcessor : AbstractProcessor() { 9 | 10 | override val visitor = ComplexityVisitor() 11 | override val key = complexityKey 12 | } 13 | 14 | val complexityKey = Key("complexity") 15 | 16 | class ComplexityVisitor : DetektVisitor() { 17 | 18 | override fun visitKtFile(file: KtFile) { 19 | with(McCabeVisitor(ignoreSimpleWhenEntries = false)) { 20 | file.accept(this) 21 | file.putUserData(complexityKey, mcc) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/processors/MethodCountVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.core.path 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.kotlin.psi.KtFile 7 | import org.jetbrains.spek.api.Spek 8 | import org.jetbrains.spek.api.dsl.it 9 | 10 | class MethodCountVisitorTest : Spek({ 11 | 12 | it("defaultMethodCount") { 13 | val file = compileForTest(path.resolve("ComplexClass.kt")) 14 | val count = getMethodCount(file) 15 | assertThat(count).isEqualTo(6) 16 | } 17 | 18 | }) 19 | 20 | private fun getMethodCount(file: KtFile): Int { 21 | return with(file) { 22 | accept(FunctionCountVisitor()) 23 | getUserData(numberOfFunctionsKey)!! 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/out/AbstractWriter.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.generator.out 2 | 3 | import java.nio.file.Files 4 | import java.nio.file.Path 5 | 6 | /** 7 | * @author Marvin Ramin 8 | */ 9 | internal abstract class AbstractWriter { 10 | 11 | protected abstract val ending: String 12 | 13 | fun write(path: Path, fileName: String, content: () -> String) { 14 | val filePath = path.resolve("$fileName.$ending") 15 | filePath.parent?.let { Files.createDirectories(it) } 16 | Files.write(filePath, content().toByteArray()) 17 | println("Wrote: $fileName.$ending") 18 | } 19 | } 20 | 21 | internal class MarkdownWriter : AbstractWriter() { 22 | 23 | override val ending = "md" 24 | } 25 | 26 | internal class YamlWriter : AbstractWriter() { 27 | 28 | override val ending = "yml" 29 | } 30 | -------------------------------------------------------------------------------- /detekt-gradle-plugin/src/main/kotlin/io/gitlab/arturbosch/detekt/extensions/DetektReports.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.extensions 2 | 3 | import groovy.lang.Closure 4 | import io.gitlab.arturbosch.detekt.extensions.DetektReportType.HTML 5 | import io.gitlab.arturbosch.detekt.extensions.DetektReportType.XML 6 | import org.gradle.api.Project 7 | import org.gradle.util.ConfigureUtil 8 | 9 | class DetektReports(project: Project) { 10 | 11 | val xml = DetektReport(XML, project) 12 | 13 | val html = DetektReport(HTML, project) 14 | 15 | fun xml(configure: DetektReport.() -> Unit) = xml.configure() 16 | fun xml(closure: Closure<*>): DetektReport = ConfigureUtil.configure(closure, xml) 17 | 18 | fun html(configure: DetektReport.() -> Unit) = html.configure() 19 | fun html(closure: Closure<*>): DetektReport = ConfigureUtil.configure(closure, html) 20 | } 21 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/service/DirectoryRegisteringVisitor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.service 2 | 3 | import java.nio.file.FileVisitResult 4 | import java.nio.file.Path 5 | import java.nio.file.SimpleFileVisitor 6 | import java.nio.file.StandardWatchEventKinds.ENTRY_CREATE 7 | import java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY 8 | import java.nio.file.WatchService 9 | import java.nio.file.attribute.BasicFileAttributes 10 | 11 | /** 12 | * @author Artur Bosch 13 | */ 14 | class DirectoryRegisteringVisitor( 15 | private val watchService: WatchService 16 | ) : SimpleFileVisitor() { 17 | 18 | override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { 19 | dir.register(watchService, ENTRY_CREATE, ENTRY_MODIFY) 20 | return FileVisitResult.CONTINUE 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/AbstractProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import io.gitlab.arturbosch.detekt.api.Detektion 5 | import io.gitlab.arturbosch.detekt.api.FileProcessListener 6 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 7 | import org.jetbrains.kotlin.psi.KtFile 8 | 9 | abstract class AbstractProcessor : FileProcessListener { 10 | 11 | protected abstract val visitor: DetektVisitor 12 | protected abstract val key: Key 13 | 14 | override fun onProcess(file: KtFile) { 15 | file.accept(visitor) 16 | } 17 | 18 | override fun onFinish(files: List, result: Detektion) { 19 | val count = files 20 | .mapNotNull { it.getUserData(key) } 21 | .sum() 22 | result.addData(key, count) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/SerializablePositive.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused") 2 | 3 | package cases 4 | 5 | import java.io.Serializable 6 | 7 | class IncorrectSerialVersionUID1 : Serializable { 8 | companion object { 9 | const val serialVersionUID = 1 // reports 1 - wrong datatype 10 | } 11 | } 12 | 13 | class IncorrectSerialVersionUID2 : Serializable { 14 | companion object { 15 | const val serialVersionUUID = 1L // reports 1 - wrong naming 16 | } 17 | 18 | object NestedIncorrectSerialVersionUID : Serializable { 19 | val serialVersionUUID = 1L // reports 1 - missing const modifier 20 | } 21 | } 22 | 23 | class IncorrectSerialVersionUID3 : Serializable { 24 | companion object { 25 | const val serialVersionUID: Int = 1 // reports 1 - wrong datatype 26 | } 27 | } 28 | 29 | class NoSerialVersionUID : Serializable // reports 1 - no serialVersionUID at all 30 | -------------------------------------------------------------------------------- /detekt-sample-extensions/src/main/kotlin/io/gitlab/arturbosch/detekt/sample/extensions/reports/Reports.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.sample.extensions.reports 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 5 | 6 | @Suppress("UNCHECKED_CAST", "DEPRECATION") 7 | fun qualifiedNamesReport(detektion: Detektion): String? { 8 | // referencing the original key 'fqNamesKey' does not retrieve the stored values 9 | // using the deprecated method seems to work for unknown reasons 10 | val key = Key.findKeyByName("FQNames") as Key> 11 | val fqNames = detektion.getData(key) 12 | println("fqNames: " + fqNames) 13 | if (fqNames == null || fqNames.isEmpty()) return null 14 | 15 | return with(StringBuilder()) { 16 | fqNames.forEach { 17 | append(it + "\n") 18 | } 19 | toString() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/console/ComplexityMetric.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.console 2 | 3 | import io.gitlab.arturbosch.detekt.api.Detektion 4 | import io.gitlab.arturbosch.detekt.core.processors.complexityKey 5 | import io.gitlab.arturbosch.detekt.core.processors.logicalLinesKey 6 | import io.gitlab.arturbosch.detekt.core.processors.linesKey 7 | import io.gitlab.arturbosch.detekt.core.processors.commentLinesKey 8 | import io.gitlab.arturbosch.detekt.core.processors.sourceLinesKey 9 | 10 | class ComplexityMetric(detektion: Detektion) { 11 | 12 | val mcc = detektion.getData(complexityKey) 13 | val loc = detektion.getData(linesKey) 14 | val sloc = detektion.getData(sourceLinesKey) 15 | val lloc = detektion.getData(logicalLinesKey) 16 | val cloc = detektion.getData(commentLinesKey) 17 | val findings = detektion.findings.entries 18 | } 19 | -------------------------------------------------------------------------------- /detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/console/ProjectStatisticsReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.cli.console 2 | 3 | import io.gitlab.arturbosch.detekt.api.ConsoleReport 4 | import io.gitlab.arturbosch.detekt.api.Detektion 5 | import io.gitlab.arturbosch.detekt.api.PREFIX 6 | import io.gitlab.arturbosch.detekt.api.format 7 | 8 | /** 9 | * @author Artur Bosch 10 | */ 11 | class ProjectStatisticsReport : ConsoleReport() { 12 | 13 | override val priority: Int = 10 14 | 15 | override fun render(detektion: Detektion): String? { 16 | val metrics = detektion.metrics 17 | if (metrics.isEmpty()) return null 18 | return with(StringBuilder()) { 19 | append("Project Statistics:".format()) 20 | metrics.sortedBy { it.priority } 21 | .reversed() 22 | .forEach { append(it.toString().format(PREFIX)) } 23 | toString() 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /detekt-rules/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/empty/EmptyWhenBlock.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.empty 2 | 3 | import io.gitlab.arturbosch.detekt.api.CodeSmell 4 | import io.gitlab.arturbosch.detekt.api.Config 5 | import io.gitlab.arturbosch.detekt.api.Entity 6 | import org.jetbrains.kotlin.psi.KtWhenExpression 7 | 8 | /** 9 | * Reports empty `when` expressions. Empty blocks of code serve no purpose and should be removed. 10 | * 11 | * @active since v1.0.0 12 | * @author Artur Bosch 13 | * @author Marvin Ramin 14 | */ 15 | class EmptyWhenBlock(config: Config) : EmptyRule(config) { 16 | 17 | override fun visitWhenExpression(expression: KtWhenExpression) { 18 | super.visitWhenExpression(expression) 19 | if (expression.entries.isEmpty()) { 20 | report(CodeSmell(issue, Entity.from(expression), "This when block is empty.")) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/ClassCountProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import io.gitlab.arturbosch.detekt.core.processors.util.collectByType 5 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 6 | import org.jetbrains.kotlin.psi.KtClass 7 | import org.jetbrains.kotlin.psi.KtFile 8 | 9 | class ClassCountProcessor : AbstractProjectMetricProcessor() { 10 | 11 | override val visitor = ClassCountVisitor() 12 | override val key = numberOfClassesKey 13 | } 14 | 15 | val numberOfClassesKey = Key("number of classes") 16 | 17 | class ClassCountVisitor : DetektVisitor() { 18 | 19 | override fun visitKtFile(file: KtFile) { 20 | super.visitKtFile(file) 21 | file.putUserData(numberOfClassesKey, file.collectByType().size) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/TooManyFunctions.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | @Suppress("unused") 4 | class TooManyFunctions { 5 | 6 | fun f1() { 7 | println() 8 | } 9 | 10 | fun f2() { 11 | println() 12 | } 13 | 14 | fun f3() { 15 | println() 16 | } 17 | 18 | fun f4() { 19 | println() 20 | } 21 | 22 | fun f5() { 23 | println() 24 | } 25 | 26 | fun f6() { 27 | println() 28 | } 29 | 30 | fun f7() { 31 | println() 32 | } 33 | 34 | fun f8() { 35 | println() 36 | } 37 | 38 | fun f9() { 39 | println() 40 | } 41 | 42 | fun f10() { 43 | println() 44 | } 45 | 46 | fun f11() { 47 | println() 48 | } 49 | 50 | fun f12() { 51 | println() 52 | } 53 | 54 | fun f13() { 55 | println() 56 | } 57 | 58 | fun f14() { 59 | println() 60 | } 61 | 62 | fun f15() { 63 | println() 64 | } 65 | 66 | fun f16() { 67 | println() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/exceptions/SwallowedExceptionSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.exceptions 2 | 3 | import io.gitlab.arturbosch.detekt.rules.Case 4 | import io.gitlab.arturbosch.detekt.test.lint 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.dsl.given 7 | import org.jetbrains.spek.api.dsl.it 8 | import org.jetbrains.spek.subject.SubjectSpek 9 | 10 | class SwallowedExceptionSpec : SubjectSpek({ 11 | subject { SwallowedException() } 12 | 13 | given("several catch blocks") { 14 | 15 | it("reports swallowed exceptions") { 16 | assertThat(subject.lint(Case.SwallowedExceptionPositive.path())).hasSize(3) 17 | } 18 | 19 | it("does not report thrown catch blocks") { 20 | assertThat(subject.lint(Case.SwallowedExceptionNegative.path())).hasSize(0) 21 | } 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/UnnecessaryAbstractClassNegative.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("unused", "RemoveEmptyPrimaryConstructor") 2 | 3 | package cases 4 | 5 | import jdk.nashorn.internal.ir.annotations.Ignore 6 | 7 | abstract class AbstractClassOk { 8 | 9 | abstract val i: Int 10 | fun f() { } 11 | } 12 | 13 | abstract class AbstractClassWithPrimaryConstructorConcretePropertyOk(val i: Int) { 14 | abstract fun f() 15 | } 16 | 17 | // empty abstract classes should not be reported by this rule 18 | abstract class EmptyAbstractClass1 19 | abstract class EmptyAbstractClass2() 20 | 21 | // This test case should be removed when type resolution is available - see issue #727 22 | abstract class AbstractClassDerivedFrom : EmptyAbstractClass1() { 23 | 24 | fun f() {} 25 | } 26 | 27 | @Ignore abstract class AbstractClassWithModuleAnnotation { 28 | abstract fun binds(foo: Integer): Number 29 | } 30 | -------------------------------------------------------------------------------- /detekt-api/src/main/kotlin/io/gitlab/arturbosch/detekt/api/OutputReport.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.api 2 | 3 | import java.nio.file.Files 4 | import java.nio.file.Path 5 | 6 | /** 7 | * @author Artur Bosch 8 | * @author Marvin Ramin 9 | */ 10 | abstract class OutputReport : Extension { 11 | 12 | abstract val ending: String 13 | 14 | open val name 15 | get() = this::class.simpleName 16 | 17 | fun write(filePath: Path, detektion: Detektion) { 18 | val reportData = render(detektion) 19 | if (reportData != null) { 20 | assert(filePath.fileName.toString().endsWith(ending)) { 21 | "The $name needs to have a file ending of type .$ending, but was ${filePath.fileName}." 22 | } 23 | filePath.parent?.let { Files.createDirectories(it) } 24 | Files.write(filePath, reportData.toByteArray()) 25 | } 26 | } 27 | 28 | abstract fun render(detektion: Detektion): String? 29 | } 30 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/CommonSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules 2 | 3 | import io.gitlab.arturbosch.detekt.api.Rule 4 | import io.gitlab.arturbosch.detekt.rules.style.WildcardImport 5 | import io.gitlab.arturbosch.detekt.test.compileForTest 6 | import io.gitlab.arturbosch.detekt.test.lint 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.jetbrains.spek.api.dsl.describe 9 | import org.jetbrains.spek.api.dsl.it 10 | import org.jetbrains.spek.subject.SubjectSpek 11 | 12 | /** 13 | * @author Artur Bosch 14 | */ 15 | class CommonSpec : SubjectSpek({ 16 | subject { WildcardImport() } 17 | val file = compileForTest(Case.Default.path()) 18 | 19 | describe("running specified rule") { 20 | it("should detect one finding") { 21 | subject.lint(file.text) 22 | assertThat(subject.findings).hasSize(1) 23 | } 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /detekt-watcher/src/main/kotlin/io/gitlab/arturbosch/detekt/watcher/state/Parameters.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.watcher.state 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import io.gitlab.arturbosch.detekt.cli.CliArgs 5 | import io.gitlab.arturbosch.detekt.cli.ExistingPathConverter 6 | import io.gitlab.arturbosch.detekt.cli.loadConfiguration 7 | import java.nio.file.Path 8 | import java.nio.file.Paths 9 | 10 | /** 11 | * @author Artur Bosch 12 | */ 13 | class Parameters( 14 | private val input: String? = null, 15 | private var config: String? = null 16 | ) { 17 | 18 | fun extractWatchDirectory(): Path { 19 | return input?.let { 20 | ExistingPathConverter().convert(it) 21 | } ?: Paths.get(".") 22 | } 23 | 24 | fun extractConfig(): Config? = 25 | config?.let { 26 | CliArgs().apply { this.config = this@Parameters.config }.loadConfiguration() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/PropertyCountProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import io.gitlab.arturbosch.detekt.core.processors.util.collectByType 5 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 6 | import org.jetbrains.kotlin.psi.KtFile 7 | import org.jetbrains.kotlin.psi.KtProperty 8 | 9 | class PropertyCountProcessor : AbstractProjectMetricProcessor() { 10 | 11 | override val visitor = PropertyCountVisitor() 12 | override val key = numberOfFieldsKey 13 | } 14 | 15 | val numberOfFieldsKey = Key("number of properties") 16 | 17 | class PropertyCountVisitor : DetektVisitor() { 18 | 19 | override fun visitKtFile(file: KtFile) { 20 | super.visitKtFile(file) 21 | file.putUserData(numberOfFieldsKey, file.collectByType().size) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /detekt-watcher/README.md: -------------------------------------------------------------------------------- 1 | ## detekt-watcher - continuous static analysis 2 | 3 | Provides three commands: 4 | - `project [path]` - sets the current project to analyze 5 | - `analyze [subPath]?` - plain detekt run, super fast after first use 6 | - `watch [start?|stop]` - watches path set by project command and runs detekt on each changed file 7 | 8 | To view builtin ksh commands write `help`. 9 | - `help [[commandId] [subCommandId]?]?` - get synopsis and option infos for specified commands 10 | 11 | #### Home folder - ~/.detekt 12 | 13 | ##### config.properties 14 | 15 | Configures the detekt watcher 16 | 17 | - set `detekt.watcher.config.paths` to one or many detekt config files separated by a comma or semicolon. 18 | 19 | Example configuration file: 20 | ``` 21 | detekt.watcher.config.paths=/home/artur/.detekt/default.yml 22 | detekt.watcher.change.notification=true 23 | detekt.watcher.change.timeout=5 24 | ``` 25 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/ExplicitGarbageCollectionCallSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.bugs 2 | 3 | import io.gitlab.arturbosch.detekt.api.Config 4 | import io.gitlab.arturbosch.detekt.test.lint 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.jetbrains.spek.api.dsl.given 7 | import org.jetbrains.spek.api.dsl.it 8 | import org.jetbrains.spek.subject.SubjectSpek 9 | 10 | class ExplicitGarbageCollectionCallSpec : SubjectSpek({ 11 | subject { ExplicitGarbageCollectionCall(Config.empty) } 12 | 13 | given("several garbage collector calls") { 14 | 15 | it("reports garbage collector calls") { 16 | val code = """ 17 | fun f() { 18 | System.gc() 19 | Runtime.getRuntime().gc() 20 | System.runFinalization() 21 | }""" 22 | assertThat(subject.lint(code)).hasSize(3) 23 | } 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/complexity/ComplexConditionSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.complexity 2 | 3 | import io.gitlab.arturbosch.detekt.test.lint 4 | import org.assertj.core.api.Assertions.assertThat 5 | import org.jetbrains.spek.api.Spek 6 | import org.jetbrains.spek.api.dsl.given 7 | import org.jetbrains.spek.api.dsl.it 8 | 9 | /** 10 | * @author Artur Bosch 11 | */ 12 | class ComplexConditionSpec : Spek({ 13 | 14 | given("some complex conditions") { 15 | 16 | val code = """ 17 | val a = if (5 > 4 && 4 < 6 || (3 < 5 || 2 < 5)) { 42 } else { 24 } 18 | 19 | fun complexConditions() { 20 | while (5 > 4 && 4 < 6 || (3 < 5 || 2 < 5)) {} 21 | do { } while (5 > 4 && 4 < 6 || (3 < 5 || 2 < 5)) 22 | } 23 | """ 24 | 25 | it("reports some complex conditions") { 26 | assertThat(ComplexCondition().lint(code)).hasSize(3) 27 | } 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/performance/UnnecessaryTemporaryInstantiationSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.performance 2 | 3 | import io.gitlab.arturbosch.detekt.test.lint 4 | import org.assertj.core.api.Assertions.assertThat 5 | import org.jetbrains.spek.api.dsl.describe 6 | import org.jetbrains.spek.subject.SubjectSpek 7 | 8 | class UnnecessaryTemporaryInstantiationSpec : SubjectSpek({ 9 | subject { UnnecessaryTemporaryInstantiation() } 10 | 11 | describe("temporary instantiation for conversion") { 12 | val code = "val i = Integer(1).toString()" 13 | subject.lint(code) 14 | assertThat(subject.findings.size).isEqualTo(1) 15 | } 16 | 17 | describe("right conversion without instantiation") { 18 | val code = "val i = Integer.toString(1)" 19 | subject.lint(code) 20 | assertThat(subject.findings.size).isZero() 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /detekt-rules/src/test/resources/cases/ComplexClass.kt: -------------------------------------------------------------------------------- 1 | package cases 2 | 3 | /** 4 | * @author Artur Bosch 5 | */ 6 | @Suppress("unused", "ConstantConditionIf") 7 | fun complex() { //20 8 | try {//5 9 | while (true) { 10 | if (true) { 11 | when ("string") { 12 | "" -> println() 13 | else -> println() 14 | } 15 | } 16 | } 17 | } catch (ex: Exception) { //1 + 5 18 | try { 19 | println() 20 | } catch (ex: Exception) { 21 | while (true) { 22 | if (false) { 23 | println() 24 | } else { 25 | println() 26 | } 27 | } 28 | } 29 | } finally { // 6 30 | try { 31 | println() 32 | } catch (ex: Exception) { 33 | while (true) { 34 | if (false) { 35 | println() 36 | } else { 37 | println() 38 | } 39 | } 40 | } 41 | } 42 | (1..10).forEach { 43 | //1 44 | println() 45 | } 46 | for (i in 1..10) { //1 47 | println() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-rule-or-changes-to-existing-rules.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New Rule or changes to existing rules 3 | about: Suggest new rules for detekt or suggest changes to existing rules 4 | 5 | --- 6 | 7 | The rule or changes you're looking for might have already been suggested! 8 | Please search in the [issues](https://github.com/arturbosch/detekt/issues) before creating a new one. 9 | 10 | ## Expected Behavior of the rule 11 | 12 | 13 | 14 | ## Context 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/processors/FunctionCountProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.api.DetektVisitor 4 | import io.gitlab.arturbosch.detekt.core.processors.util.collectByType 5 | import org.jetbrains.kotlin.com.intellij.openapi.util.Key 6 | import org.jetbrains.kotlin.psi.KtFile 7 | import org.jetbrains.kotlin.psi.KtNamedFunction 8 | 9 | class FunctionCountProcessor : AbstractProjectMetricProcessor() { 10 | 11 | override val visitor = FunctionCountVisitor() 12 | override val key = numberOfFunctionsKey 13 | } 14 | 15 | val numberOfFunctionsKey = Key("number of functions") 16 | 17 | class FunctionCountVisitor : DetektVisitor() { 18 | 19 | override fun visitKtFile(file: KtFile) { 20 | super.visitKtFile(file) 21 | file.putUserData(numberOfFunctionsKey, file.collectByType().size) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/processors/KtFileCountVisitorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.core.processors 2 | 3 | import io.gitlab.arturbosch.detekt.core.path 4 | import io.gitlab.arturbosch.detekt.test.compileForTest 5 | import org.assertj.core.api.Assertions 6 | import org.jetbrains.kotlin.psi.KtFile 7 | import org.jetbrains.spek.api.Spek 8 | import org.jetbrains.spek.api.dsl.it 9 | 10 | class KtFileCountVisitorTest : Spek({ 11 | 12 | it("twoFiles") { 13 | val files = arrayOf( 14 | compileForTest(path.resolve("Default.kt")), 15 | compileForTest(path.resolve("Test.kt")) 16 | ) 17 | val count = files 18 | .map { getData(it) } 19 | .sum() 20 | Assertions.assertThat(count).isEqualTo(2) 21 | } 22 | }) 23 | 24 | private fun getData(file: KtFile): Int { 25 | return with(file) { 26 | accept(KtFileCountVisitor()) 27 | getUserData(numberOfFilesKey)!! 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /detekt-rules/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/PackageNamingSpec.kt: -------------------------------------------------------------------------------- 1 | package io.gitlab.arturbosch.detekt.rules.naming 2 | 3 | import io.gitlab.arturbosch.detekt.test.lint 4 | import org.assertj.core.api.Assertions.assertThat 5 | import org.jetbrains.spek.api.dsl.it 6 | import org.jetbrains.spek.subject.SubjectSpek 7 | 8 | class PackageNamingSpec : SubjectSpek({ 9 | 10 | it("should find a uppercase package name") { 11 | assertThat(NamingRules().lint("package FOO.BAR")).hasSize(1) 12 | } 13 | 14 | it("should find a upper camel case package name") { 15 | assertThat(NamingRules().lint("package Foo.Bar")).hasSize(1) 16 | } 17 | 18 | it("should find a camel case package name") { 19 | assertThat(NamingRules().lint("package fOO.bAR")).hasSize(1) 20 | } 21 | 22 | it("should check an valid package name") { 23 | assertThat(NamingRules().lint("package foo.bar")).isEmpty() 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /docs/_data/alerts.yml: -------------------------------------------------------------------------------- 1 | tip: '