├── .circleci └── config.yml ├── .editorconfig ├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle.kts ├── buildScripts └── detekt │ └── detekt.yml ├── common ├── build.gradle.kts └── src │ └── main │ ├── kotlin │ └── org │ │ └── jetbrains │ │ └── research │ │ └── deepbugs │ │ └── common │ │ ├── CommonResourceBundle.kt │ │ ├── DeepBugsConfig.kt │ │ ├── DeepBugsConfigHandler.kt │ │ ├── DeepBugsPlugin.kt │ │ ├── datatypes │ │ ├── BinOp.kt │ │ ├── Call.kt │ │ └── DataType.kt │ │ ├── ide │ │ ├── error │ │ │ └── DeepBugsErrorReporter.kt │ │ ├── fus │ │ │ ├── DeepBugsEventLogger.kt │ │ │ ├── DeepBugsEventLoggerProvider.kt │ │ │ └── collectors │ │ │ │ └── counter │ │ │ │ └── DeepBugsCounterCollector.kt │ │ ├── inspections │ │ │ ├── DeepBugsInspectionManager.kt │ │ │ └── specific │ │ │ │ └── SpecificInspectionDescriptor.kt │ │ ├── msg │ │ │ ├── DeepBugsLifecycle.kt │ │ │ └── InspectionStateHandler.kt │ │ ├── problem │ │ │ └── BugDescriptor.kt │ │ ├── quickfixes │ │ │ ├── FlipFunctionArgumentsQuickFix.kt │ │ │ └── ReplaceBinOperatorQuickFix.kt │ │ └── ui │ │ │ ├── DeepBugsConfigurable.kt │ │ │ ├── DeepBugsSettingsPanel.kt │ │ │ └── UiUtils.kt │ │ ├── model │ │ ├── CommonModelStorage.kt │ │ ├── ModelHandler.kt │ │ ├── Vocabulary.kt │ │ └── common │ │ │ └── CommonModel.kt │ │ └── utils │ │ ├── Cbor.kt │ │ └── Mapping.kt │ └── resources │ └── DeepBugsCommonBundle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── js-plugin ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── jetbrains │ │ │ └── research │ │ │ └── deepbugs │ │ │ └── javascript │ │ │ ├── JSDeepBugsConfig.kt │ │ │ ├── JSResourceBundle.kt │ │ │ ├── datatypes │ │ │ └── JSDataTypeUtils.kt │ │ │ ├── extraction │ │ │ └── JSExtraction.kt │ │ │ ├── ide │ │ │ ├── inspections │ │ │ │ ├── base │ │ │ │ │ ├── JSDeepBugsBaseInspection.kt │ │ │ │ │ ├── JSDeepBugsBinExprInspection.kt │ │ │ │ │ └── JSDeepBugsCallExprInspection.kt │ │ │ │ ├── common │ │ │ │ │ ├── JSDeepBugsBinOperandInspection.kt │ │ │ │ │ ├── JSDeepBugsBinOperatorInspection.kt │ │ │ │ │ └── JSDeepBugsSwappedArgsInspection.kt │ │ │ │ └── specific │ │ │ │ │ └── math │ │ │ │ │ ├── JSDeepBugsIncorrectArgMathInspection.kt │ │ │ │ │ ├── JSDeepBugsMathCallExprInspection.kt │ │ │ │ │ └── JSDeepBugsSwappedArgsMathInspection.kt │ │ │ ├── quickfixes │ │ │ │ ├── JSFlipFunctionArgumentsQuickFix.kt │ │ │ │ ├── JSIgnoreExpressionQuickFix.kt │ │ │ │ └── utils │ │ │ │ │ └── JSOperatorMap.kt │ │ │ └── ui │ │ │ │ └── JSDeepBugsConfigurable.kt │ │ │ └── model │ │ │ └── specific │ │ │ ├── JSSpecificModel.kt │ │ │ └── MathModel.kt │ ├── models │ │ ├── common │ │ │ ├── binOperandDetectionModel.h5 │ │ │ ├── binOperatorDetectionModel.h5 │ │ │ └── swappedArgsDetectionModel.h5 │ │ ├── math │ │ │ ├── incorrectFuncArgDetectionModelMath.h5 │ │ │ └── swappedArgsDetectionModelMath.h5 │ │ ├── nodeTypeToVector.cbor │ │ ├── operatorToVector.cbor │ │ ├── tokenToVector.cbor │ │ └── typeToVector.cbor │ └── resources │ │ ├── DeepBugsJavaScriptBundle.properties │ │ ├── META-INF │ │ ├── plugin.xml │ │ └── pluginIcon.svg │ │ └── inspectionDescriptions │ │ ├── JSDeepBugsBinOperand.html │ │ ├── JSDeepBugsBinOperator.html │ │ ├── JSDeepBugsIncorrectArgMath.html │ │ ├── JSDeepBugsSwappedArgs.html │ │ └── JSDeepBugsSwappedArgsMath.html │ └── test │ ├── kotlin │ └── org │ │ └── jetbrains │ │ └── research │ │ └── deepbugs │ │ └── javascript │ │ ├── DeepBugsTestBase.kt │ │ └── JSDeepBugsTest.kt │ └── testData │ ├── testIncorrectArgumentMathJS.js │ ├── testIncorrectBinOperandJS.js │ ├── testIncorrectBinOperatorJS.js │ ├── testSwappedArgumentsJS.js │ └── testSwappedArgumentsMathJS.js ├── keras-runner ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── jetbrains │ └── research │ └── keras │ └── runner │ ├── deserializer │ ├── ModelLoader.kt │ ├── Utils.kt │ └── json │ │ ├── ActivationType.kt │ │ ├── LayerConfig.kt │ │ ├── LayerScheme.kt │ │ ├── ModelConfig.kt │ │ └── ModelScheme.kt │ └── nn │ ├── activation │ ├── ActivatableVector.kt │ └── ActivationFunction.kt │ ├── layer │ ├── ActivatableLayer.kt │ ├── Layer.kt │ └── dense │ │ ├── DenseLayer.kt │ │ └── DenseParameters.kt │ └── model │ ├── Model.kt │ └── sequential │ ├── Perceptron.kt │ └── SequentialModel.kt ├── py-plugin ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── jetbrains │ │ │ └── research │ │ │ └── deepbugs │ │ │ └── python │ │ │ ├── PyDeepBugsConfig.kt │ │ │ ├── PyResourceBundle.kt │ │ │ ├── datatypes │ │ │ └── PyDataTypeUtils.kt │ │ │ ├── extraction │ │ │ └── PyExtraction.kt │ │ │ └── ide │ │ │ ├── inspections │ │ │ ├── PyDeepBugsBinOperandInspection.kt │ │ │ ├── PyDeepBugsBinOperatorInspection.kt │ │ │ ├── PyDeepBugsSwappedArgsInspection.kt │ │ │ └── base │ │ │ │ ├── PyDeepBugsBaseInspection.kt │ │ │ │ ├── PyDeepBugsBinExprInspection.kt │ │ │ │ └── PyDeepBugsCallExprInspection.kt │ │ │ ├── quickfixes │ │ │ ├── PyFlipFunctionArgumentsQuickFix.kt │ │ │ └── PyIgnoreExpressionQuickFix.kt │ │ │ └── ui │ │ │ └── PyDeepBugsConfigurable.kt │ ├── models │ │ ├── common │ │ │ ├── binOperandDetectionModel.h5 │ │ │ ├── binOperatorDetectionModel.h5 │ │ │ └── swappedArgsDetectionModel.h5 │ │ ├── nodeTypeToVector.cbor │ │ ├── operatorToVector.cbor │ │ ├── tokenToVector.cbor │ │ └── typeToVector.cbor │ └── resources │ │ ├── DeepBugsPythonBundle.properties │ │ ├── META-INF │ │ ├── plugin.xml │ │ └── pluginIcon.svg │ │ └── inspectionDescriptions │ │ ├── PyDeepBugsBinOperand.html │ │ ├── PyDeepBugsBinOperator.html │ │ └── PyDeepBugsSwappedArgs.html │ └── test │ ├── kotlin │ └── org │ │ └── jetbrains │ │ └── research │ │ └── deepbugs │ │ └── python │ │ ├── DeepBugsTestBase.kt │ │ └── PyDeepBugsTest.kt │ └── testData │ ├── testIncorrectBinOperandPy.py │ ├── testIncorrectBinOperatorPy.py │ └── testSwappedArgumentsPy.py └── settings.gradle.kts /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/openjdk:8-jdk 6 | working_directory: ~ 7 | steps: 8 | - checkout 9 | - run: ./gradlew build 10 | 11 | release: 12 | docker: 13 | - image: circleci/openjdk:8-jdk 14 | working_directory: ~ 15 | steps: 16 | - checkout 17 | - run: ./gradlew publishPlugin 18 | workflows: 19 | version: 2 20 | build: 21 | jobs: 22 | - build: 23 | filters: 24 | branches: 25 | ignore: 26 | - /dev-.*/ 27 | - /stable-.*/ 28 | release: 29 | jobs: 30 | - build: 31 | filters: 32 | branches: 33 | only: 34 | - /dev-.*/ 35 | - /stable-.*/ 36 | - approve-release: 37 | type: approval 38 | requires: 39 | - build 40 | - release: 41 | requires: 42 | - approve-release 43 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | max_line_length = 160 5 | 6 | [*.kt] 7 | indent_style = space 8 | indent_size = 4 9 | ij_kotlin_name_count_to_use_star_import = 3 10 | ij_kotlin_name_count_to_use_star_import_for_members = 3 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | out 3 | build 4 | .gradle 5 | *.iml 6 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 JetBrains-Research 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

DeepBugs Icon DeepBugs for IntelliJ

2 | 3 | [![JB Research](https://jb.gg/badges/research-flat-square.svg)](https://research.jetbrains.org/) 4 | [![CircleCI](https://img.shields.io/circleci/build/github/JetBrains-Research/DeepBugsPlugin.svg?style=flat-square)](https://circleci.com/gh/JetBrains-Research/DeepBugsPlugin) 5 | [![Plugin Gitter](https://img.shields.io/static/v1?message=deepbugs&label=gitter&color=brightgreen&logo=gitter&style=flat-square)](https://gitter.im/deepbugs4intellij/community) 6 | [![JS Plugin](https://img.shields.io/jetbrains/plugin/v/12220-deepbugsjavascript.svg?style=flat-square&label=js%20plugin)](https://plugins.jetbrains.com/plugin/12220-deepbugsjavascript) 7 | [![JS Downloads](https://img.shields.io/jetbrains/plugin/d/12220-deepbugsjavascript.svg?style=flat-square&label=js%20downloads)](https://plugins.jetbrains.com/plugin/12220-deepbugsjavascript) 8 | [![Py Plugin](https://img.shields.io/jetbrains/plugin/v/12218-deepbugspython.svg?style=flat-square&label=py%20plugin)](https://plugins.jetbrains.com/plugin/12218-deepbugspython) 9 | [![Py Downloads](https://img.shields.io/jetbrains/plugin/d/12218-deepbugspython.svg?style=flat-square&label=py%20downloads)](https://plugins.jetbrains.com/plugin/12218-deepbugspython) 10 | 11 | 12 | __DeepBugs for IntelliJ__ is a pair of plugins for IntelliJ-based IDEs that provide semantics-aware bug detection in Python and JavaScript. The plugins use deep learning models inspired by the [DeepBugs framework](https://github.com/michaelpradel/DeepBugs) to extract the semantics of code and find bugs. 13 | 14 | The plugins are available for download: [Python](https://plugins.jetbrains.com/plugin/12218-deepbugspython/), [JavaScript](https://plugins.jetbrains.com/plugin/12220-deepbugsjavascript/). 15 | 16 |

17 | 18 |

19 | 20 | ## Getting started 21 | Code inspections in the plugins detect several types of bugs, including incorrect function arguments, incorrect comparison, and others, based on code semantics. 22 | 23 | If the plugin provides some warnings that you consider as false positives, you can disable check on any particular piece of code with a quick-fix. 24 | All the ignored expressions can be reset in __Preferences / Settings__ under __Tools | DeepBugs for Python/DeepBugs for JavaScript__. 25 | 26 | ## Supported code inspections 27 | ### Incorrect binary operator 28 | The inspection detects misuse of binary operators (such as `<`, `<=`, `+`, etc.). 29 | 30 | For example, it may detect the following bugs: 31 | - `i <= length` (index is less or equal to length, but should be less) 32 | - `text + binary` (concatenated non-compatible types) 33 | 34 | This inspection provides a quick-fix that allows replacing misused operator with more appropriate one. 35 | ### Incorrect binary operand 36 | The inspection detects misuse of binary operands (arguments of binary operations). 37 | 38 | For example: 39 | - `height - x` (in most cases it should be `height - y`) 40 | - `j < params` (should be `params.length`) 41 | 42 | ### Incorrect function arguments 43 | The inspection detects misuse of function arguments (specifically, their order). 44 | 45 | For example: 46 | - `startPoller(100, function(delay, fn) { … })` (should be fn, delay) 47 | - `2 % i` (unusual order of operands) 48 | 49 | This inspection provides a quick-fix allowing to fix the order of arguments. 50 | 51 | ## Got any more questions? 52 | If you want to know more about the DeepBugs framework that these plugins are based on, please [refer to this paper](http://software-lab.org/publications/oopsla2018_DeepBugs.pdf). 53 | 54 | If you have any questions about the plugins themselves, please don’t hesitate to contact us on [Gitter](https://gitter.im/deepbugs4intellij/community). 55 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.gitlab.arturbosch.detekt.Detekt 2 | import org.jetbrains.intellij.tasks.BuildSearchableOptionsTask 3 | import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile 4 | import tanvd.kosogor.defaults.configureIdea 5 | 6 | group = "org.jetbrains.research.deepbugs" 7 | version = "0.5" 8 | 9 | plugins { 10 | id("tanvd.kosogor") version "1.0.7" apply true 11 | id("io.gitlab.arturbosch.detekt") version ("1.6.0") apply false 12 | id("org.jetbrains.intellij") version "0.4.13" apply true 13 | kotlin("jvm") version "1.3.70" apply true 14 | id("org.jetbrains.kotlin.plugin.serialization") version "1.3.70" apply true 15 | } 16 | 17 | intellij { 18 | version = "2020.1" 19 | } 20 | 21 | allprojects { 22 | repositories { 23 | jcenter() 24 | maven("https://dl.bintray.com/mipt-npm/scientifik") 25 | } 26 | } 27 | 28 | subprojects { 29 | apply { 30 | plugin("kotlin") 31 | plugin("org.jetbrains.kotlin.plugin.serialization") 32 | plugin("org.jetbrains.intellij") 33 | plugin("tanvd.kosogor") 34 | plugin("io.gitlab.arturbosch.detekt") 35 | } 36 | 37 | tasks.withType().forEach { it.enabled = false } 38 | 39 | configureIdea { 40 | exclude += file("build") 41 | } 42 | 43 | intellij { 44 | sandboxDirectory = File(rootProject.projectDir, "build/${project.name}/idea-sandbox").canonicalPath 45 | } 46 | 47 | tasks.withType { 48 | parallel = true 49 | failFast = false 50 | config.setFrom(File(rootProject.projectDir, "buildScripts/detekt/detekt.yml")) 51 | reports { 52 | xml.enabled = false 53 | html.enabled = false 54 | } 55 | } 56 | 57 | dependencies { 58 | compileOnly(kotlin("stdlib")) 59 | compileOnly(kotlin("stdlib-jdk8")) 60 | implementation("org.jetbrains.kotlinx", "kotlinx-serialization-cbor", "0.20.0") { 61 | exclude("org.jetbrains.kotlin") 62 | } 63 | } 64 | 65 | tasks.withType { 66 | kotlinOptions { 67 | jvmTarget = "1.8" 68 | languageVersion = "1.3" 69 | apiVersion = "1.3" 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /buildScripts/detekt/detekt.yml: -------------------------------------------------------------------------------- 1 | build: 2 | maxIssues: 10 3 | excludeCorrectable: false 4 | weights: 5 | # complexity: 2 6 | # LongParameterList: 1 7 | # style: 1 8 | # comments: 1 9 | 10 | config: 11 | validation: true 12 | # when writing own rules with new properties, exclude the property path e.g.: "my_rule_set,.*>.*>[my_property]" 13 | excludes: "" 14 | 15 | processors: 16 | active: true 17 | exclude: 18 | - 'DetektProgressListener' 19 | # - 'FunctionCountProcessor' 20 | # - 'PropertyCountProcessor' 21 | # - 'ClassCountProcessor' 22 | # - 'PackageCountProcessor' 23 | # - 'KtFileCountProcessor' 24 | 25 | console-reports: 26 | active: true 27 | exclude: 28 | - 'ProjectStatisticsReport' 29 | - 'ComplexityReport' 30 | - 'NotificationReport' 31 | # - 'FindingsReport' 32 | - 'FileBasedFindingsReport' 33 | 34 | comments: 35 | active: true 36 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 37 | CommentOverPrivateFunction: 38 | active: false 39 | CommentOverPrivateProperty: 40 | active: false 41 | EndOfSentenceFormat: 42 | active: false 43 | endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!:]$) 44 | UndocumentedPublicClass: 45 | active: false 46 | searchInNestedClass: true 47 | searchInInnerClass: true 48 | searchInInnerObject: true 49 | searchInInnerInterface: true 50 | UndocumentedPublicFunction: 51 | active: false 52 | UndocumentedPublicProperty: 53 | active: false 54 | 55 | complexity: 56 | active: true 57 | ComplexCondition: 58 | active: true 59 | threshold: 4 60 | ComplexInterface: 61 | active: false 62 | threshold: 10 63 | includeStaticDeclarations: false 64 | ComplexMethod: 65 | active: true 66 | threshold: 15 67 | ignoreSingleWhenExpression: false 68 | ignoreSimpleWhenEntries: false 69 | ignoreNestingFunctions: false 70 | nestingFunctions: run,let,apply,with,also,use,forEach,isNotNull,ifNull 71 | LabeledExpression: 72 | active: false 73 | ignoredLabels: "" 74 | LargeClass: 75 | active: true 76 | threshold: 600 77 | LongMethod: 78 | active: true 79 | threshold: 60 80 | LongParameterList: 81 | active: true 82 | threshold: 6 83 | ignoreDefaultParameters: false 84 | MethodOverloading: 85 | active: false 86 | threshold: 6 87 | NestedBlockDepth: 88 | active: true 89 | threshold: 4 90 | StringLiteralDuplication: 91 | active: false 92 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 93 | threshold: 3 94 | ignoreAnnotation: true 95 | excludeStringsWithLessThan5Characters: true 96 | ignoreStringsRegex: '$^' 97 | TooManyFunctions: 98 | active: true 99 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 100 | thresholdInFiles: 11 101 | thresholdInClasses: 11 102 | thresholdInInterfaces: 11 103 | thresholdInObjects: 11 104 | thresholdInEnums: 11 105 | ignoreDeprecated: false 106 | ignorePrivate: false 107 | ignoreOverridden: false 108 | 109 | coroutines: 110 | active: true 111 | GlobalCoroutineUsage: 112 | active: false 113 | RedundantSuspendModifier: 114 | active: false 115 | 116 | empty-blocks: 117 | active: true 118 | EmptyCatchBlock: 119 | active: true 120 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)" 121 | EmptyClassBlock: 122 | active: true 123 | EmptyDefaultConstructor: 124 | active: true 125 | EmptyDoWhileBlock: 126 | active: true 127 | EmptyElseBlock: 128 | active: true 129 | EmptyFinallyBlock: 130 | active: true 131 | EmptyForBlock: 132 | active: true 133 | EmptyFunctionBlock: 134 | active: true 135 | ignoreOverridden: false 136 | EmptyIfBlock: 137 | active: true 138 | EmptyInitBlock: 139 | active: true 140 | EmptyKtFile: 141 | active: true 142 | EmptySecondaryConstructor: 143 | active: true 144 | EmptyTryBlock: 145 | active: true 146 | EmptyWhenBlock: 147 | active: true 148 | EmptyWhileBlock: 149 | active: true 150 | 151 | exceptions: 152 | active: true 153 | ExceptionRaisedInUnexpectedLocation: 154 | active: false 155 | methodNames: 'toString,hashCode,equals,finalize' 156 | InstanceOfCheckForException: 157 | active: false 158 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 159 | NotImplementedDeclaration: 160 | active: false 161 | PrintStackTrace: 162 | active: false 163 | RethrowCaughtException: 164 | active: false 165 | ReturnFromFinally: 166 | active: false 167 | ignoreLabeled: false 168 | SwallowedException: 169 | active: false 170 | ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException' 171 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)" 172 | ThrowingExceptionFromFinally: 173 | active: false 174 | ThrowingExceptionInMain: 175 | active: false 176 | ThrowingExceptionsWithoutMessageOrCause: 177 | active: false 178 | exceptions: 'IllegalArgumentException,IllegalStateException,IOException' 179 | ThrowingNewInstanceOfSameException: 180 | active: false 181 | TooGenericExceptionCaught: 182 | active: false 183 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 184 | exceptionNames: 185 | - ArrayIndexOutOfBoundsException 186 | - Error 187 | - Exception 188 | - IllegalMonitorStateException 189 | - NullPointerException 190 | - IndexOutOfBoundsException 191 | - RuntimeException 192 | - Throwable 193 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)" 194 | TooGenericExceptionThrown: 195 | active: true 196 | exceptionNames: 197 | - Error 198 | - Exception 199 | - Throwable 200 | - RuntimeException 201 | 202 | formatting: 203 | active: true 204 | android: false 205 | autoCorrect: true 206 | AnnotationOnSeparateLine: 207 | active: false 208 | autoCorrect: true 209 | ChainWrapping: 210 | active: true 211 | autoCorrect: true 212 | CommentSpacing: 213 | active: true 214 | autoCorrect: true 215 | EnumEntryNameCase: 216 | active: false 217 | autoCorrect: true 218 | Filename: 219 | active: true 220 | FinalNewline: 221 | active: true 222 | autoCorrect: true 223 | insertFinalNewLine: true 224 | ImportOrdering: 225 | active: false 226 | autoCorrect: true 227 | Indentation: 228 | active: false 229 | autoCorrect: true 230 | indentSize: 4 231 | continuationIndentSize: 4 232 | MaximumLineLength: 233 | active: true 234 | maxLineLength: 120 235 | ModifierOrdering: 236 | active: true 237 | autoCorrect: true 238 | MultiLineIfElse: 239 | active: true 240 | autoCorrect: true 241 | NoBlankLineBeforeRbrace: 242 | active: true 243 | autoCorrect: true 244 | NoConsecutiveBlankLines: 245 | active: true 246 | autoCorrect: true 247 | NoEmptyClassBody: 248 | active: true 249 | autoCorrect: true 250 | NoEmptyFirstLineInMethodBlock: 251 | active: false 252 | autoCorrect: true 253 | NoLineBreakAfterElse: 254 | active: true 255 | autoCorrect: true 256 | NoLineBreakBeforeAssignment: 257 | active: true 258 | autoCorrect: true 259 | NoMultipleSpaces: 260 | active: true 261 | autoCorrect: true 262 | NoSemicolons: 263 | active: true 264 | autoCorrect: true 265 | NoTrailingSpaces: 266 | active: true 267 | autoCorrect: true 268 | NoUnitReturn: 269 | active: true 270 | autoCorrect: true 271 | NoUnusedImports: 272 | active: true 273 | autoCorrect: true 274 | NoWildcardImports: 275 | active: true 276 | PackageName: 277 | active: true 278 | autoCorrect: true 279 | ParameterListWrapping: 280 | active: true 281 | autoCorrect: true 282 | indentSize: 4 283 | SpacingAroundColon: 284 | active: true 285 | autoCorrect: true 286 | SpacingAroundComma: 287 | active: true 288 | autoCorrect: true 289 | SpacingAroundCurly: 290 | active: true 291 | autoCorrect: true 292 | SpacingAroundDot: 293 | active: true 294 | autoCorrect: true 295 | SpacingAroundKeyword: 296 | active: true 297 | autoCorrect: true 298 | SpacingAroundOperators: 299 | active: true 300 | autoCorrect: true 301 | SpacingAroundParens: 302 | active: true 303 | autoCorrect: true 304 | SpacingAroundRangeOperator: 305 | active: true 306 | autoCorrect: true 307 | StringTemplate: 308 | active: true 309 | autoCorrect: true 310 | 311 | naming: 312 | active: true 313 | ClassNaming: 314 | active: true 315 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 316 | classPattern: '[A-Z$][a-zA-Z0-9$]*' 317 | ConstructorParameterNaming: 318 | active: false 319 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 320 | parameterPattern: '[a-z][A-Za-z0-9]*' 321 | privateParameterPattern: '[a-z][A-Za-z0-9]*' 322 | excludeClassPattern: '$^' 323 | ignoreOverridden: true 324 | EnumNaming: 325 | active: false 326 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 327 | enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*' 328 | ForbiddenClassName: 329 | active: false 330 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 331 | forbiddenName: '' 332 | FunctionMaxLength: 333 | active: false 334 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 335 | maximumFunctionNameLength: 30 336 | FunctionMinLength: 337 | active: false 338 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 339 | minimumFunctionNameLength: 3 340 | FunctionNaming: 341 | active: true 342 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 343 | functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' 344 | excludeClassPattern: '$^' 345 | ignoreOverridden: true 346 | FunctionParameterNaming: 347 | active: true 348 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 349 | parameterPattern: '[a-z][A-Za-z0-9]*' 350 | excludeClassPattern: '$^' 351 | ignoreOverridden: true 352 | InvalidPackageDeclaration: 353 | active: false 354 | rootPackage: '' 355 | MatchingDeclarationName: 356 | active: true 357 | mustBeFirst: true 358 | MemberNameEqualsClassName: 359 | active: false 360 | ignoreOverridden: true 361 | ObjectPropertyNaming: 362 | active: true 363 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 364 | constantPattern: '[A-Za-z][_A-Za-z0-9]*' 365 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 366 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' 367 | PackageNaming: 368 | active: true 369 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 370 | packagePattern: '^[a-z]+(\.[a-z][A-Za-z0-9]*)*$' 371 | TopLevelPropertyNaming: 372 | active: true 373 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 374 | constantPattern: '[A-Z][_A-Z0-9]*' 375 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 376 | privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' 377 | VariableMaxLength: 378 | active: false 379 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 380 | maximumVariableNameLength: 64 381 | VariableMinLength: 382 | active: false 383 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 384 | minimumVariableNameLength: 1 385 | VariableNaming: 386 | active: false 387 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 388 | variablePattern: '[a-z][A-Za-z0-9]*' 389 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' 390 | excludeClassPattern: '$^' 391 | ignoreOverridden: true 392 | 393 | performance: 394 | active: true 395 | ArrayPrimitive: 396 | active: true 397 | ForEachOnRange: 398 | active: true 399 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 400 | SpreadOperator: 401 | active: false 402 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 403 | UnnecessaryTemporaryInstantiation: 404 | active: true 405 | 406 | potential-bugs: 407 | active: true 408 | Deprecation: 409 | active: false 410 | DuplicateCaseInWhenExpression: 411 | active: true 412 | EqualsAlwaysReturnsTrueOrFalse: 413 | active: true 414 | EqualsWithHashCodeExist: 415 | active: true 416 | ExplicitGarbageCollectionCall: 417 | active: true 418 | HasPlatformType: 419 | active: false 420 | ImplicitDefaultLocale: 421 | active: false 422 | InvalidRange: 423 | active: true 424 | IteratorHasNextCallsNextMethod: 425 | active: true 426 | IteratorNotThrowingNoSuchElementException: 427 | active: true 428 | LateinitUsage: 429 | active: false 430 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 431 | excludeAnnotatedProperties: "" 432 | ignoreOnClassesPattern: "" 433 | MapGetWithNotNullAssertionOperator: 434 | active: false 435 | MissingWhenCase: 436 | active: true 437 | RedundantElseInWhen: 438 | active: true 439 | UnconditionalJumpStatementInLoop: 440 | active: false 441 | UnreachableCode: 442 | active: true 443 | UnsafeCallOnNullableType: 444 | active: true 445 | UnsafeCast: 446 | active: false 447 | UselessPostfixExpression: 448 | active: false 449 | WrongEqualsTypeParameter: 450 | active: true 451 | 452 | style: 453 | active: true 454 | CollapsibleIfStatements: 455 | active: false 456 | DataClassContainsFunctions: 457 | active: false 458 | conversionFunctionPrefix: 'to' 459 | DataClassShouldBeImmutable: 460 | active: false 461 | EqualsNullCall: 462 | active: true 463 | EqualsOnSignatureLine: 464 | active: false 465 | ExplicitCollectionElementAccessMethod: 466 | active: false 467 | ExplicitItLambdaParameter: 468 | active: false 469 | ExpressionBodySyntax: 470 | active: false 471 | includeLineWrapping: false 472 | ForbiddenComment: 473 | active: true 474 | values: 'TODO:,FIXME:,STOPSHIP:' 475 | allowedPatterns: "" 476 | ForbiddenImport: 477 | active: false 478 | imports: '' 479 | forbiddenPatterns: "" 480 | ForbiddenMethodCall: 481 | active: false 482 | methods: '' 483 | ForbiddenPublicDataClass: 484 | active: false 485 | ignorePackages: '*.internal,*.internal.*' 486 | ForbiddenVoid: 487 | active: false 488 | ignoreOverridden: false 489 | ignoreUsageInGenerics: false 490 | FunctionOnlyReturningConstant: 491 | active: true 492 | ignoreOverridableFunction: true 493 | excludedFunctions: 'describeContents' 494 | excludeAnnotatedFunction: "dagger.Provides" 495 | LibraryCodeMustSpecifyReturnType: 496 | active: true 497 | LoopWithTooManyJumpStatements: 498 | active: true 499 | maxJumpCount: 1 500 | MagicNumber: 501 | active: false 502 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 503 | ignoreNumbers: '-1,0,1,2' 504 | ignoreHashCodeFunction: true 505 | ignorePropertyDeclaration: false 506 | ignoreLocalVariableDeclaration: false 507 | ignoreConstantDeclaration: true 508 | ignoreCompanionObjectPropertyDeclaration: true 509 | ignoreAnnotation: false 510 | ignoreNamedArgument: true 511 | ignoreEnums: false 512 | ignoreRanges: false 513 | MandatoryBracesIfStatements: 514 | active: false 515 | MaxLineLength: 516 | active: false 517 | maxLineLength: 120 518 | excludePackageStatements: true 519 | excludeImportStatements: true 520 | excludeCommentStatements: false 521 | MayBeConst: 522 | active: true 523 | ModifierOrder: 524 | active: true 525 | NestedClassesVisibility: 526 | active: false 527 | NewLineAtEndOfFile: 528 | active: true 529 | NoTabs: 530 | active: false 531 | OptionalAbstractKeyword: 532 | active: true 533 | OptionalUnit: 534 | active: false 535 | OptionalWhenBraces: 536 | active: false 537 | PreferToOverPairSyntax: 538 | active: false 539 | ProtectedMemberInFinalClass: 540 | active: true 541 | RedundantExplicitType: 542 | active: false 543 | RedundantVisibilityModifierRule: 544 | active: false 545 | ReturnCount: 546 | active: false 547 | max: 2 548 | excludedFunctions: "equals" 549 | excludeLabeled: false 550 | excludeReturnFromLambda: true 551 | excludeGuardClauses: false 552 | SafeCast: 553 | active: true 554 | SerialVersionUIDInSerializableClass: 555 | active: false 556 | SpacingBetweenPackageAndImports: 557 | active: false 558 | ThrowsCount: 559 | active: true 560 | max: 2 561 | TrailingWhitespace: 562 | active: false 563 | UnderscoresInNumericLiterals: 564 | active: false 565 | acceptableDecimalLength: 5 566 | UnnecessaryAbstractClass: 567 | active: false 568 | excludeAnnotatedClasses: "dagger.Module" 569 | UnnecessaryAnnotationUseSiteTarget: 570 | active: false 571 | UnnecessaryApply: 572 | active: false 573 | UnnecessaryInheritance: 574 | active: true 575 | UnnecessaryLet: 576 | active: false 577 | UnnecessaryParentheses: 578 | active: false 579 | UntilInsteadOfRangeTo: 580 | active: false 581 | UnusedImports: 582 | active: false 583 | UnusedPrivateClass: 584 | active: true 585 | UnusedPrivateMember: 586 | active: false 587 | allowedNames: "(_|ignored|expected|serialVersionUID)" 588 | UseArrayLiteralsInAnnotations: 589 | active: false 590 | UseCheckOrError: 591 | active: false 592 | UseDataClass: 593 | active: false 594 | excludeAnnotatedClasses: "" 595 | allowVars: false 596 | UseIfInsteadOfWhen: 597 | active: false 598 | UseRequire: 599 | active: false 600 | UselessCallOnNotNull: 601 | active: true 602 | UtilityClassWithPublicConstructor: 603 | active: true 604 | VarCouldBeVal: 605 | active: false 606 | WildcardImport: 607 | active: false 608 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 609 | excludeImports: 'java.util.*,kotlinx.android.synthetic.*' 610 | -------------------------------------------------------------------------------- /common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = rootProject.group 2 | version = rootProject.version 3 | 4 | intellij { 5 | version = rootProject.intellij.version 6 | } 7 | 8 | dependencies { 9 | implementation(project(":keras-runner")) 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/CommonResourceBundle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common 2 | 3 | import com.intellij.AbstractBundle 4 | import org.jetbrains.annotations.PropertyKey 5 | import java.util.* 6 | 7 | object CommonResourceBundle { 8 | private const val BUNDLE_NAME = "DeepBugsCommonBundle" 9 | 10 | private val bundle by lazy { ResourceBundle.getBundle(BUNDLE_NAME) } 11 | 12 | fun message(@PropertyKey(resourceBundle = BUNDLE_NAME) key: String, vararg params: Any): String { 13 | return AbstractBundle.message(bundle!!, key, *params) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/DeepBugsConfig.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent 4 | import com.intellij.util.xmlb.annotations.Property 5 | import org.jetbrains.research.deepbugs.common.ide.msg.DeepBugsLifecycle 6 | 7 | abstract class DeepBugsConfig(private val default: State) : PersistentStateComponent { 8 | data class State( 9 | @Property val quickFixesThreshold: Float = 0.3f, 10 | @Property val userDisabledChecks: Set = emptySet() 11 | ) 12 | 13 | private var myState: State? = null 14 | 15 | override fun getState(): State { 16 | if (myState == null) { 17 | update(default) 18 | } 19 | return myState!! 20 | } 21 | 22 | override fun loadState(state: State) { 23 | update(state) 24 | } 25 | 26 | fun disableCheck(expr: String) { 27 | val newState = State( 28 | userDisabledChecks = state.userDisabledChecks + expr 29 | ) 30 | update(newState) 31 | } 32 | 33 | fun enableCheck(expr: String) { 34 | val newState = State( 35 | userDisabledChecks = state.userDisabledChecks - expr 36 | ) 37 | update(newState) 38 | } 39 | 40 | 41 | fun update(new: State) { 42 | if (myState == null) { 43 | myState = new 44 | 45 | DeepBugsLifecycle.publisher.init(state) 46 | } else { 47 | val prevState = myState!! 48 | myState = new 49 | 50 | DeepBugsLifecycle.publisher.update(prevState, state) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/DeepBugsConfigHandler.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common 2 | 3 | import org.jetbrains.research.deepbugs.common.datatypes.DataType 4 | 5 | abstract class DeepBugsConfigHandler { 6 | protected abstract val instance: DeepBugsConfig 7 | abstract val default: DeepBugsConfig.State 8 | 9 | fun get() = instance.state 10 | 11 | @Synchronized 12 | fun ignoreExpression(expr: DataType) = instance.disableCheck(expr.text) 13 | 14 | @Synchronized 15 | fun considerExpression(expr: DataType) = instance.enableCheck(expr.text) 16 | 17 | fun shouldIgnore(expr: DataType) = get().userDisabledChecks.contains(expr.text) 18 | 19 | fun isProblem(result: Float, threshold: Float, expr: DataType) = result > threshold && !shouldIgnore(expr) 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/DeepBugsPlugin.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common 2 | 3 | import com.intellij.ide.plugins.* 4 | import com.intellij.internal.statistic.utils.* 5 | import com.intellij.openapi.application.ApplicationManager 6 | import org.jetbrains.annotations.TestOnly 7 | import java.io.File 8 | 9 | object DeepBugsPlugin { 10 | private val classLoader: ClassLoader 11 | get() = this::class.java.classLoader 12 | 13 | private var myTestPluginId: String? = null 14 | 15 | private val descriptor: IdeaPluginDescriptor 16 | get() = PluginManagerCore.getLoadedPlugins().single { 17 | (ApplicationManager.getApplication().isUnitTestMode && it.pluginId.idString == myTestPluginId) || 18 | (ApplicationManager.getApplication().isUnitTestMode.not() && it.pluginClassLoader == classLoader) 19 | } 20 | 21 | val name: String 22 | get() = descriptor.name 23 | 24 | val installationFolder: File 25 | get() = descriptor.pluginPath.toFile() 26 | 27 | val info: PluginInfo? 28 | get() = try { 29 | getPluginInfoByDescriptor(descriptor) 30 | } catch (ex: Exception) { 31 | null 32 | } 33 | 34 | @TestOnly 35 | fun setTestPlugin(id: String) { 36 | myTestPluginId = id 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/datatypes/BinOp.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.datatypes 2 | 3 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 4 | 5 | class BinOp( 6 | private val left: String, 7 | private val right: String, 8 | private val op: String, 9 | private val leftType: String, 10 | private val rightType: String, 11 | private val parent: String, 12 | private val grandParent: String 13 | ) : DataType() { 14 | override val text: String = "$left $op $right" 15 | 16 | override fun vectorize(): FloatArray? { 17 | val vocab = CommonModelStorage.vocabulary 18 | 19 | return listOf( 20 | vocab.tokens[left] ?: return null, 21 | vocab.tokens[right] ?: return null, 22 | vocab.operators[op] ?: return null, 23 | vocab.types[leftType] ?: return null, 24 | vocab.types[rightType] ?: return null, 25 | vocab.nodeTypes[parent] ?: return null, 26 | vocab.nodeTypes[grandParent] ?: return null 27 | ).reduce(FloatArray::plus) 28 | } 29 | 30 | fun replaceOperator(newOp: String) = BinOp(left, right, newOp, leftType, rightType, parent, grandParent) 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/datatypes/Call.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.datatypes 2 | 3 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 4 | 5 | class Call( 6 | private val callee: String, 7 | private val arguments: List, 8 | private val base: String, 9 | private val argumentTypes: List, 10 | private val parameters: List 11 | ) : DataType() { 12 | override val text: String = "$base.$callee(${arguments.joinToString(",")})" 13 | 14 | override fun vectorize(): FloatArray? { 15 | val vocab = CommonModelStorage.vocabulary 16 | 17 | val nameVector = vocab.tokens[callee] ?: return null 18 | val argVectors = arguments.map { arg -> vocab.tokens[arg] ?: return null }.reduce(FloatArray::plus) 19 | val baseVector = vocab.tokens[base] ?: FloatArray(200) { 0.0f } 20 | val typeVectors = argumentTypes.map { argType -> vocab.types[argType] ?: return null }.reduce(FloatArray::plus) 21 | val paramVectors = parameters.map { param -> vocab.tokens[param] ?: FloatArray(200) { 0.0f } }.reduce(FloatArray::plus) 22 | 23 | return nameVector + argVectors + baseVector + typeVectors + paramVectors 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/datatypes/DataType.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.datatypes 2 | 3 | abstract class DataType { 4 | abstract val text: String 5 | abstract fun vectorize(): FloatArray? 6 | } 7 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/error/DeepBugsErrorReporter.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.error 2 | 3 | import com.intellij.diagnostic.ITNReporter 4 | 5 | class DeepBugsErrorReporter : ITNReporter() 6 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/fus/DeepBugsEventLogger.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.fus 2 | 3 | import com.intellij.internal.statistic.eventLog.* 4 | 5 | object DeepBugsEventLogger { 6 | private val loggerProvider: StatisticsEventLoggerProvider = getEventLogProvider("DBP") 7 | 8 | val version: Int = loggerProvider.version 9 | 10 | fun log(group: EventLogGroup, action: String) { 11 | return loggerProvider.logger.log(group, action, false) 12 | } 13 | 14 | fun log(group: EventLogGroup, action: String, data: FeatureUsageData) { 15 | return loggerProvider.logger.log(group, action, data.build(), false) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/fus/DeepBugsEventLoggerProvider.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.fus 2 | 3 | import com.intellij.internal.statistic.eventLog.StatisticsEventLoggerProvider 4 | import com.intellij.internal.statistic.utils.StatisticsUploadAssistant 5 | import com.intellij.openapi.application.ApplicationManager 6 | import com.intellij.openapi.util.registry.Registry 7 | 8 | class DeepBugsEventLoggerProvider : StatisticsEventLoggerProvider("DBP", 1) { 9 | override fun isRecordEnabled(): Boolean = 10 | !ApplicationManager.getApplication().isUnitTestMode && 11 | Registry.`is`("feature.usage.event.log.collect.and.upload") && 12 | StatisticsUploadAssistant.isCollectAllowed() 13 | 14 | override fun isSendEnabled(): Boolean = isRecordEnabled() && StatisticsUploadAssistant.isSendAllowed() 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/fus/collectors/counter/DeepBugsCounterCollector.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter 2 | 3 | import com.intellij.concurrency.JobScheduler 4 | import com.intellij.internal.statistic.eventLog.EventLogGroup 5 | import com.intellij.internal.statistic.eventLog.FeatureUsageData 6 | import com.intellij.openapi.project.Project 7 | import org.jetbrains.research.deepbugs.common.DeepBugsPlugin 8 | import org.jetbrains.research.deepbugs.common.ide.fus.DeepBugsEventLogger 9 | import org.slf4j.LoggerFactory 10 | import java.util.concurrent.TimeUnit 11 | 12 | object DeepBugsCounterCollector { 13 | private const val LOG_DELAY_MIN = 24 * 60 14 | private const val LOG_INITIAL_DELAY_MIN = 10 15 | private val LOG = LoggerFactory.getLogger(DeepBugsCounterCollector::class.java) 16 | 17 | private val eventGroup = EventLogGroup("dbp.count", DeepBugsEventLogger.version) 18 | 19 | init { 20 | JobScheduler.getScheduler().scheduleWithFixedDelay( 21 | { trackRegistered() }, 22 | LOG_INITIAL_DELAY_MIN.toLong(), 23 | LOG_DELAY_MIN.toLong(), 24 | TimeUnit.MINUTES 25 | ) 26 | } 27 | 28 | fun problemFound(project: Project, inspection: String, result: Float) = log("report") { 29 | addProject(project) 30 | addData("inspection", inspection) 31 | addData("result", result) 32 | } 33 | 34 | fun tokensMatched(project: Project, inspection: String, matched: Boolean) = log("tokens.matched") { 35 | addProject(project) 36 | addData("inspection", inspection) 37 | addData("matched", matched) 38 | } 39 | 40 | fun quickFixApplied(project: Project, quickFixId: String, cancelled: Boolean) = log("quickfix.applied") { 41 | addProject(project) 42 | addData("quickfix", quickFixId) 43 | addData("cancelled", cancelled) 44 | } 45 | 46 | fun checkDisabled(project: Project, total: Int) = log("check.disabled") { 47 | addProject(project) 48 | addData("total", total) 49 | } 50 | 51 | fun modelReset(total: Int) = log("model.reset") { 52 | addData("total", total) 53 | } 54 | 55 | private fun log(eventId: String, body: FeatureUsageData.() -> Unit) { 56 | return try { 57 | val data = FeatureUsageData() 58 | .addPluginInfo(DeepBugsPlugin.info ?: return) 59 | .apply(body) 60 | DeepBugsEventLogger.log(eventGroup, eventId, data) 61 | } catch (ex: Exception) { 62 | LOG.warn("Failed to get PluginInfo for ${DeepBugsPlugin.name}") 63 | } 64 | } 65 | 66 | private fun trackRegistered() = DeepBugsEventLogger.log(eventGroup, "registered") 67 | } 68 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/inspections/DeepBugsInspectionManager.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.inspections 2 | 3 | import com.intellij.psi.PsiElement 4 | import org.jetbrains.research.deepbugs.common.ide.inspections.specific.SpecificInspectionDescriptor 5 | import java.util.concurrent.ConcurrentHashMap 6 | 7 | object DeepBugsInspectionManager { 8 | private val specificDescriptors = ConcurrentHashMap.newKeySet() 9 | 10 | fun register(descriptor: SpecificInspectionDescriptor) = specificDescriptors.add(descriptor) 11 | 12 | fun isSpecific(element: PsiElement) = specificDescriptors.any { it.shouldProcess(element) } 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/inspections/specific/SpecificInspectionDescriptor.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.inspections.specific 2 | 3 | import com.intellij.psi.PsiElement 4 | 5 | data class SpecificInspectionDescriptor( 6 | val shouldProcess: (PsiElement) -> Boolean 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/msg/DeepBugsLifecycle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.msg 2 | 3 | import com.intellij.application.subscribe 4 | import com.intellij.openapi.application.ApplicationManager 5 | import com.intellij.util.messages.Topic 6 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 7 | import org.jetbrains.research.deepbugs.common.ide.ui.DeepBugsSettingsPanel 8 | 9 | interface DeepBugsLifecycle { 10 | companion object { 11 | private val topic = Topic.create("deepbugs_lifecycle", DeepBugsLifecycle::class.java) 12 | val publisher by lazy { ApplicationManager.getApplication().messageBus.syncPublisher(topic) } 13 | 14 | init { 15 | topic.subscribe(ApplicationManager.getApplication(), InspectionStateHandler) 16 | topic.subscribe(ApplicationManager.getApplication(), DeepBugsSettingsPanel) 17 | } 18 | } 19 | 20 | fun init(init: DeepBugsConfig.State) 21 | 22 | fun update(previous: DeepBugsConfig.State, new: DeepBugsConfig.State) 23 | } 24 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/msg/InspectionStateHandler.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.msg 2 | 3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer 4 | import com.intellij.openapi.project.ProjectManager 5 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 6 | 7 | object InspectionStateHandler : DeepBugsLifecycle { 8 | override fun init(init: DeepBugsConfig.State) { 9 | ProjectManager.getInstance().openProjects.forEach { 10 | DaemonCodeAnalyzer.getInstance(it).restart() 11 | } 12 | } 13 | 14 | override fun update(previous: DeepBugsConfig.State, new: DeepBugsConfig.State) { 15 | if (previous == new) return 16 | init(new) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/problem/BugDescriptor.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.problem 2 | 3 | import com.intellij.codeInspection.LocalQuickFix 4 | import com.intellij.codeInspection.ProblemDescriptorBase 5 | import com.intellij.codeInspection.ProblemHighlightType 6 | import com.intellij.psi.PsiElement 7 | import com.intellij.util.containers.toArray 8 | 9 | class BugDescriptor(element: PsiElement, description: String, onTheFly: Boolean, fixes: List = emptyList()) : ProblemDescriptorBase( 10 | element, 11 | element, 12 | description, 13 | fixes.toArray(LocalQuickFix.EMPTY_ARRAY), 14 | ProblemHighlightType.GENERIC_ERROR, 15 | false, 16 | null, 17 | true, 18 | onTheFly 19 | ) 20 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/quickfixes/FlipFunctionArgumentsQuickFix.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.quickfixes 2 | 3 | import com.intellij.codeInsight.intention.PriorityAction 4 | import com.intellij.codeInspection.LocalQuickFix 5 | import com.intellij.codeInspection.ProblemDescriptor 6 | import com.intellij.openapi.project.Project 7 | import com.intellij.psi.PsiElement 8 | import org.jetbrains.research.deepbugs.common.CommonResourceBundle 9 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 10 | 11 | abstract class FlipFunctionArgumentsQuickFix : LocalQuickFix, PriorityAction { 12 | override fun getName(): String = CommonResourceBundle.message("deepbugs.flip.arguments.quickfix") 13 | 14 | override fun getPriority(): PriorityAction.Priority = PriorityAction.Priority.HIGH 15 | 16 | protected abstract fun T.toArguments(): Pair 17 | 18 | @Suppress("UNCHECKED_CAST") 19 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) { 20 | val element = descriptor.psiElement as? T ?: return 21 | 22 | val (arg0, arg1) = element.toArguments() 23 | 24 | arg0.replace(arg1) 25 | arg1.replace(arg0) 26 | 27 | DeepBugsCounterCollector.quickFixApplied(project, "flip.arguments", cancelled = false) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/quickfixes/ReplaceBinOperatorQuickFix.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.quickfixes 2 | 3 | import com.intellij.codeInsight.intention.PriorityAction 4 | import com.intellij.codeInsight.lookup.* 5 | import com.intellij.codeInsight.lookup.impl.LookupImpl 6 | import com.intellij.codeInspection.LocalQuickFix 7 | import com.intellij.codeInspection.ProblemDescriptor 8 | import com.intellij.ide.DataManager 9 | import com.intellij.openapi.actionSystem.CommonDataKeys 10 | import com.intellij.openapi.editor.Editor 11 | import com.intellij.openapi.project.Project 12 | import com.intellij.openapi.util.TextRange 13 | import org.jetbrains.research.deepbugs.common.CommonResourceBundle 14 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 15 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 16 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 17 | import kotlin.math.min 18 | 19 | class ReplaceBinOperatorQuickFix( 20 | private val data: BinOp, 21 | private val operatorRange: TextRange, 22 | private val threshold: Float, 23 | private val displayName: String, 24 | private val transform: (String) -> String = { it } 25 | ) : LocalQuickFix, PriorityAction { 26 | override fun getName(): String = if (lookups.size == 1) { 27 | CommonResourceBundle.message("deepbugs.replace.operator.single.quickfix", lookups.single().lookupString) 28 | } else { 29 | CommonResourceBundle.message("deepbugs.replace.operator.multiple.quickfix") 30 | } 31 | 32 | override fun getFamilyName(): String = displayName 33 | 34 | override fun getPriority(): PriorityAction.Priority = PriorityAction.Priority.HIGH 35 | 36 | override fun startInWriteAction(): Boolean = true 37 | 38 | fun isAvailable() = lookups.isNotEmpty() 39 | 40 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) { 41 | DataManager.getInstance().dataContextFromFocusAsync.onSuccess { context -> 42 | val editor: Editor = CommonDataKeys.EDITOR.getData(context) ?: return@onSuccess 43 | 44 | val endOff = min(operatorRange.endOffset, editor.document.textLength) 45 | editor.selectionModel.setSelection(operatorRange.startOffset, endOff) 46 | 47 | val lookup = LookupManager.getInstance(project) 48 | .createLookup(editor, lookups.toTypedArray(),"", LookupArranger.DefaultArranger()) 49 | .setSelectionRemoval() 50 | .registerCollector() as LookupImpl 51 | 52 | lookup.items.singleOrNull()?.let { 53 | editor.document.replaceString(operatorRange.startOffset, endOff, it.lookupString) 54 | lookup.fireItemSelected(it, 0.toChar()) 55 | } ?: lookup.showLookup() 56 | } 57 | } 58 | 59 | private val lookups: List by lazy { 60 | CommonModelStorage.vocabulary.operators.data.map { 61 | val newBinOp = data.replaceOperator(it.key).vectorize() 62 | val res = newBinOp?.let { op -> CommonModelStorage.common.binOperatorModel.predict(op) } 63 | it.key to res 64 | }.filter { it.second != null && it.second!! < threshold } 65 | .sortedBy { it.second }.take(5) 66 | .map { LookupElementBuilder.create(transform(it.first)) } 67 | } 68 | 69 | companion object { 70 | fun ReplaceBinOperatorQuickFix?.toLookups() = if (this == null) emptyArray() else lookups.map { it.lookupString }.toTypedArray() 71 | 72 | private fun Lookup.registerCollector(): Lookup { 73 | addLookupListener( 74 | object : LookupListener { 75 | override fun itemSelected(event: LookupEvent) = DeepBugsCounterCollector.quickFixApplied(project, "replace.operator", cancelled = false) 76 | override fun lookupCanceled(event: LookupEvent) = DeepBugsCounterCollector.quickFixApplied(project, "replace.operator", cancelled = true) 77 | } 78 | ) 79 | return this 80 | } 81 | 82 | private fun Lookup.setSelectionRemoval(): Lookup { 83 | addLookupListener ( 84 | object : LookupListener { 85 | override fun itemSelected(event: LookupEvent) = editor.selectionModel.removeSelection(false) 86 | } 87 | ) 88 | return this 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/ui/DeepBugsConfigurable.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.ui 2 | 3 | import com.intellij.openapi.options.ConfigurableBase 4 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 5 | 6 | abstract class DeepBugsConfigurable( 7 | private val default: DeepBugsConfig.State, 8 | id: String, 9 | display: String 10 | ) : ConfigurableBase(id, display, null) { 11 | override fun createUi(): DeepBugsSettingsPanel = DeepBugsSettingsPanel(settings, default) 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/ui/DeepBugsSettingsPanel.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.ui 2 | 3 | import com.intellij.openapi.options.ConfigurableUi 4 | import com.intellij.ui.layout.migLayout.createLayoutConstraints 5 | import net.miginfocom.layout.AC 6 | import net.miginfocom.layout.CC 7 | import net.miginfocom.swing.MigLayout 8 | import org.jetbrains.research.deepbugs.common.* 9 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 10 | import org.jetbrains.research.deepbugs.common.ide.msg.DeepBugsLifecycle 11 | import javax.swing.JButton 12 | 13 | class DeepBugsSettingsPanel(private val settings: DeepBugsConfig, private val default: DeepBugsConfig.State) : ConfigurableUi { 14 | companion object : DeepBugsLifecycle { 15 | private val resetButton = JButton(CommonResourceBundle.message("reset.button.text")) 16 | 17 | override fun init(init: DeepBugsConfig.State) { 18 | resetButton.isEnabled = init.userDisabledChecks.isNotEmpty() 19 | } 20 | 21 | override fun update(previous: DeepBugsConfig.State, new: DeepBugsConfig.State) { 22 | if (previous.userDisabledChecks == new.userDisabledChecks) return 23 | 24 | init(new) 25 | } 26 | } 27 | 28 | init { 29 | resetButton.addActionListener { 30 | DeepBugsCounterCollector.modelReset(settings.state.userDisabledChecks.size) 31 | settings.update(default) 32 | } 33 | } 34 | 35 | 36 | override fun getComponent() = panel(MigLayout(createLayoutConstraints(), AC().grow(), AC().index(1).grow())) { 37 | panel(MigLayout(createLayoutConstraints(), AC().grow()), constraint = CC().growX().wrap()) { 38 | add(wrapWithComment(resetButton, CommonResourceBundle.message("reset.button.comment")), 39 | CC().growX().width("100%").height("10%").alignY("top")) 40 | } 41 | } 42 | 43 | override fun apply(settings: DeepBugsConfig) = Unit 44 | override fun isModified(settings: DeepBugsConfig): Boolean = false 45 | override fun reset(settings: DeepBugsConfig) = Unit 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/ide/ui/UiUtils.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.ide.ui 2 | 3 | import com.intellij.openapi.ui.panel.ComponentPanelBuilder 4 | import java.awt.* 5 | import javax.swing.JComponent 6 | import javax.swing.JPanel 7 | 8 | fun panel(layout: LayoutManager = BorderLayout(0, 0), body: JPanel.() -> Unit) = JPanel(layout).apply(body) 9 | 10 | fun Container.panel( 11 | layout: LayoutManager = BorderLayout(0, 0), constraint: Any, 12 | body: JPanel.() -> Unit 13 | ): JPanel = JPanel(layout).apply(body).also { add(it, constraint) } 14 | 15 | fun wrapWithComment(component: JComponent, comment: String) = ComponentPanelBuilder(component) 16 | .withComment(comment) 17 | .moveCommentRight() 18 | .resizeY(true) 19 | .createPanel() 20 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/model/CommonModelStorage.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.model 2 | 3 | import org.jetbrains.research.deepbugs.common.model.common.CommonModel 4 | 5 | object CommonModelStorage { 6 | val common: CommonModel by lazy { CommonModel() } 7 | val vocabulary: Vocabulary by lazy { Vocabulary() } 8 | } 9 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/model/ModelHandler.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.model 2 | 3 | import org.jetbrains.research.deepbugs.common.DeepBugsPlugin 4 | import org.jetbrains.research.deepbugs.common.utils.Cbor 5 | import org.jetbrains.research.deepbugs.common.utils.Mapping 6 | import org.jetbrains.research.keras.runner.deserializer.ModelLoader 7 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 8 | import java.io.File 9 | 10 | object ModelHandler { 11 | private val modelsRoot by lazy { File(DeepBugsPlugin.installationFolder, "models") } 12 | 13 | private fun getModule(module: String): File = File(modelsRoot, module) 14 | 15 | fun loadMapping(name: String): Mapping = Cbor.parse(File(modelsRoot, name).readBytes(), Mapping.serializer()) 16 | 17 | fun loadModel(name: String, module: String): Perceptron? = try { 18 | ModelLoader.loadPerceptronModel(File(getModule(module), name)) 19 | } catch (ex: Exception) { 20 | null 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/model/Vocabulary.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.model 2 | 3 | import org.jetbrains.research.deepbugs.common.utils.Mapping 4 | 5 | data class Vocabulary( 6 | val tokens: Mapping = ModelHandler.loadMapping("tokenToVector.cbor"), 7 | val operators: Mapping = ModelHandler.loadMapping("operatorToVector.cbor"), 8 | val types: Mapping = ModelHandler.loadMapping("typeToVector.cbor"), 9 | val nodeTypes: Mapping = ModelHandler.loadMapping("nodeTypeToVector.cbor") 10 | ) 11 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/model/common/CommonModel.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.model.common 2 | 3 | import org.jetbrains.research.deepbugs.common.model.ModelHandler 4 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 5 | 6 | data class CommonModel( 7 | val binOperandModel: Perceptron = loadModel("binOperandDetectionModel.h5"), 8 | val binOperatorModel: Perceptron = loadModel("binOperatorDetectionModel.h5"), 9 | val swappedArgsModel: Perceptron = loadModel("swappedArgsDetectionModel.h5") 10 | ) { 11 | companion object { 12 | fun loadModel(model: String): Perceptron = ModelHandler.loadModel(model, "common")!! 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/utils/Cbor.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.utils 2 | 3 | import kotlinx.serialization.KSerializer 4 | import kotlinx.serialization.cbor.Cbor 5 | 6 | object Cbor { 7 | val cbor = Cbor() 8 | 9 | @Suppress("unused") 10 | inline fun bytes(value: T, serializer: KSerializer) = cbor.dump(serializer, value) 11 | 12 | inline fun parse(value: ByteArray, serializer: KSerializer) = cbor.load(serializer, value) 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/kotlin/org/jetbrains/research/deepbugs/common/utils/Mapping.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.common.utils 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Mapping(val data: Map) { 7 | operator fun get(fieldName: String): FloatArray? = data[fieldName] 8 | } 9 | -------------------------------------------------------------------------------- /common/src/main/resources/DeepBugsCommonBundle.properties: -------------------------------------------------------------------------------- 1 | platform.exception.message={0} is not supported on the current platform. 2 | reset.button.text=Reset to Default 3 | reset.button.comment=Enable all previously ignored bug detection rules 4 | deepbugs.replace.operator.multiple.quickfix=Replace operator with more appropriate 5 | deepbugs.replace.operator.single.quickfix=Change operator to “{0}” 6 | deepbugs.flip.arguments.quickfix=Fix order of arguments 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /js-plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.intellij.tasks.* 2 | import tanvd.kosogor.defaults.configureIdea 3 | 4 | group = rootProject.group 5 | version = rootProject.version 6 | 7 | intellij { 8 | pluginName = "DeepBugs for JavaScript" 9 | version = rootProject.intellij.version 10 | type = "IU" 11 | downloadSources = true 12 | setPlugins("JavaScriptLanguage", "CSS", "platform-images") 13 | } 14 | 15 | configureIdea { 16 | exclude += file("src/test/testData") 17 | } 18 | 19 | tasks.withType { 20 | from("${projectDir}/src/main/models") { 21 | into("${pluginName}/models") 22 | } 23 | } 24 | 25 | tasks.withType { 26 | jvmArgs("-Xmx1g", "-Didea.is.internal=true") 27 | } 28 | 29 | tasks.withType { 30 | useJUnit() 31 | 32 | jvmArgs("-Xmx1g", "-Didea.is.internal=true") 33 | testLogging { 34 | events("passed", "skipped", "failed") 35 | } 36 | } 37 | 38 | tasks.withType { 39 | sinceBuild("201") 40 | untilBuild("") 41 | } 42 | 43 | dependencies { 44 | implementation(project(":common")) 45 | implementation(project(":keras-runner")) 46 | } 47 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/JSDeepBugsConfig.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript 2 | 3 | import com.intellij.openapi.components.* 4 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 5 | import org.jetbrains.research.deepbugs.common.DeepBugsConfigHandler 6 | 7 | @State(name = "DeepBugsJS", storages = [Storage("deepbugs.js.xml")]) 8 | class JSDeepBugsConfig : PersistentStateComponent, DeepBugsConfig(default) { 9 | companion object : DeepBugsConfigHandler() { 10 | override val instance: JSDeepBugsConfig by lazy { service() } 11 | override val default = State() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/JSResourceBundle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript 2 | 3 | import com.intellij.AbstractBundle 4 | import org.jetbrains.annotations.PropertyKey 5 | import java.util.* 6 | 7 | object JSResourceBundle { 8 | private const val BUNDLE_NAME = "DeepBugsJavaScriptBundle" 9 | 10 | private val bundle by lazy { ResourceBundle.getBundle(BUNDLE_NAME) } 11 | 12 | fun message(@PropertyKey(resourceBundle = BUNDLE_NAME) key: String, vararg params: Any): String { 13 | return AbstractBundle.message(bundle!!, key, *params) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/datatypes/JSDataTypeUtils.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.datatypes 2 | 3 | import com.intellij.lang.javascript.psi.* 4 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 5 | import org.jetbrains.research.deepbugs.common.datatypes.Call 6 | import org.jetbrains.research.deepbugs.javascript.extraction.* 7 | 8 | fun JSBinaryExpression.collect(): BinOp? { 9 | val leftName = lOperand?.extractNodeName() ?: return null 10 | val rightName = rOperand?.extractNodeName() ?: return null 11 | val op = operationSign?.toString() ?: return null 12 | val leftType = lOperand?.extractNodeType() ?: return null 13 | val rightType = rOperand?.extractNodeType() ?: return null 14 | val parentNode = parent.javaClass.simpleName ?: "" 15 | val grandParentNode = parent.parent.javaClass.simpleName ?: "" 16 | return BinOp(leftName, rightName, op, leftType, rightType, parentNode, grandParentNode) 17 | } 18 | 19 | fun JSCallExpression.collect(): Call? { 20 | val callee = methodExpression as? JSReferenceExpression ?: return null 21 | val name = callee.extractNodeName() ?: return null 22 | 23 | val args = ArrayList() 24 | val argTypes = ArrayList() 25 | for (arg in arguments) { 26 | args.add(arg.extractNodeName() ?: return null) 27 | argTypes.add(arg.extractNodeType()) 28 | } 29 | 30 | val base = extractNodeBase() 31 | 32 | val resolved = try { 33 | callee.multiResolve(false).asSequence().mapNotNull { it.element as? JSFunction }.firstOrNull() 34 | } catch (ex: Exception) { 35 | null 36 | } 37 | 38 | val params = resolved?.parameters?.toList() 39 | val paramNames = MutableList(args.size) { "" } 40 | paramNames.forEachIndexed { idx, _ -> 41 | paramNames[idx] = params?.getOrNull(idx)?.extractNodeName() ?: "" 42 | } 43 | return Call(name, args, base, argTypes, paramNames) 44 | } 45 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/extraction/JSExtraction.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.extraction 2 | 3 | import com.intellij.lang.javascript.JSTokenTypes 4 | import com.intellij.lang.javascript.psi.* 5 | import com.intellij.psi.util.PsiTreeUtil 6 | 7 | fun String.asLiteralString() = "LIT:$this" 8 | 9 | fun String.asIdentifierString() = "ID:$this" 10 | 11 | @Suppress("ComplexMethod") 12 | fun JSElement.extractNodeName(): String? = when (this) { 13 | is JSLiteralExpression -> text.asLiteralString() 14 | is JSThisExpression -> text.asLiteralString() 15 | is JSReferenceExpression -> referenceName?.asIdentifierString() 16 | is JSPrefixExpression -> { 17 | val operand = expression as? JSLiteralExpression 18 | if (operand != null && operand.isNumericLiteral && operationSign == JSTokenTypes.MINUS) 19 | text.asLiteralString() 20 | else expression?.extractNodeName() 21 | } 22 | is JSCallExpression -> methodExpression?.extractNodeName() 23 | is JSParameter -> text.takeWhile { it != ':' }.asIdentifierString() 24 | is JSArrayLiteralExpression -> text.asIdentifierString() 25 | is JSIndexedPropertyAccessExpression -> 26 | PsiTreeUtil.getChildOfType(this, JSReferenceExpression::class.java)?.referenceName?.asIdentifierString() 27 | else -> null 28 | } 29 | 30 | @Suppress("ComplexMethod") 31 | fun JSElement.extractNodeType(): String = when (this) { 32 | is JSThisExpression -> "object" 33 | is JSLiteralExpression -> { 34 | when { 35 | value == null -> "null" 36 | isNumericLiteral -> "number" 37 | isStringLiteral -> "string" 38 | isRegExpLiteral -> "regex" 39 | isBooleanLiteral -> "boolean" 40 | else -> "unknown" 41 | } 42 | } 43 | is JSReferenceExpression -> 44 | if (node.elementType.toString() == JSTokenTypes.UNDEFINED_KEYWORD.toString()) "undefined" else "unknown" 45 | is JSPrefixExpression -> expression?.extractNodeType() ?: "unknown" 46 | else -> "unknown" 47 | } 48 | 49 | fun JSElement.extractNodeBase(): String = when (this) { 50 | is JSCallExpression -> (methodExpression as? JSReferenceExpression)?.extractNodeBase() ?: "" 51 | is JSReferenceExpression -> qualifier?.extractNodeName() ?: "" 52 | else -> "" 53 | } 54 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/base/JSDeepBugsBaseInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.base 2 | 3 | import com.intellij.codeInspection.ProblemDescriptor 4 | import com.intellij.codeInspection.ProblemsHolder 5 | import com.intellij.lang.javascript.inspections.JSInspection 6 | import com.intellij.lang.javascript.psi.JSElement 7 | import com.intellij.lang.javascript.psi.JSElementVisitor 8 | import org.jetbrains.research.deepbugs.common.datatypes.DataType 9 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 10 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 11 | import org.jetbrains.research.deepbugs.javascript.JSDeepBugsConfig 12 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.JSIgnoreExpressionQuickFix 13 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 14 | 15 | abstract class JSDeepBugsBaseInspection(private val threshold: Float) : JSInspection() { 16 | protected abstract val model: Perceptron? 17 | 18 | protected open fun skip(node: T): Boolean = false 19 | 20 | protected open fun createProblemDescriptor(node: T, data: V): ProblemDescriptor = 21 | BugDescriptor(node, createTooltip(node), myOnTheFly, listOf(JSIgnoreExpressionQuickFix(data, node.text))) 22 | 23 | protected abstract fun createTooltip(node: T, vararg params: String): String 24 | 25 | abstract inner class JSDeepBugsVisitor(private val holder: ProblemsHolder) : JSElementVisitor() { 26 | protected fun visit(node: T, collect: T.() -> V?) { 27 | if (skip(node)) return 28 | val data = node.collect() ?: return 29 | val vectorized = data.vectorize() 30 | DeepBugsCounterCollector.tokensMatched(holder.project, shortName, matched = vectorized == null) 31 | val result = model?.predict(vectorized ?: return) ?: return 32 | analyzeInspected(result, node, data) 33 | } 34 | 35 | private fun analyzeInspected(result: Float, node: T, data: V) { 36 | if (!JSDeepBugsConfig.isProblem(result, threshold, data)) return 37 | holder.registerProblem(createProblemDescriptor(node, data)) 38 | DeepBugsCounterCollector.problemFound(holder.project, shortName, result) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/base/JSDeepBugsBinExprInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.base 2 | 3 | import com.intellij.codeInspection.LocalInspectionToolSession 4 | import com.intellij.codeInspection.ProblemsHolder 5 | import com.intellij.lang.javascript.psi.JSBinaryExpression 6 | import com.intellij.psi.PsiElementVisitor 7 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 8 | import org.jetbrains.research.deepbugs.javascript.datatypes.collect 9 | 10 | abstract class JSDeepBugsBinExprInspection(threshold: Float = 0.8f) : JSDeepBugsBaseInspection(threshold) { 11 | override fun createVisitor(holder: ProblemsHolder, session: LocalInspectionToolSession): PsiElementVisitor = JSDeepBugsBinOpVisitor(holder) 12 | 13 | inner class JSDeepBugsBinOpVisitor(holder: ProblemsHolder) : JSDeepBugsVisitor(holder) { 14 | override fun visitJSBinaryExpression(node: JSBinaryExpression?) { 15 | visit(node ?: return) { node.collect() } 16 | super.visitJSBinaryExpression(node) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/base/JSDeepBugsCallExprInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.base 2 | 3 | import com.intellij.codeInspection.LocalInspectionToolSession 4 | import com.intellij.codeInspection.ProblemsHolder 5 | import com.intellij.lang.javascript.psi.JSCallExpression 6 | import com.intellij.psi.PsiElementVisitor 7 | import org.jetbrains.research.deepbugs.common.datatypes.Call 8 | import org.jetbrains.research.deepbugs.javascript.datatypes.collect 9 | 10 | abstract class JSDeepBugsCallExprInspection( 11 | protected val requiredArgumentsNum: Int, 12 | threshold: Float = 0.8f 13 | ) : JSDeepBugsBaseInspection(threshold) { 14 | override fun createVisitor(holder: ProblemsHolder, session: LocalInspectionToolSession): PsiElementVisitor = JSDeepBugsCallVisitor(holder) 15 | 16 | inner class JSDeepBugsCallVisitor(holder: ProblemsHolder) : JSDeepBugsVisitor(holder) { 17 | override fun visitJSCallExpression(node: JSCallExpression?) { 18 | visit(node ?: return) { node.collect() } 19 | super.visitJSCallExpression(node) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/common/JSDeepBugsBinOperandInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.common 2 | 3 | import com.intellij.lang.javascript.psi.JSBinaryExpression 4 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 5 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 6 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.base.JSDeepBugsBinExprInspection 7 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 8 | 9 | class JSDeepBugsBinOperandInspection : JSDeepBugsBinExprInspection() { 10 | override val model: Perceptron? 11 | get() = CommonModelStorage.common.binOperandModel 12 | 13 | override fun createTooltip(node: JSBinaryExpression, vararg params: String): String = 14 | JSResourceBundle.message( 15 | "deepbugs.javascript.binary.operand.inspection.warning", 16 | node.lOperand?.text ?: "", 17 | node.rOperand?.text ?: "" 18 | ) 19 | 20 | override fun getShortName() = "JSDeepBugsBinOperand" 21 | } 22 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/common/JSDeepBugsBinOperatorInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.common 2 | 3 | import com.intellij.codeInspection.ProblemDescriptor 4 | import com.intellij.lang.javascript.psi.JSBinaryExpression 5 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 6 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 7 | import org.jetbrains.research.deepbugs.common.ide.quickfixes.ReplaceBinOperatorQuickFix 8 | import org.jetbrains.research.deepbugs.common.ide.quickfixes.ReplaceBinOperatorQuickFix.Companion.toLookups 9 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 10 | import org.jetbrains.research.deepbugs.javascript.JSDeepBugsConfig 11 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 12 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.base.JSDeepBugsBinExprInspection 13 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.JSIgnoreExpressionQuickFix 14 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.utils.operators 15 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 16 | 17 | class JSDeepBugsBinOperatorInspection : JSDeepBugsBinExprInspection() { 18 | override val model: Perceptron? 19 | get() = CommonModelStorage.common.binOperatorModel 20 | 21 | override fun createProblemDescriptor(node: JSBinaryExpression, data: BinOp): ProblemDescriptor { 22 | val textRange = node.operationNode!!.textRange 23 | val replaceQuickFix = ReplaceBinOperatorQuickFix(data, textRange, JSDeepBugsConfig.get().quickFixesThreshold, 24 | JSResourceBundle.message("deepbugs.javascript.replace.operator.family")) { operators[it] ?: "" }.takeIf { it.isAvailable() } 25 | return BugDescriptor( 26 | node, 27 | createTooltip(node, *(replaceQuickFix.toLookups())), 28 | myOnTheFly, 29 | listOfNotNull(JSIgnoreExpressionQuickFix(data, node.text), replaceQuickFix) 30 | ) 31 | } 32 | 33 | override fun createTooltip(node: JSBinaryExpression, vararg params: String): String { 34 | val operatorText = node.operationNode?.text ?: "" 35 | return params.singleOrNull()?.let { 36 | JSResourceBundle.message("deepbugs.javascript.binary.operator.inspection.warning.single", it, operatorText) 37 | } ?: JSResourceBundle.message("deepbugs.javascript.binary.operator.inspection.warning", operatorText) 38 | } 39 | 40 | override fun getShortName() = "JSDeepBugsBinOperator" 41 | } 42 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/common/JSDeepBugsSwappedArgsInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.common 2 | 3 | import com.intellij.codeInspection.ProblemDescriptor 4 | import com.intellij.lang.javascript.psi.JSCallExpression 5 | import org.jetbrains.research.deepbugs.common.datatypes.Call 6 | import org.jetbrains.research.deepbugs.common.ide.inspections.DeepBugsInspectionManager 7 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 8 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 9 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 10 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.base.JSDeepBugsCallExprInspection 11 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.JSFlipFunctionArgumentsQuickFix 12 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.JSIgnoreExpressionQuickFix 13 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 14 | 15 | open class JSDeepBugsSwappedArgsInspection : JSDeepBugsCallExprInspection(2) { 16 | override val model: Perceptron? 17 | get() = CommonModelStorage.common.swappedArgsModel 18 | 19 | override fun skip(node: JSCallExpression): Boolean { 20 | if (node.arguments.size != requiredArgumentsNum) return true 21 | return DeepBugsInspectionManager.isSpecific(node) 22 | } 23 | 24 | override fun createProblemDescriptor(node: JSCallExpression, data: Call): ProblemDescriptor = 25 | BugDescriptor(node, createTooltip(node), myOnTheFly, listOf( 26 | JSIgnoreExpressionQuickFix(data, node.text), 27 | JSFlipFunctionArgumentsQuickFix() 28 | )) 29 | 30 | override fun createTooltip(node: JSCallExpression, vararg params: String): String = 31 | JSResourceBundle.message("deepbugs.javascript.swapped.args.inspection.warning") 32 | 33 | override fun getShortName() = "JSDeepBugsSwappedArgs" 34 | } 35 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/specific/math/JSDeepBugsIncorrectArgMathInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.specific.math 2 | 3 | import com.intellij.lang.javascript.psi.JSCallExpression 4 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 5 | import org.jetbrains.research.deepbugs.javascript.model.specific.JSSpecificModel 6 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 7 | 8 | class JSDeepBugsIncorrectArgMathInspection : JSDeepBugsMathCallExprInspection(requiredArgsNum = 1, threshold = 0.72f) { 9 | override val model: Perceptron? 10 | get() = JSSpecificModel.math.incorrectArgModel 11 | 12 | override val ignore: Set = setOf("toString", "substring") 13 | 14 | override fun createTooltip(node: JSCallExpression, vararg params: String): String = 15 | JSResourceBundle.message( 16 | "deepbugs.javascript.math.incorrect.arg.inspection.warning", 17 | node.arguments.first().text 18 | ) 19 | 20 | override fun getShortName() = "JSDeepBugsIncorrectArgMath" 21 | } 22 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/specific/math/JSDeepBugsMathCallExprInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.specific.math 2 | 3 | import com.intellij.lang.javascript.library.JSLibraryUtil 4 | import com.intellij.lang.javascript.psi.JSCallExpression 5 | import com.intellij.lang.javascript.psi.JSReferenceExpression 6 | import org.jetbrains.research.deepbugs.common.ide.inspections.DeepBugsInspectionManager 7 | import org.jetbrains.research.deepbugs.common.ide.inspections.specific.SpecificInspectionDescriptor 8 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.base.JSDeepBugsCallExprInspection 9 | 10 | abstract class JSDeepBugsMathCallExprInspection(requiredArgsNum: Int, threshold: Float = 0.8f) : JSDeepBugsCallExprInspection(requiredArgsNum, threshold) { 11 | init { 12 | DeepBugsInspectionManager.register( 13 | SpecificInspectionDescriptor { (it is JSCallExpression) && !skip(it) } 14 | ) 15 | } 16 | 17 | protected open val libsToConsider: Set = emptySet() 18 | protected open val ignore: Set = emptySet() 19 | 20 | override fun skip(node: JSCallExpression): Boolean { 21 | if (node.arguments.size != requiredArgumentsNum) return true 22 | val call = node.methodExpression as? JSReferenceExpression ?: return true 23 | return ignore.contains(call.referenceName) || (!call.isBuiltIn() && !call.isLibCall()) 24 | } 25 | 26 | private fun JSReferenceExpression.isLibCall(): Boolean { 27 | val resolvedFiles = try { 28 | multiResolve(false).mapNotNull { it.element?.containingFile } 29 | } catch (ex: Exception) { 30 | return false 31 | } 32 | val libs = resolvedFiles.mapNotNull { JSLibraryUtil.getLibraryFolder(it.virtualFile)?.name } 33 | return libsToConsider.intersect(libs).isNotEmpty() 34 | } 35 | 36 | companion object { 37 | private val modulesToConsider: Set = setOf("Math") 38 | 39 | private fun JSReferenceExpression.isBuiltIn(): Boolean { 40 | val first = qualifier?.text?.split('.')?.firstOrNull() ?: return false 41 | return modulesToConsider.contains(first) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/inspections/specific/math/JSDeepBugsSwappedArgsMathInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.inspections.specific.math 2 | 3 | import com.intellij.codeInspection.ProblemDescriptor 4 | import com.intellij.lang.javascript.psi.JSCallExpression 5 | import org.jetbrains.research.deepbugs.common.datatypes.Call 6 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 7 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 8 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.JSFlipFunctionArgumentsQuickFix 9 | import org.jetbrains.research.deepbugs.javascript.ide.quickfixes.JSIgnoreExpressionQuickFix 10 | import org.jetbrains.research.deepbugs.javascript.model.specific.JSSpecificModel 11 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 12 | 13 | class JSDeepBugsSwappedArgsMathInspection : JSDeepBugsMathCallExprInspection(requiredArgsNum = 2) { 14 | override val model: Perceptron? 15 | get() = JSSpecificModel.math.swappedArgsModel 16 | 17 | override val libsToConsider: Set = setOf("mathjs") 18 | override val ignore: Set = setOf("min", "max") 19 | 20 | override fun createProblemDescriptor(node: JSCallExpression, data: Call): ProblemDescriptor = 21 | BugDescriptor(node, createTooltip(node), myOnTheFly, listOf( 22 | JSIgnoreExpressionQuickFix(data, node.text), 23 | JSFlipFunctionArgumentsQuickFix() 24 | )) 25 | 26 | override fun createTooltip(node: JSCallExpression, vararg params: String): String = 27 | JSResourceBundle.message("deepbugs.javascript.math.swapped.args.inspection.warning") 28 | 29 | override fun getShortName() = "JSDeepBugsSwappedArgsMath" 30 | } 31 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/quickfixes/JSFlipFunctionArgumentsQuickFix.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.quickfixes 2 | 3 | import com.intellij.lang.javascript.psi.JSCallExpression 4 | import com.intellij.psi.PsiElement 5 | import org.jetbrains.research.deepbugs.common.ide.quickfixes.FlipFunctionArgumentsQuickFix 6 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 7 | 8 | class JSFlipFunctionArgumentsQuickFix : FlipFunctionArgumentsQuickFix() { 9 | override fun getFamilyName(): String = JSResourceBundle.message("deepbugs.javascript.flip.args.family") 10 | 11 | override fun JSCallExpression.toArguments(): Pair = Pair(arguments[0], arguments[1]) 12 | } 13 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/quickfixes/JSIgnoreExpressionQuickFix.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.quickfixes 2 | 3 | import com.intellij.codeInsight.intention.PriorityAction 4 | import com.intellij.codeInspection.LocalQuickFix 5 | import com.intellij.codeInspection.ProblemDescriptor 6 | import com.intellij.icons.AllIcons 7 | import com.intellij.openapi.command.undo.BasicUndoableAction 8 | import com.intellij.openapi.command.undo.UndoManager 9 | import com.intellij.openapi.project.Project 10 | import com.intellij.openapi.util.Iconable 11 | import org.jetbrains.research.deepbugs.common.datatypes.DataType 12 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 13 | import org.jetbrains.research.deepbugs.javascript.JSDeepBugsConfig 14 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 15 | import javax.swing.Icon 16 | 17 | class JSIgnoreExpressionQuickFix(private val expr: DataType, private val displayText: String) : LocalQuickFix, Iconable, PriorityAction { 18 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) { 19 | val ignore = object : BasicUndoableAction(descriptor.psiElement?.containingFile?.virtualFile) { 20 | override fun redo() = JSDeepBugsConfig.ignoreExpression(expr) 21 | override fun undo() = JSDeepBugsConfig.considerExpression(expr) 22 | } 23 | ignore.redo() 24 | DeepBugsCounterCollector.checkDisabled(project, JSDeepBugsConfig.get().userDisabledChecks.size) 25 | UndoManager.getInstance(project).undoableActionPerformed(ignore) 26 | } 27 | 28 | override fun getIcon(flags: Int): Icon = AllIcons.Actions.Cancel 29 | override fun getPriority(): PriorityAction.Priority = PriorityAction.Priority.LOW 30 | 31 | override fun getFamilyName(): String = JSResourceBundle.message("deepbugs.javascript.ignore.family") 32 | override fun getName(): String = JSResourceBundle.message("deepbugs.javascript.ignore.quickfix", displayText) 33 | } 34 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/quickfixes/utils/JSOperatorMap.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.quickfixes.utils 2 | 3 | import com.intellij.lang.javascript.JSTokenTypes 4 | 5 | val operators by lazy { 6 | hashMapOf( 7 | JSTokenTypes.AND.toString() to "&", 8 | JSTokenTypes.ANDAND.toString() to "&&", 9 | JSTokenTypes.AS_KEYWORD.toString() to "as", 10 | JSTokenTypes.COMMA.toString() to ",", 11 | JSTokenTypes.DIV.toString() to "/", 12 | JSTokenTypes.EQEQ.toString() to "==", 13 | JSTokenTypes.EQEQEQ.toString() to "===", 14 | JSTokenTypes.GE.toString() to ">=", 15 | JSTokenTypes.GT.toString() to ">", 16 | JSTokenTypes.GTGT.toString() to ">>", 17 | JSTokenTypes.GTGTGT.toString() to ">>>", 18 | JSTokenTypes.INSTANCEOF_KEYWORD.toString() to "instance of", 19 | JSTokenTypes.IN_KEYWORD.toString() to "in", 20 | JSTokenTypes.LE.toString() to "<=", 21 | JSTokenTypes.LT.toString() to "<", 22 | JSTokenTypes.LTLT.toString() to "<<", 23 | JSTokenTypes.MINUS.toString() to "-", 24 | JSTokenTypes.MULT.toString() to "*", 25 | JSTokenTypes.NE.toString() to "!=", 26 | JSTokenTypes.NEQEQ.toString() to "!==", 27 | JSTokenTypes.OR.toString() to "|", 28 | JSTokenTypes.OROR.toString() to "||", 29 | JSTokenTypes.PERC.toString() to "%", 30 | JSTokenTypes.PLUS.toString() to "+", 31 | JSTokenTypes.XOR.toString() to "^" 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/ide/ui/JSDeepBugsConfigurable.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.ide.ui 2 | 3 | import com.intellij.openapi.components.service 4 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 5 | import org.jetbrains.research.deepbugs.common.ide.ui.DeepBugsConfigurable 6 | import org.jetbrains.research.deepbugs.javascript.JSDeepBugsConfig 7 | import org.jetbrains.research.deepbugs.javascript.JSResourceBundle 8 | 9 | class JSDeepBugsConfigurable : DeepBugsConfigurable( 10 | JSDeepBugsConfig.default, 11 | "JSPluginConfig", 12 | JSResourceBundle.message("deepbugs.javascript.display") 13 | ) { 14 | override fun getSettings(): DeepBugsConfig = service() 15 | } 16 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/model/specific/JSSpecificModel.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.model.specific 2 | 3 | object JSSpecificModel { 4 | val math: MathModel by lazy { MathModel() } 5 | } 6 | -------------------------------------------------------------------------------- /js-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/javascript/model/specific/MathModel.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript.model.specific 2 | 3 | import org.jetbrains.research.deepbugs.common.model.ModelHandler 4 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 5 | 6 | data class MathModel( 7 | val swappedArgsModel: Perceptron = loadModel("swappedArgsDetectionModelMath.h5"), 8 | val incorrectArgModel: Perceptron = loadModel("incorrectFuncArgDetectionModelMath.h5") 9 | ) { 10 | companion object { 11 | private fun loadModel(model: String): Perceptron = ModelHandler.loadModel(model, "math")!! 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /js-plugin/src/main/models/common/binOperandDetectionModel.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/common/binOperandDetectionModel.h5 -------------------------------------------------------------------------------- /js-plugin/src/main/models/common/binOperatorDetectionModel.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/common/binOperatorDetectionModel.h5 -------------------------------------------------------------------------------- /js-plugin/src/main/models/common/swappedArgsDetectionModel.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/common/swappedArgsDetectionModel.h5 -------------------------------------------------------------------------------- /js-plugin/src/main/models/math/incorrectFuncArgDetectionModelMath.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/math/incorrectFuncArgDetectionModelMath.h5 -------------------------------------------------------------------------------- /js-plugin/src/main/models/math/swappedArgsDetectionModelMath.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/math/swappedArgsDetectionModelMath.h5 -------------------------------------------------------------------------------- /js-plugin/src/main/models/nodeTypeToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/nodeTypeToVector.cbor -------------------------------------------------------------------------------- /js-plugin/src/main/models/operatorToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/operatorToVector.cbor -------------------------------------------------------------------------------- /js-plugin/src/main/models/tokenToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/tokenToVector.cbor -------------------------------------------------------------------------------- /js-plugin/src/main/models/typeToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/js-plugin/src/main/models/typeToVector.cbor -------------------------------------------------------------------------------- /js-plugin/src/main/resources/DeepBugsJavaScriptBundle.properties: -------------------------------------------------------------------------------- 1 | deepbugs.javascript.binary.operator.inspection.warning=Possibly incorrect operator: “{0}” 2 | deepbugs.javascript.binary.operator.inspection.warning.single=Probably you meant “{0}” instead of “{1}” 3 | deepbugs.javascript.binary.operand.inspection.warning=Possibly incorrect operand: “{0}” or “{1}” 4 | deepbugs.javascript.swapped.args.inspection.warning=Possibly wrong order of function arguments 5 | deepbugs.javascript.math.swapped.args.inspection.warning=Possibly wrong order of math function arguments 6 | deepbugs.javascript.math.incorrect.arg.inspection.warning=Possibly incorrect argument in math function call: “{0}” 7 | deepbugs.javascript.ignore.family=DeepBugs for JavaScript: Ignore expression 8 | deepbugs.javascript.flip.args.family=DeepBugs for JavaScript: Fix order of arguments 9 | deepbugs.javascript.replace.operator.family=DeepBugs for JavaScript: Replace operator 10 | deepbugs.javascript.display=DeepBugs for JavaScript 11 | deepbugs.javascript.ignore.quickfix=Always ignore “{0}” 12 | deepbugs.javascript.group.name=Probable bugs 13 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | DeepBugs for JavaScript 3 | DeepBugsJavaScript 4 | JetBrains 5 | Finds potential bugs and code quality issues for JavaScript using deep learning models.

7 | 8 |

Detects several types of bugs, including incorrect function arguments, incorrect comparison, and others, based on extracted code semantics.

9 | 10 |

Deep learning models are inspired by DeepBugs.

11 | 12 |

To configure, open Preferences/Settings | Tools | DeepBugs for JavaScript.

13 | ]]>
14 | 15 | 0.5 17 | Update for 201.* builds 18 | 19 |

0.4

20 |
    21 |
  • Support specific inspections for math (built-in Math object) function calls
  • 22 |
      23 |
    • Misused function argument
    • 24 |
    • Incorrect order of function arguments (also available for mathjs library)
    • 25 |
    26 |
  • Minor bug fixes
  • 27 |
28 | 29 |

0.3

30 |
    31 |
  • Significantly reduce plugin size
  • 32 |
  • Add several quick-fixes for detected bugs
  • 33 |
  • Fully rework settings UI and inspections tooltips
  • 34 |
  • A lot of bug fixes and stability improvements
  • 35 |
36 | 37 |

0.2

38 |
    39 |
  • Minor improvements
  • 40 |
41 | ]]> 42 |
43 | 44 | com.intellij.modules.lang 45 | JavaScript 46 | 47 | 48 | 49 | 50 | 56 | 57 | 63 | 64 | 70 | 71 | 77 | 78 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/inspectionDescriptions/JSDeepBugsBinOperand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of binary operands (arguments of binary operations) 4 | 5 | 6 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/inspectionDescriptions/JSDeepBugsBinOperator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of binary operators 4 | 5 | 6 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/inspectionDescriptions/JSDeepBugsIncorrectArgMath.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of math function arguments 4 | 5 | 6 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/inspectionDescriptions/JSDeepBugsSwappedArgs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of function arguments (specifically, their order) 4 | 5 | 6 | -------------------------------------------------------------------------------- /js-plugin/src/main/resources/inspectionDescriptions/JSDeepBugsSwappedArgsMath.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of math function arguments (specifically, their order) 4 | 5 | 6 | -------------------------------------------------------------------------------- /js-plugin/src/test/kotlin/org/jetbrains/research/deepbugs/javascript/DeepBugsTestBase.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript 2 | 3 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 4 | import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl 5 | import org.jetbrains.research.deepbugs.common.DeepBugsPlugin 6 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.common.* 7 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.specific.math.JSDeepBugsIncorrectArgMathInspection 8 | import org.jetbrains.research.deepbugs.javascript.ide.inspections.specific.math.JSDeepBugsSwappedArgsMathInspection 9 | import java.io.File 10 | 11 | abstract class DeepBugsTestBase : BasePlatformTestCase() { 12 | init { 13 | DeepBugsPlugin.setTestPlugin("DeepBugsJavaScript") 14 | } 15 | 16 | override fun getTestDataPath(): String { 17 | return File("src/test/testData").canonicalPath 18 | } 19 | 20 | override fun setUp() { 21 | super.setUp() 22 | myFixture.enableInspections(*inspectionTools) 23 | (myFixture as? CodeInsightTestFixtureImpl)?.canChangeDocumentDuringHighlighting(true) 24 | } 25 | 26 | protected open fun runHighlightTestForFile(file: String) { 27 | myFixture.configureByFile(file) 28 | myFixture.checkHighlighting(true, false, false) 29 | } 30 | 31 | companion object { 32 | val inspectionTools by lazy { 33 | arrayOf( 34 | JSDeepBugsBinOperandInspection(), 35 | JSDeepBugsBinOperatorInspection(), 36 | JSDeepBugsSwappedArgsInspection(), 37 | JSDeepBugsSwappedArgsMathInspection(), 38 | JSDeepBugsIncorrectArgMathInspection() 39 | ) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /js-plugin/src/test/kotlin/org/jetbrains/research/deepbugs/javascript/JSDeepBugsTest.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.javascript 2 | 3 | class JSDeepBugsTest : DeepBugsTestBase() { 4 | fun `test bin operand`() { 5 | runHighlightTestForFile("testIncorrectBinOperandJS.js") 6 | } 7 | 8 | fun `test bin operator`() { 9 | runHighlightTestForFile("testIncorrectBinOperatorJS.js") 10 | } 11 | 12 | fun `test swapped arguments`() { 13 | runHighlightTestForFile("testSwappedArgumentsJS.js") 14 | } 15 | 16 | fun `test swapped arguments math`() { 17 | runHighlightTestForFile("testSwappedArgumentsMathJS.js") 18 | } 19 | 20 | fun `test incorrect argument math`() { 21 | runHighlightTestForFile("testIncorrectArgumentMathJS.js") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js-plugin/src/test/testData/testIncorrectArgumentMathJS.js: -------------------------------------------------------------------------------- 1 | let res1 = Math.sin(90); 2 | 3 | let txt = "text" 4 | let res2 = Math.ceil(txt); 5 | 6 | let rad = Math.PI / 2 7 | let res3 = Math.cos(rad) 8 | -------------------------------------------------------------------------------- /js-plugin/src/test/testData/testIncorrectBinOperandJS.js: -------------------------------------------------------------------------------- 1 | function adder1(base) { 2 | base = Number(base); 3 | for (let j = 1; j < arguments; j++) { 4 | base += Number(arguments[j]); 5 | } 6 | return base; 7 | } 8 | 9 | function adder2(base) { 10 | base = Number(base); 11 | for (let j = 1; j < arguments.length; j++) { 12 | base += Number(arguments[j]); 13 | } 14 | return base; 15 | } 16 | 17 | 18 | let x = 1; 19 | let y = 2; 20 | let height = 3; 21 | 22 | let res1 = height - x; 23 | let res2 = height - y; 24 | -------------------------------------------------------------------------------- /js-plugin/src/test/testData/testIncorrectBinOperatorJS.js: -------------------------------------------------------------------------------- 1 | function adder1(base) { 2 | base = Number(base); 3 | for (let i = 1; i <= arguments.length; i++) { 4 | base += Number(arguments[i]); 5 | } 6 | return base; 7 | } 8 | 9 | function adder2(base) { 10 | base = Number(base); 11 | for (let i = 1; i < arguments.length; i++) { 12 | base += Number(arguments[i]); 13 | } 14 | return base; 15 | } 16 | 17 | 18 | let text = 1; 19 | let str = 2; 20 | 21 | text / str; 22 | text + str; 23 | -------------------------------------------------------------------------------- /js-plugin/src/test/testData/testSwappedArgumentsJS.js: -------------------------------------------------------------------------------- 1 | let x = 1; 2 | let y = 2; 3 | function setSize(xx, yy) { 4 | x = xx; 5 | y = yy; 6 | } 7 | 8 | let width = 5; 9 | let height = 10; 10 | setSize(width, height); 11 | setSize(height, width); 12 | 13 | 14 | let promise = new Promise((resolve, reject) => { 15 | if (Math.random() * 100 < 90) { 16 | resolve('Success'); 17 | } 18 | reject(new Error('Error')); 19 | }); 20 | 21 | let onSuccess = (resolvedValue) => console.log(resolvedValue); 22 | let onError = (error) => console.log(error); 23 | 24 | promise.then(onError, onSuccess); 25 | promise.then(onSuccess, onError); 26 | -------------------------------------------------------------------------------- /js-plugin/src/test/testData/testSwappedArgumentsMathJS.js: -------------------------------------------------------------------------------- 1 | let x = 1; 2 | let y = 2; 3 | Math.atan2(x, y); 4 | -------------------------------------------------------------------------------- /keras-runner/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = "org.jetbrains.research" 2 | version = rootProject.version 3 | 4 | intellij { 5 | version = rootProject.intellij.version 6 | } 7 | 8 | dependencies { 9 | implementation("io.jhdf", "jhdf", "0.5.3") { 10 | // to avoid conflict with the dependency already included in IntelliJ Platform 11 | exclude("org.slf4j") 12 | } 13 | api("scientifik", "kmath-core-jvm", "0.1.3") { 14 | exclude("org.jetbrains.kotlin") 15 | } 16 | implementation("org.jetbrains.kotlinx", "kotlinx-serialization-runtime", "0.20.0") { 17 | exclude("org.jetbrains.kotlin") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/ModelLoader.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer 2 | 3 | import io.jhdf.HdfFile 4 | import io.jhdf.api.Dataset 5 | import org.jetbrains.research.keras.runner.deserializer.json.ModelConfig 6 | import org.jetbrains.research.keras.runner.deserializer.json.ModelScheme 7 | import org.jetbrains.research.keras.runner.nn.layer.Layer 8 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 9 | import java.io.File 10 | 11 | @Suppress("UNCHECKED_CAST") 12 | object ModelLoader { 13 | fun loadPerceptronModel(model: File): Perceptron { 14 | val (config, layers) = importSequentialModelParameters(model) 15 | config as ModelConfig.Sequential 16 | return Perceptron.create(config.name, layers, config.batchInputShape) 17 | } 18 | 19 | private fun importSequentialModelParameters(model: File): Pair>> { 20 | val hdf = HdfFile(model) 21 | 22 | val config = importModelConfig(hdf) 23 | val layers = importSequentialModelLayers(hdf, config.config) 24 | 25 | return config.config to layers 26 | } 27 | 28 | private fun importSequentialModelLayers(hdf: HdfFile, config: ModelConfig) = config.layers.mapNotNull { layer -> 29 | val layerWeights = hdf.getByPath("model_weights/${layer.config.name}") 30 | val weightNames = (layerWeights.getAttribute("weight_names").data as? Array)?.filterNotNull() 31 | 32 | val (weights, biases) = weightNames?.map { weight -> 33 | val data = hdf.getByPath("model_weights/${layer.config.name}/$weight") as Dataset 34 | weight to data.data.toMatrix() 35 | }?.partition { !it.first.contains("bias") } ?: null to null 36 | 37 | val params = Layer.Parameters( 38 | weights?.map { it.second }?.singleOrNull(), 39 | biases?.map { it.second }?.singleOrNull() 40 | ) 41 | Layer.create(layer, params) 42 | } 43 | 44 | private fun importModelConfig(hdf: HdfFile): ModelScheme { 45 | val configString = hdf.getAttribute("model_config").data as String 46 | return ModelScheme.parse(configString) 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/Utils.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer 2 | 3 | import scientifik.kmath.linear.VirtualMatrix 4 | import scientifik.kmath.linear.transpose 5 | import scientifik.kmath.structures.Matrix 6 | import java.lang.IllegalStateException 7 | 8 | internal inline fun List.toDoubleList(): List = map { it.toDouble() } 9 | 10 | internal fun FloatArray.toDoubleList() = asList().toDoubleList() 11 | internal fun Array.toDoubleList() = map { it.toDoubleList() } 12 | 13 | @Suppress("UNCHECKED_CAST") 14 | internal inline fun T.toMatrix(): Matrix<*> = when (this) { 15 | is FloatArray -> VirtualMatrix(rowNum = size, colNum = 1, generator = { i, _ -> this[i] }).transpose() 16 | is Array<*> -> { 17 | this as Array 18 | VirtualMatrix(rowNum = size, colNum = this[0].size, generator = { i, j -> this[i][j] }).transpose() 19 | } 20 | else -> throw IllegalStateException("Cannot cast ${T::class} to matrix") 21 | } 22 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/json/ActivationType.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer.json 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | @Suppress("EnumEntryName") 7 | enum class ActivationType { 8 | relu, 9 | sigmoid 10 | } 11 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/json/LayerConfig.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer.json 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | @Suppress("PropertyName") 7 | sealed class LayerConfig { 8 | abstract val name: String 9 | abstract val trainable: Boolean 10 | abstract val batch_input_shape: List? 11 | abstract val dtype: String? 12 | 13 | @Serializable 14 | data class Dense( 15 | override val name: String, 16 | override val trainable: Boolean, 17 | override val batch_input_shape: List? = null, 18 | override val dtype: String? = null, 19 | val units: Int, 20 | val activation: ActivationType, 21 | val use_bias: Boolean 22 | ) : LayerConfig() 23 | 24 | @Serializable 25 | data class Dropout( 26 | override val name: String, 27 | override val trainable: Boolean, 28 | override val batch_input_shape: List? = null, 29 | override val dtype: String? = null, 30 | val rate: Double 31 | ) : LayerConfig() 32 | } 33 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/json/LayerScheme.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer.json 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | import kotlinx.serialization.Transient 6 | 7 | @Serializable 8 | sealed class LayerScheme { 9 | abstract val type: Type 10 | abstract val config: LayerConfig 11 | 12 | @Serializable 13 | @SerialName("Dense") 14 | @Suppress("UNUSED") 15 | data class DenseLayerScheme( 16 | @Transient override val type: Type = Type.DENSE, 17 | override val config: LayerConfig.Dense 18 | ) : LayerScheme() 19 | 20 | @Serializable 21 | @SerialName("Dropout") 22 | @Suppress("UNUSED") 23 | data class DropoutLayerScheme( 24 | @Transient override val type: Type = Type.DROPOUT, 25 | override val config: LayerConfig.Dropout 26 | ) : LayerScheme() 27 | 28 | enum class Type { 29 | DENSE, 30 | DROPOUT 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/json/ModelConfig.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer.json 2 | 3 | import kotlinx.serialization.Serializable 4 | import kotlinx.serialization.Transient 5 | 6 | @Serializable 7 | sealed class ModelConfig { 8 | abstract val name: String 9 | abstract val layers: List 10 | 11 | @Serializable 12 | data class Sequential( 13 | override val name: String, 14 | override val layers: List 15 | ) : ModelConfig() { 16 | @Transient 17 | val batchInputShape = layers.first().config.batch_input_shape!!.filterNotNull() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/deserializer/json/ModelScheme.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.deserializer.json 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | import kotlinx.serialization.json.Json 6 | import kotlinx.serialization.json.JsonConfiguration 7 | 8 | @Serializable 9 | sealed class ModelScheme { 10 | abstract val config: ModelConfig 11 | 12 | @Serializable 13 | @SerialName("Sequential") 14 | @Suppress("UNUSED") 15 | data class SequentialScheme(override val config: ModelConfig.Sequential) : ModelScheme() 16 | 17 | companion object { 18 | private val json = Json(configuration = JsonConfiguration.Stable.copy(ignoreUnknownKeys = true, classDiscriminator = "class_name")) 19 | 20 | fun parse(config: String) = json.parse(serializer(), config) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/activation/ActivatableVector.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.activation 2 | 3 | import scientifik.kmath.linear.* 4 | import scientifik.kmath.structures.Buffer 5 | 6 | class ActivatableVector(size: Int) { 7 | var values: RealMatrix = BufferMatrix(size, 1, Buffer.auto(size) { 0.0 }) 8 | private set 9 | 10 | private var notActivatedValues: RealMatrix? = null 11 | 12 | fun activate(func: ActivationFunction) { 13 | if (notActivatedValues == null) notActivatedValues = values 14 | values = func(notActivatedValues!!.asPoint()) 15 | } 16 | 17 | fun forward(weights: RealMatrix, bias: RealMatrix?, x: RealMatrix): RealMatrix { 18 | var res = weights.dot(x) 19 | if (bias != null) res = MatrixContext.real.add(res, bias.transpose()) 20 | notActivatedValues = res 21 | return res 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/activation/ActivationFunction.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.activation 2 | 3 | import org.jetbrains.research.keras.runner.deserializer.json.ActivationType 4 | import scientifik.kmath.linear.BufferMatrix 5 | import scientifik.kmath.linear.Point 6 | import scientifik.kmath.linear.RealMatrix 7 | import scientifik.kmath.structures.asBuffer 8 | import scientifik.kmath.structures.asIterable 9 | import kotlin.math.exp 10 | import kotlin.math.max 11 | 12 | sealed class ActivationFunction(private val func: (Double) -> Double) { 13 | operator fun invoke(array: Point): RealMatrix { 14 | return BufferMatrix(array.size, 1, array.asIterable().map(func).asBuffer()) 15 | } 16 | 17 | object ReLU : ActivationFunction(func = { x -> max(0.0, x) }) 18 | object Sigmoid : ActivationFunction(func = { x -> 1.0 / (1.0 + exp(-x)) }) 19 | 20 | companion object { 21 | operator fun get(type: ActivationType) = when (type) { 22 | ActivationType.relu -> ReLU 23 | ActivationType.sigmoid -> Sigmoid 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/layer/ActivatableLayer.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.layer 2 | 3 | import org.jetbrains.research.keras.runner.nn.activation.ActivationFunction 4 | import scientifik.kmath.structures.NDStructure 5 | 6 | abstract class ActivatableLayer>(name: String, params: Parameters) : Layer(name, params) { 7 | protected abstract val activationFunction: ActivationFunction 8 | 9 | abstract fun activate() 10 | } 11 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/layer/Layer.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.layer 2 | 3 | import org.jetbrains.research.keras.runner.deserializer.json.LayerConfig 4 | import org.jetbrains.research.keras.runner.deserializer.json.LayerScheme 5 | import org.jetbrains.research.keras.runner.nn.activation.ActivationFunction 6 | import org.jetbrains.research.keras.runner.nn.layer.dense.DenseLayer 7 | import org.jetbrains.research.keras.runner.nn.layer.dense.DenseParameters 8 | import scientifik.kmath.structures.NDStructure 9 | 10 | abstract class Layer>(val name: String, val params: Parameters) { 11 | data class Parameters>(val weights: T?, val biases: T?) 12 | 13 | companion object { 14 | @Suppress("UNCHECKED_CAST") 15 | fun create(config: LayerScheme, params: Parameters<*>) = when (config.type) { 16 | LayerScheme.Type.DENSE -> DenseLayer( 17 | name = config.config.name, 18 | params = params as DenseParameters, 19 | activationFunction = ActivationFunction[(config.config as LayerConfig.Dense).activation] 20 | ) 21 | LayerScheme.Type.DROPOUT -> null 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/layer/dense/DenseLayer.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.layer.dense 2 | 3 | import org.jetbrains.research.keras.runner.nn.activation.ActivatableVector 4 | import org.jetbrains.research.keras.runner.nn.activation.ActivationFunction 5 | import org.jetbrains.research.keras.runner.nn.layer.ActivatableLayer 6 | import scientifik.kmath.linear.BufferMatrix 7 | import scientifik.kmath.linear.Point 8 | import scientifik.kmath.structures.Matrix 9 | 10 | class DenseLayer( 11 | name: String, 12 | params: DenseParameters, 13 | override val activationFunction: ActivationFunction 14 | ) : ActivatableLayer>(name, params) { 15 | 16 | lateinit var inputArray: Point 17 | var outputArray: ActivatableVector = ActivatableVector(params.weights?.colNum ?: 0) 18 | 19 | override fun activate() { 20 | outputArray.forward( 21 | weights = params.weights!!, 22 | bias = params.biases, 23 | x = BufferMatrix(inputArray.size, 1, inputArray) 24 | ) 25 | outputArray.activate(activationFunction) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/layer/dense/DenseParameters.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.layer.dense 2 | 3 | import org.jetbrains.research.keras.runner.nn.layer.Layer 4 | import scientifik.kmath.linear.RealMatrix 5 | 6 | typealias DenseParameters = Layer.Parameters 7 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/model/Model.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.model 2 | 3 | abstract class Model(val name: String) { 4 | abstract fun predict(input: T): V? 5 | } 6 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/model/sequential/Perceptron.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.model.sequential 2 | 3 | import org.jetbrains.research.keras.runner.nn.layer.Layer 4 | import org.jetbrains.research.keras.runner.nn.layer.dense.DenseLayer 5 | import scientifik.kmath.linear.Point 6 | import scientifik.kmath.linear.asPoint 7 | 8 | open class Perceptron( 9 | name: String, 10 | override val layers: List, 11 | batchInputShape: List 12 | ) : SequentialModel(name, layers, batchInputShape) { 13 | companion object { 14 | @Suppress("UNCHECKED_CAST") 15 | fun create(name: String, layers: List>, batchInputShape: List?): Perceptron { 16 | require(batchInputShape != null) { "Model input shape is unspecified" } 17 | require(batchInputShape.filterNotNull().size == 1) { "Input should be one-dimensional" } 18 | 19 | layers as List 20 | 21 | return Perceptron(name, layers, batchInputShape) 22 | } 23 | } 24 | 25 | override fun predict(input: FloatArray): Float { 26 | require(batchInputShape!!.filterNotNull().single() == input.size) { "Unmatched input shapes" } 27 | 28 | layers.first().let { 29 | it.inputArray = Point.real(input.size) { i -> input[i].toDouble() } 30 | it.activate() 31 | } 32 | 33 | layers.zipWithNext { prev, cur -> 34 | cur.inputArray = prev.outputArray.values.asPoint() 35 | cur.activate() 36 | } 37 | 38 | return layers.last().outputArray.values[0, 0].toFloat() 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /keras-runner/src/main/kotlin/org/jetbrains/research/keras/runner/nn/model/sequential/SequentialModel.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.keras.runner.nn.model.sequential 2 | 3 | import org.jetbrains.research.keras.runner.nn.layer.Layer 4 | import org.jetbrains.research.keras.runner.nn.model.Model 5 | 6 | abstract class SequentialModel( 7 | name: String, 8 | protected open val layers: List>, 9 | val batchInputShape: List? = null 10 | ) : Model(name) 11 | -------------------------------------------------------------------------------- /py-plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.intellij.tasks.* 2 | import tanvd.kosogor.defaults.configureIdea 3 | 4 | group = rootProject.group 5 | version = rootProject.version 6 | 7 | intellij { 8 | pluginName = "DeepBugs for Python" 9 | version = rootProject.intellij.version 10 | type = "IC" 11 | downloadSources = true 12 | setPlugins("PythonCore:201.6668.13", "java") 13 | } 14 | 15 | configureIdea { 16 | exclude += file("src/test/testData") 17 | } 18 | 19 | tasks.withType { 20 | from("${projectDir}/src/main/models") { 21 | into("${pluginName}/models") 22 | } 23 | } 24 | 25 | tasks.withType { 26 | jvmArgs("-Xmx1g", "-Didea.is.internal=true") 27 | } 28 | 29 | tasks.withType { 30 | useJUnit() 31 | 32 | testLogging { 33 | events("passed", "skipped", "failed") 34 | } 35 | } 36 | 37 | tasks.withType { 38 | sinceBuild("201") 39 | untilBuild("") 40 | } 41 | 42 | dependencies { 43 | implementation(project(":common")) 44 | implementation(project(":keras-runner")) 45 | } 46 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/PyDeepBugsConfig.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python 2 | 3 | import com.intellij.openapi.components.* 4 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 5 | import org.jetbrains.research.deepbugs.common.DeepBugsConfigHandler 6 | 7 | @State(name = "DeepBugsPy", storages = [Storage("deepbugs.py.xml")]) 8 | class PyDeepBugsConfig : PersistentStateComponent, DeepBugsConfig(default) { 9 | companion object : DeepBugsConfigHandler() { 10 | override val instance: PyDeepBugsConfig by lazy { service() } 11 | override val default = State() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/PyResourceBundle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python 2 | 3 | import com.intellij.AbstractBundle 4 | import org.jetbrains.annotations.PropertyKey 5 | import java.util.* 6 | 7 | object PyResourceBundle { 8 | private const val BUNDLE_NAME = "DeepBugsPythonBundle" 9 | 10 | private val bundle by lazy { ResourceBundle.getBundle(BUNDLE_NAME) } 11 | 12 | fun message(@PropertyKey(resourceBundle = BUNDLE_NAME) key: String, vararg params: Any): String { 13 | return AbstractBundle.message(bundle!!, key, *params) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/datatypes/PyDataTypeUtils.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.datatypes 2 | 3 | import com.jetbrains.python.psi.PyBinaryExpression 4 | import com.jetbrains.python.psi.PyCallExpression 5 | import com.jetbrains.python.psi.resolve.PyResolveContext 6 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 7 | import org.jetbrains.research.deepbugs.common.datatypes.Call 8 | import org.jetbrains.research.deepbugs.python.extraction.* 9 | 10 | fun PyCallExpression.collect(): Call? { 11 | val name = callee?.extractNodeName() ?: return null 12 | 13 | val args = ArrayList() 14 | val argTypes = ArrayList() 15 | for (arg in arguments) { 16 | args.add(arg.extractNodeName() ?: return null) 17 | argTypes.add(arg.extractNodeType()) 18 | } 19 | 20 | val base = extractNodeBase() 21 | 22 | val resolved = multiResolveCalleeFunction(PyResolveContext.defaultContext()).firstOrNull() 23 | var params = resolved?.parameterList?.parameters?.toList() 24 | if (!params.isNullOrEmpty() && params.first().isSelf && params.size > args.size) 25 | params = params.drop(1) 26 | val paramNames = MutableList(args.size) { "" } 27 | paramNames.forEachIndexed { idx, _ -> 28 | paramNames[idx] = params?.getOrNull(idx)?.extractNodeName() ?: "" 29 | } 30 | return Call(name, args, base, argTypes, paramNames) 31 | } 32 | 33 | fun PyBinaryExpression.collect(): BinOp? { 34 | val leftName = leftExpression?.extractNodeName() ?: return null 35 | val rightName = rightExpression?.extractNodeName() ?: return null 36 | val op = extractOperatorText() ?: return null 37 | val leftType = leftExpression?.extractNodeType() ?: return null 38 | val rightType = rightExpression?.extractNodeType() ?: return null 39 | val parentNode = parent.javaClass.simpleName ?: "" 40 | val grandParentNode = parent.parent.javaClass.simpleName ?: "" 41 | return BinOp(leftName, rightName, op, leftType, rightType, parentNode, grandParentNode) 42 | } 43 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/extraction/PyExtraction.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.extraction 2 | 3 | import com.intellij.openapi.util.TextRange 4 | import com.intellij.psi.PsiElement 5 | import com.intellij.psi.PsiWhiteSpace 6 | import com.intellij.psi.util.siblings 7 | import com.jetbrains.python.* 8 | import com.jetbrains.python.psi.* 9 | 10 | fun String.asLiteralString() = "LIT:$this" 11 | 12 | fun String.asIdentifierString() = "ID:$this" 13 | 14 | @Suppress("ComplexMethod") 15 | fun PyElement.extractNodeName(): String? = when (this) { 16 | is PyNumericLiteralExpression -> text.asLiteralString() 17 | is PyStringLiteralExpression -> stringValue.asLiteralString() 18 | is PyBoolLiteralExpression -> text.asLiteralString() 19 | is PyNoneLiteralExpression -> text.asLiteralString() 20 | is PyReferenceExpression -> referencedName?.asIdentifierString() 21 | is PyPrefixExpression -> { 22 | if (operator == PyTokenTypes.MINUS && operand is PyNumericLiteralExpression) text.asLiteralString() 23 | operand?.extractNodeName() 24 | } 25 | is PyCallExpression -> callee?.extractNodeName() 26 | is PySubscriptionExpression -> operand.extractNodeName() 27 | is PyLambdaExpression -> PyNames.LAMBDA.asIdentifierString() 28 | is PyParameter -> text.substringBefore(':').substringBefore('=').asIdentifierString() 29 | else -> null 30 | } 31 | 32 | @Suppress("ComplexMethod") 33 | fun PyElement.extractNodeType(): String = when (this) { 34 | is PyNumericLiteralExpression -> "number" 35 | is PyStringLiteralExpression -> "string" 36 | is PyBoolLiteralExpression -> "boolean" 37 | is PyNoneLiteralExpression -> "none" 38 | is PyReferenceExpression -> when (referencedName) { 39 | PyNames.CANONICAL_SELF -> "object" 40 | else -> "unknown" 41 | } 42 | is PyPrefixExpression -> operand?.extractNodeType() ?: "unknown" 43 | is PyLambdaExpression -> "lambda" 44 | else -> "unknown" 45 | } 46 | 47 | fun PyElement.extractNodeBase(): String = when (this) { 48 | is PyCallExpression -> (callee as? PyReferenceExpression)?.extractNodeBase() ?: "" 49 | is PyReferenceExpression -> qualifier?.extractNodeName() ?: "" 50 | is PySubscriptionExpression -> operand.extractNodeName() ?: "" 51 | else -> "" 52 | } 53 | 54 | fun PyBinaryExpression.extractOperatorText(): String? { 55 | operatorRange ?: return null 56 | if (operatorRange!!.first == operatorRange!!.second) return operatorRange!!.first.text 57 | 58 | return findOperatorElements().toList().asReversed().joinToString(" ") { it.text } 59 | } 60 | 61 | fun PyBinaryExpression.findOperatorTextRange(): TextRange? { 62 | operatorRange ?: return null 63 | return TextRange(operatorRange!!.first.textRange.startOffset, operatorRange!!.second.textRange.endOffset) 64 | } 65 | 66 | private fun PyBinaryExpression.findOperatorElements(): Sequence { 67 | operatorRange ?: emptySequence() 68 | if (operatorRange!!.first == operatorRange!!.second) return sequenceOf(operatorRange!!.first) 69 | 70 | val siblings = rightExpression?.prevSibling?.siblings(forward = false) ?: emptySequence() 71 | return siblings.takeWhile { it != operatorRange!!.first.prevSibling }.filter { it !is PsiWhiteSpace } 72 | } 73 | 74 | private val PyBinaryExpression.operatorRange: Pair? 75 | get() { 76 | val firstElement = psiOperator ?: return null 77 | val lastElement = rightExpression?.prevSibling?.siblings(forward = false)?.firstOrNull { it !is PsiWhiteSpace } 78 | return firstElement to (lastElement ?: firstElement) 79 | } 80 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/inspections/PyDeepBugsBinOperandInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.inspections 2 | 3 | import com.jetbrains.python.psi.PyBinaryExpression 4 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 5 | import org.jetbrains.research.deepbugs.python.PyResourceBundle 6 | import org.jetbrains.research.deepbugs.python.ide.inspections.base.PyDeepBugsBinExprInspection 7 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 8 | 9 | class PyDeepBugsBinOperandInspection : PyDeepBugsBinExprInspection(0.86f) { 10 | override val model: Perceptron? 11 | get() = CommonModelStorage.common.binOperandModel 12 | 13 | override fun createTooltip(node: PyBinaryExpression, vararg params: String): String = 14 | PyResourceBundle.message( 15 | "deepbugs.python.binary.operand.inspection.warning", 16 | node.leftExpression.text, 17 | node.rightExpression?.text ?: "" 18 | ) 19 | 20 | override fun getDisplayName() = PyResourceBundle.message("deepbugs.python.binary.operand.inspection.display") 21 | override fun getShortName(): String = "PyDeepBugsBinOperand" 22 | } 23 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/inspections/PyDeepBugsBinOperatorInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.inspections 2 | 3 | import com.intellij.codeInspection.ProblemDescriptor 4 | import com.jetbrains.python.psi.PyBinaryExpression 5 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 6 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 7 | import org.jetbrains.research.deepbugs.common.ide.quickfixes.ReplaceBinOperatorQuickFix 8 | import org.jetbrains.research.deepbugs.common.ide.quickfixes.ReplaceBinOperatorQuickFix.Companion.toLookups 9 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 10 | import org.jetbrains.research.deepbugs.python.PyDeepBugsConfig 11 | import org.jetbrains.research.deepbugs.python.PyResourceBundle 12 | import org.jetbrains.research.deepbugs.python.extraction.extractOperatorText 13 | import org.jetbrains.research.deepbugs.python.extraction.findOperatorTextRange 14 | import org.jetbrains.research.deepbugs.python.ide.inspections.base.PyDeepBugsBinExprInspection 15 | import org.jetbrains.research.deepbugs.python.ide.quickfixes.PyIgnoreExpressionQuickFix 16 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 17 | 18 | class PyDeepBugsBinOperatorInspection : PyDeepBugsBinExprInspection(0.85f) { 19 | override val model: Perceptron? 20 | get() = CommonModelStorage.common.binOperatorModel 21 | 22 | override fun createProblemDescriptor(node: PyBinaryExpression, data: BinOp, onTheFly: Boolean): ProblemDescriptor { 23 | val textRange = node.findOperatorTextRange()!! 24 | val replaceQuickFix = ReplaceBinOperatorQuickFix(data, textRange, PyDeepBugsConfig.get().quickFixesThreshold, 25 | PyResourceBundle.message("deepbugs.python.replace.operator.family")).takeIf { it.isAvailable() } 26 | return BugDescriptor( 27 | node, 28 | createTooltip(node, *(replaceQuickFix.toLookups())), 29 | onTheFly, 30 | listOfNotNull(PyIgnoreExpressionQuickFix(data, node.text), replaceQuickFix) 31 | ) 32 | } 33 | 34 | override fun createTooltip(node: PyBinaryExpression, vararg params: String): String { 35 | val operatorText = node.extractOperatorText() ?: "" 36 | return params.singleOrNull()?.let { 37 | PyResourceBundle.message("deepbugs.python.binary.operator.inspection.warning.single", it, operatorText) 38 | } ?: PyResourceBundle.message("deepbugs.python.binary.operator.inspection.warning", operatorText) 39 | } 40 | 41 | override fun getDisplayName() = PyResourceBundle.message("deepbugs.python.binary.operator.inspection.display") 42 | override fun getShortName(): String = "PyDeepBugsBinOperator" 43 | } 44 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/inspections/PyDeepBugsSwappedArgsInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.inspections 2 | 3 | import com.intellij.codeInspection.ProblemDescriptor 4 | import com.jetbrains.python.psi.PyCallExpression 5 | import org.jetbrains.research.deepbugs.common.datatypes.Call 6 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 7 | import org.jetbrains.research.deepbugs.common.model.CommonModelStorage 8 | import org.jetbrains.research.deepbugs.python.PyResourceBundle 9 | import org.jetbrains.research.deepbugs.python.ide.inspections.base.PyDeepBugsCallExprInspection 10 | import org.jetbrains.research.deepbugs.python.ide.quickfixes.PyFlipFunctionArgumentsQuickFix 11 | import org.jetbrains.research.deepbugs.python.ide.quickfixes.PyIgnoreExpressionQuickFix 12 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 13 | 14 | class PyDeepBugsSwappedArgsInspection : PyDeepBugsCallExprInspection(2, 0.8f) { 15 | override val model: Perceptron? 16 | get() = CommonModelStorage.common.swappedArgsModel 17 | 18 | override fun skip(node: PyCallExpression): Boolean = node.arguments.size != requiredArgsNum 19 | 20 | override fun createProblemDescriptor(node: PyCallExpression, data: Call, onTheFly: Boolean): ProblemDescriptor = 21 | BugDescriptor(node, createTooltip(node), onTheFly, listOf( 22 | PyIgnoreExpressionQuickFix(data, node.text), 23 | PyFlipFunctionArgumentsQuickFix() 24 | )) 25 | 26 | override fun createTooltip(node: PyCallExpression, vararg params: String): String = 27 | PyResourceBundle.message("deepbugs.python.swapped.args.inspection.warning") 28 | 29 | override fun getDisplayName() = PyResourceBundle.message("deepbugs.python.swapped.args.inspection.display") 30 | override fun getShortName(): String = "PyDeepBugsSwappedArgs" 31 | } 32 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/inspections/base/PyDeepBugsBaseInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.inspections.base 2 | 3 | import com.intellij.codeInspection.* 4 | import com.jetbrains.python.inspections.PyInspection 5 | import com.jetbrains.python.inspections.PyInspectionVisitor 6 | import com.jetbrains.python.psi.PyElement 7 | import org.jetbrains.research.deepbugs.common.datatypes.DataType 8 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 9 | import org.jetbrains.research.deepbugs.common.ide.problem.BugDescriptor 10 | import org.jetbrains.research.deepbugs.python.PyDeepBugsConfig 11 | import org.jetbrains.research.deepbugs.python.ide.quickfixes.PyIgnoreExpressionQuickFix 12 | import org.jetbrains.research.keras.runner.nn.model.sequential.Perceptron 13 | 14 | abstract class PyDeepBugsBaseInspection(private val threshold: Float) : PyInspection() { 15 | protected abstract val model: Perceptron? 16 | 17 | protected open fun skip(node: T): Boolean = false 18 | 19 | protected open fun createProblemDescriptor(node: T, data: V, onTheFly: Boolean): ProblemDescriptor = 20 | BugDescriptor(node, createTooltip(node), onTheFly, listOf(PyIgnoreExpressionQuickFix(data, node.text))) 21 | 22 | protected abstract fun createTooltip(node: T, vararg params: String): String 23 | 24 | abstract inner class PyDeepBugsVisitor( 25 | holder: ProblemsHolder, 26 | session: LocalInspectionToolSession 27 | ) : PyInspectionVisitor(holder, session) { 28 | protected fun visit(node: T, collect: T.() -> V?) { 29 | if (skip(node)) return 30 | val data = node.collect() ?: return 31 | val vectorized = data.vectorize() 32 | DeepBugsCounterCollector.tokensMatched(holder?.project ?: return, shortName, matched = vectorized == null) 33 | val result = model?.predict(vectorized ?: return) ?: return 34 | analyzeInspected(result, node, data) 35 | } 36 | 37 | private fun analyzeInspected(result: Float, node: T, data: V) { 38 | if (!PyDeepBugsConfig.isProblem(result, threshold, data)) return 39 | holder?.registerProblem(createProblemDescriptor(node, data, holder!!.isOnTheFly)) 40 | DeepBugsCounterCollector.problemFound(holder?.project ?: return, shortName, result) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/inspections/base/PyDeepBugsBinExprInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.inspections.base 2 | 3 | import com.intellij.codeInspection.LocalInspectionToolSession 4 | import com.intellij.codeInspection.ProblemsHolder 5 | import com.jetbrains.python.psi.PyBinaryExpression 6 | import org.jetbrains.research.deepbugs.common.datatypes.BinOp 7 | import org.jetbrains.research.deepbugs.python.datatypes.collect 8 | 9 | abstract class PyDeepBugsBinExprInspection(threshold: Float) : PyDeepBugsBaseInspection(threshold) { 10 | override fun buildVisitor( 11 | holder: ProblemsHolder, 12 | isOnTheFly: Boolean, 13 | session: LocalInspectionToolSession 14 | ) = PyDeepBugsBinOpVisitor(holder, session) 15 | 16 | inner class PyDeepBugsBinOpVisitor(holder: ProblemsHolder, session: LocalInspectionToolSession) : PyDeepBugsVisitor(holder, session) { 17 | override fun visitPyBinaryExpression(node: PyBinaryExpression?) { 18 | visit(node ?: return) { node.collect() } 19 | super.visitPyBinaryExpression(node) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/inspections/base/PyDeepBugsCallExprInspection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.inspections.base 2 | 3 | import com.intellij.codeInspection.LocalInspectionToolSession 4 | import com.intellij.codeInspection.ProblemsHolder 5 | import com.intellij.psi.PsiElementVisitor 6 | import com.jetbrains.python.psi.PyCallExpression 7 | import org.jetbrains.research.deepbugs.common.datatypes.Call 8 | import org.jetbrains.research.deepbugs.python.datatypes.collect 9 | 10 | abstract class PyDeepBugsCallExprInspection( 11 | protected val requiredArgsNum: Int, threshold: Float 12 | ) : PyDeepBugsBaseInspection(threshold) { 13 | override fun buildVisitor( 14 | holder: ProblemsHolder, 15 | isOnTheFly: Boolean, 16 | session: LocalInspectionToolSession 17 | ): PsiElementVisitor = PyDeepBugsCallVisitor(holder, session) 18 | 19 | inner class PyDeepBugsCallVisitor( 20 | holder: ProblemsHolder, 21 | session: LocalInspectionToolSession 22 | ) : PyDeepBugsVisitor(holder, session) { 23 | override fun visitPyCallExpression(node: PyCallExpression?) { 24 | visit(node ?: return) { node.collect() } 25 | super.visitPyCallExpression(node) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/quickfixes/PyFlipFunctionArgumentsQuickFix.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.quickfixes 2 | 3 | import com.intellij.psi.PsiElement 4 | import com.jetbrains.python.psi.PyCallExpression 5 | import org.jetbrains.research.deepbugs.common.ide.quickfixes.FlipFunctionArgumentsQuickFix 6 | import org.jetbrains.research.deepbugs.python.PyResourceBundle 7 | 8 | class PyFlipFunctionArgumentsQuickFix : FlipFunctionArgumentsQuickFix() { 9 | override fun getFamilyName(): String = PyResourceBundle.message("deepbugs.python.flip.args.family") 10 | 11 | override fun PyCallExpression.toArguments(): Pair = Pair(arguments[0], arguments[1]) 12 | } 13 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/quickfixes/PyIgnoreExpressionQuickFix.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.quickfixes 2 | 3 | import com.intellij.codeInsight.intention.PriorityAction 4 | import com.intellij.codeInspection.LocalQuickFix 5 | import com.intellij.codeInspection.ProblemDescriptor 6 | import com.intellij.icons.AllIcons 7 | import com.intellij.openapi.command.undo.BasicUndoableAction 8 | import com.intellij.openapi.command.undo.UndoManager 9 | import com.intellij.openapi.project.Project 10 | import com.intellij.openapi.util.Iconable 11 | import org.jetbrains.research.deepbugs.common.datatypes.DataType 12 | import org.jetbrains.research.deepbugs.common.ide.fus.collectors.counter.DeepBugsCounterCollector 13 | import org.jetbrains.research.deepbugs.python.PyDeepBugsConfig 14 | import org.jetbrains.research.deepbugs.python.PyResourceBundle 15 | import javax.swing.Icon 16 | 17 | class PyIgnoreExpressionQuickFix(private val expr: DataType, private val displayText: String) : LocalQuickFix, Iconable, PriorityAction { 18 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) { 19 | val ignore = object : BasicUndoableAction(descriptor.psiElement?.containingFile?.virtualFile) { 20 | override fun redo() = PyDeepBugsConfig.ignoreExpression(expr) 21 | override fun undo() = PyDeepBugsConfig.considerExpression(expr) 22 | } 23 | ignore.redo() 24 | DeepBugsCounterCollector.checkDisabled(project, PyDeepBugsConfig.get().userDisabledChecks.size) 25 | UndoManager.getInstance(project).undoableActionPerformed(ignore) 26 | } 27 | 28 | override fun getIcon(flags: Int): Icon = AllIcons.Actions.Cancel 29 | override fun getPriority(): PriorityAction.Priority = PriorityAction.Priority.LOW 30 | 31 | override fun getFamilyName(): String = PyResourceBundle.message("deepbugs.python.ignore.family") 32 | override fun getName(): String = PyResourceBundle.message("deepbugs.python.ignore.quickfix", displayText) 33 | } 34 | -------------------------------------------------------------------------------- /py-plugin/src/main/kotlin/org/jetbrains/research/deepbugs/python/ide/ui/PyDeepBugsConfigurable.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python.ide.ui 2 | 3 | import com.intellij.openapi.components.service 4 | import org.jetbrains.research.deepbugs.common.DeepBugsConfig 5 | import org.jetbrains.research.deepbugs.common.ide.ui.DeepBugsConfigurable 6 | import org.jetbrains.research.deepbugs.python.PyDeepBugsConfig 7 | import org.jetbrains.research.deepbugs.python.PyResourceBundle 8 | 9 | class PyDeepBugsConfigurable : DeepBugsConfigurable( 10 | PyDeepBugsConfig.default, 11 | "PyPluginConfig", 12 | PyResourceBundle.message("deepbugs.python.display") 13 | ) { 14 | override fun getSettings(): DeepBugsConfig = service() 15 | } 16 | -------------------------------------------------------------------------------- /py-plugin/src/main/models/common/binOperandDetectionModel.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/common/binOperandDetectionModel.h5 -------------------------------------------------------------------------------- /py-plugin/src/main/models/common/binOperatorDetectionModel.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/common/binOperatorDetectionModel.h5 -------------------------------------------------------------------------------- /py-plugin/src/main/models/common/swappedArgsDetectionModel.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/common/swappedArgsDetectionModel.h5 -------------------------------------------------------------------------------- /py-plugin/src/main/models/nodeTypeToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/nodeTypeToVector.cbor -------------------------------------------------------------------------------- /py-plugin/src/main/models/operatorToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/operatorToVector.cbor -------------------------------------------------------------------------------- /py-plugin/src/main/models/tokenToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/tokenToVector.cbor -------------------------------------------------------------------------------- /py-plugin/src/main/models/typeToVector.cbor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JetBrains-Research/DeepBugsPlugin/8e9b2c0b070baef9bdcbf9159c0fec0ef357b7a7/py-plugin/src/main/models/typeToVector.cbor -------------------------------------------------------------------------------- /py-plugin/src/main/resources/DeepBugsPythonBundle.properties: -------------------------------------------------------------------------------- 1 | deepbugs.python.binary.operator.inspection.display=DeepBugs for Python: Possibly incorrect operator 2 | deepbugs.python.binary.operand.inspection.display=DeepBugs for Python: Possibly incorrect operand 3 | deepbugs.python.swapped.args.inspection.display=DeepBugs for Python: Possibly wrong order of function arguments 4 | deepbugs.python.binary.operator.inspection.warning=Possibly incorrect operator: “{0}” 5 | deepbugs.python.binary.operator.inspection.warning.single=Probably you meant “{0}” instead of “{1}” 6 | deepbugs.python.binary.operand.inspection.warning=Possibly incorrect operand: “{0}” or “{1}” 7 | deepbugs.python.swapped.args.inspection.warning=Possibly wrong order of function arguments 8 | deepbugs.python.ignore.family=DeepBugs for Python: Ignore expression 9 | deepbugs.python.flip.args.family=DeepBugs for Python: Fix order of arguments 10 | deepbugs.python.replace.operator.family=DeepBugs for Python: Replace operator 11 | deepbugs.python.display=DeepBugs for Python 12 | deepbugs.python.ignore.quickfix=Always ignore “{0}” 13 | deepbugs.python.group.name=Probable bugs 14 | -------------------------------------------------------------------------------- /py-plugin/src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | DeepBugs for Python 3 | DeepBugsPython 4 | JetBrains 5 | Finds potential bugs and code quality issues for Python using deep learning models.

7 | 8 |

Detects several types of bugs, including incorrect function arguments, incorrect comparison, and others, based on extracted code semantics.

9 | 10 |

Deep learning models are inspired by DeepBugs.

11 | 12 |

To configure, open Preferences/Settings | Tools | DeepBugs for Python.

13 | ]]>
14 | 15 | 0.5 17 | Update for 201.* builds 18 | 19 |

0.4

20 |
    21 |
  • Minor bug fixes
  • 22 |
23 | 24 |

0.3

25 |
    26 |
  • Significantly reduce plugin size
  • 27 |
  • Add several quick-fixes for detected bugs
  • 28 |
  • Fully rework settings UI and inspections tooltips
  • 29 |
  • A lot of bug fixes and stability improvements
  • 30 |
31 | 32 |

0.2

33 |
    34 |
  • Minor improvements
  • 35 |
36 | ]]> 37 |
38 | 39 | com.intellij.modules.lang 40 | com.intellij.modules.python 41 | 42 | 43 | 44 | 45 | 50 | 51 | 56 | 57 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | -------------------------------------------------------------------------------- /py-plugin/src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /py-plugin/src/main/resources/inspectionDescriptions/PyDeepBugsBinOperand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of binary operands (arguments of binary operations) 4 | 5 | 6 | -------------------------------------------------------------------------------- /py-plugin/src/main/resources/inspectionDescriptions/PyDeepBugsBinOperator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of binary operators 4 | 5 | 6 | -------------------------------------------------------------------------------- /py-plugin/src/main/resources/inspectionDescriptions/PyDeepBugsSwappedArgs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The inspection detects misuse of function arguments (specifically, their order) 4 | 5 | 6 | -------------------------------------------------------------------------------- /py-plugin/src/test/kotlin/org/jetbrains/research/deepbugs/python/DeepBugsTestBase.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python 2 | 3 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 4 | import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl 5 | import org.jetbrains.research.deepbugs.common.DeepBugsPlugin 6 | import org.jetbrains.research.deepbugs.python.ide.inspections.* 7 | import java.io.File 8 | 9 | abstract class DeepBugsTestBase : BasePlatformTestCase() { 10 | init { 11 | DeepBugsPlugin.setTestPlugin("DeepBugsPython") 12 | } 13 | 14 | override fun getTestDataPath(): String { 15 | return File("src/test/testData").canonicalPath 16 | } 17 | 18 | override fun setUp() { 19 | super.setUp() 20 | myFixture.enableInspections(*inspectionTools) 21 | (myFixture as? CodeInsightTestFixtureImpl)?.canChangeDocumentDuringHighlighting(true) 22 | } 23 | 24 | protected open fun runHighlightTestForFile(file: String) { 25 | myFixture.configureByFile(file) 26 | myFixture.checkHighlighting(true, false, false) 27 | } 28 | 29 | companion object { 30 | val inspectionTools by lazy { 31 | arrayOf( 32 | PyDeepBugsBinOperandInspection(), 33 | PyDeepBugsBinOperatorInspection(), 34 | PyDeepBugsSwappedArgsInspection() 35 | ) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /py-plugin/src/test/kotlin/org/jetbrains/research/deepbugs/python/PyDeepBugsTest.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.deepbugs.python 2 | 3 | class PyDeepBugsTest : DeepBugsTestBase() { 4 | fun `test bin operand`() { 5 | runHighlightTestForFile("testIncorrectBinOperandPy.py") 6 | } 7 | 8 | fun `test bin operator`() { 9 | runHighlightTestForFile("testIncorrectBinOperatorPy.py") 10 | } 11 | 12 | fun `test swapped arguments`() { 13 | runHighlightTestForFile("testSwappedArgumentsPy.py") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /py-plugin/src/test/testData/testIncorrectBinOperandPy.py: -------------------------------------------------------------------------------- 1 | a = 1 + 6 2 | b = 1 / 0 3 | -------------------------------------------------------------------------------- /py-plugin/src/test/testData/testIncorrectBinOperatorPy.py: -------------------------------------------------------------------------------- 1 | text = "123" 2 | string = "456" 3 | 4 | text / string 5 | text + string 6 | -------------------------------------------------------------------------------- /py-plugin/src/test/testData/testSwappedArgumentsPy.py: -------------------------------------------------------------------------------- 1 | def size(xx, yy): 2 | return xx, yy 3 | 4 | size(width, height) 5 | size(height, width) 6 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "deep-bugs" 2 | 3 | include(":common") 4 | include(":py-plugin") 5 | include(":js-plugin") 6 | include(":keras-runner") 7 | --------------------------------------------------------------------------------