├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── doc ├── install.png ├── instance_methods.png ├── object-sql-intellij-1.0.zip └── static_methods.png ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── com │ └── github │ └── braisdom │ └── objsql │ └── intellij │ ├── ModelMethodBuilder.java │ ├── ObjSqlImplicitUsageProvider.java │ ├── ObjSqlLightClassBuilder.java │ ├── ObjSqlLightMethodBuilder.java │ ├── ObjSqlPsiAugmentProvider.java │ ├── ObjSqlSourcePositionProvider.java │ ├── ObjsqlLightFieldBuilder.java │ ├── PersistenceMethodBuilder.java │ ├── PrimaryKeyBuilder.java │ ├── PsiAnnotationSearchUtil.java │ ├── PsiClassUtil.java │ ├── QueryMethodBuilder.java │ ├── RelationFieldBuilder.java │ ├── SetterGetterMethodBuilder.java │ ├── TableClassBuilder.java │ ├── WordUtil.java │ └── oo │ ├── OOComponent.java │ ├── OOHighlightVisitorImpl.java │ ├── OOMethods.java │ ├── OOResolver.java │ ├── PsiOOArrayAccessExpressionImpl.java │ ├── PsiOOBinaryExpressionImpl.java │ ├── PsiOOPolyadicExpressionImpl.java │ ├── PsiOOPrefixExpressionImpl.java │ └── Util.java └── resources └── META-INF └── plugin.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | 4 | # User-specific stuff 5 | .idea/**/workspace.xml 6 | .idea/**/tasks.xml 7 | .idea/**/usage.statistics.xml 8 | .idea/**/dictionaries 9 | .idea/**/shelf 10 | 11 | # Generated files 12 | .idea/**/contentModel.xml 13 | 14 | # Sensitive or high-churn files 15 | .idea/**/dataSources/ 16 | .idea/**/dataSources.ids 17 | .idea/**/dataSources.local.xml 18 | .idea/**/sqlDataSources.xml 19 | .idea/**/dynamic.xml 20 | .idea/**/uiDesigner.xml 21 | .idea/**/dbnavigator.xml 22 | 23 | # Gradle 24 | .idea/**/gradle.xml 25 | .idea/**/libraries 26 | .gradle 27 | 28 | # Gradle and Maven with auto-import 29 | # When using Gradle or Maven with auto-import, you should exclude module files, 30 | # since they will be recreated, and may cause churn. Uncomment if using 31 | # auto-import. 32 | # .idea/artifacts 33 | # .idea/compiler.xml 34 | # .idea/jarRepositories.xml 35 | # .idea/modules.xml 36 | # .idea/*.iml 37 | # .idea/modules 38 | # *.iml 39 | # *.ipr 40 | 41 | # CMake 42 | cmake-build-*/ 43 | 44 | # Mongo Explorer plugin 45 | .idea/**/mongoSettings.xml 46 | 47 | # File-based project format 48 | *.iws 49 | 50 | # IntelliJ 51 | out/ 52 | 53 | # mpeltonen/sbt-idea plugin 54 | .idea_modules/ 55 | 56 | # JIRA plugin 57 | atlassian-ide-plugin.xml 58 | 59 | # Cursive Clojure plugin 60 | .idea/replstate.xml 61 | 62 | # Crashlytics plugin (for Android Studio and IntelliJ) 63 | com_crashlytics_export_strings.xml 64 | crashlytics.properties 65 | crashlytics-build.properties 66 | fabric.properties 67 | 68 | # Editor-based Rest Client 69 | .idea/httpRequests 70 | 71 | # Android studio 3.1+ serialized cache file 72 | .idea/caches/build_file_checksums.ser 73 | /.idea/ 74 | /gradle/ 75 | /build/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ObjectiveSql IntelliJ Plugin 2 | Fill the generated elements for ObjectSql, and the plugin name of IntelliJ is "ObjectiveSql" 3 | 4 | ## Install from local 5 | 6 | Download [ObjectiveSql](./doc/object-sql-intellij-1.0.zip) and [Perference... -> Plugins -> Install Plugin from Disk... ] 7 | 8 | static_methods 9 | 10 | ## Static members example 11 | 12 | static_methods 13 | 14 | ## Instance members example 15 | 16 | instance_methods -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "org.jetbrains.intellij" version "0.6.1" 3 | } 4 | 5 | group 'com.github.braisdom' 6 | version '1.3.4' 7 | 8 | repositories { 9 | mavenLocal() 10 | maven { url 'http://dl.bintray.com/jetbrains/intellij-plugin-service' } 11 | maven { url 'https://jitpack.io' } 12 | mavenCentral() 13 | } 14 | 15 | dependencies { 16 | testCompile group: 'junit', name: 'junit', version: '4.12' 17 | } 18 | 19 | apply plugin: 'java' 20 | apply plugin: 'idea' 21 | idea { 22 | project { 23 | jdkName = '1.8' 24 | languageLevel = '1.8' 25 | } 26 | } 27 | 28 | apply plugin: 'java' 29 | compileJava { 30 | options.encoding = 'UTF-8' 31 | options.compilerArgs << "-Xlint:deprecation" 32 | } 33 | 34 | apply plugin: 'org.jetbrains.intellij' 35 | intellij { 36 | version = "2020.2" 37 | type = 'IC' 38 | updateSinceUntilBuild = false 39 | downloadSources = true 40 | plugins = ['java'] 41 | } 42 | 43 | patchPluginXml { 44 | changeNotes """ 45 |

1. Generating setter and getter methods for model who has annotation @DomainModel

46 |

2. Generating query and persistence methods for model who has annotation @DomainModel

47 |

3. Generating query method for field who has annotation @Queryable

48 |

4. Generating relation method for field who has annotation @Relation

49 |

...

""" 50 | } -------------------------------------------------------------------------------- /doc/install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braisdom/ObjectiveSql-IntelliJ-Plugin/1cde1897d21ae9dbcfaa1049707f588f22c3f809/doc/install.png -------------------------------------------------------------------------------- /doc/instance_methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braisdom/ObjectiveSql-IntelliJ-Plugin/1cde1897d21ae9dbcfaa1049707f588f22c3f809/doc/instance_methods.png -------------------------------------------------------------------------------- /doc/object-sql-intellij-1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braisdom/ObjectiveSql-IntelliJ-Plugin/1cde1897d21ae9dbcfaa1049707f588f22c3f809/doc/object-sql-intellij-1.0.zip -------------------------------------------------------------------------------- /doc/static_methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braisdom/ObjectiveSql-IntelliJ-Plugin/1cde1897d21ae9dbcfaa1049707f588f22c3f809/doc/static_methods.png -------------------------------------------------------------------------------- /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="" 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= 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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'object-sql-intellij' 2 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ModelMethodBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiModifier; 6 | import com.intellij.psi.PsiType; 7 | import com.intellij.psi.impl.light.LightFieldBuilder; 8 | 9 | import java.util.List; 10 | 11 | import static com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider.*; 12 | 13 | final class ModelMethodBuilder { 14 | 15 | static void buildField(PsiClass psiClass, List result) { 16 | buildTableName(psiClass, result); 17 | buildRawAttributes(psiClass, result); 18 | } 19 | 20 | static void buildMethod(PsiClass psiClass, List result) { 21 | buildGetRawAttributes(psiClass, result); 22 | buildGetRawAttribute(psiClass, result); 23 | } 24 | 25 | private static void buildRawAttributes(PsiClass psiClass, List result) { 26 | PsiType fieldType = createParameterType(psiClass.getProject(), 27 | "java.util.Map", "java.lang.String", "java.lang.Object"); 28 | ObjsqlLightFieldBuilder primaryBuilder = new ObjsqlLightFieldBuilder("rawAttributes", fieldType, psiClass); 29 | primaryBuilder.setNavigationElement(psiClass); 30 | primaryBuilder.setModifiers(PsiModifier.PRIVATE, PsiModifier.FINAL); 31 | primaryBuilder.setContainingClass(psiClass); 32 | 33 | result.add(primaryBuilder); 34 | } 35 | 36 | private static void buildTableName(PsiClass psiClass, List result) { 37 | PsiType fieldType = createParameterType(psiClass.getProject(), "java.lang.String"); 38 | ObjsqlLightFieldBuilder tableNameBuilder = new ObjsqlLightFieldBuilder("TABLE_NAME", fieldType, psiClass); 39 | tableNameBuilder.setModifiers(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL); 40 | tableNameBuilder.setContainingClass(psiClass); 41 | tableNameBuilder.setNavigationElement(tableNameBuilder); 42 | 43 | result.add(tableNameBuilder); 44 | } 45 | 46 | private static void buildGetRawAttributes(PsiClass psiClass, List result) { 47 | Project project = psiClass.getProject(); 48 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "getRawAttributes"); 49 | PsiType psiType = getProjectType("java.util.Map", project); 50 | methodBuilder.withMethodReturnType(psiType) 51 | .withContainingClass(psiClass) 52 | .withModifier(PsiModifier.PUBLIC, PsiModifier.FINAL); 53 | 54 | if(!checkMethodExists(psiClass, methodBuilder)) { 55 | result.add(methodBuilder); 56 | } 57 | } 58 | 59 | private static void buildGetRawAttribute(PsiClass psiClass, List result) { 60 | Project project = psiClass.getProject(); 61 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "getRawAttribute"); 62 | PsiType psiType = getProjectType("java.lang.Object", project); 63 | methodBuilder.withParameter("key", "java.lang.String") 64 | .withMethodReturnType(psiType) 65 | .withContainingClass(psiClass) 66 | .withModifier(PsiModifier.PUBLIC, PsiModifier.FINAL); 67 | 68 | if(!checkMethodExists(psiClass, methodBuilder)) { 69 | result.add(methodBuilder); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ObjSqlImplicitUsageProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.codeInsight.daemon.ImplicitUsageProvider; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiField; 7 | 8 | public class ObjSqlImplicitUsageProvider implements ImplicitUsageProvider { 9 | 10 | @Override 11 | public boolean isImplicitUsage(PsiElement element) { 12 | return isImplicitWrite(element) || isImplicitRead(element); 13 | } 14 | 15 | @Override 16 | public boolean isImplicitRead(PsiElement element) { 17 | return checkUsage(element); 18 | } 19 | 20 | @Override 21 | public boolean isImplicitWrite(PsiElement element) { 22 | return checkUsage(element); 23 | } 24 | 25 | private boolean checkUsage(PsiElement element) { 26 | if (element instanceof PsiField) { 27 | PsiClass psiClass = ((PsiField)element).getContainingClass(); 28 | return psiClass.hasAnnotation(ObjSqlPsiAugmentProvider.DOMAIN_MODEL_CLASSNAME); 29 | } 30 | return false; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ObjSqlLightClassBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.impl.light.LightPsiClassBuilder; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public class ObjSqlLightClassBuilder extends LightPsiClassBuilder { 8 | private final String myQualifiedName; 9 | 10 | public ObjSqlLightClassBuilder(@NotNull PsiElement context, 11 | @NotNull String simpleName, 12 | @NotNull String qualifiedName) { 13 | super(context, simpleName); 14 | myQualifiedName = qualifiedName; 15 | } 16 | 17 | @Override 18 | public boolean equals(Object o) { 19 | if (this == o) { 20 | return true; 21 | } 22 | 23 | if (o == null || getClass() != o.getClass()) { 24 | return false; 25 | } 26 | 27 | ObjSqlLightClassBuilder that = (ObjSqlLightClassBuilder) o; 28 | 29 | return myQualifiedName.equals(that.myQualifiedName); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return myQualifiedName.hashCode(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ObjSqlLightMethodBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.ide.util.PsiNavigationSupport; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.openapi.util.TextRange; 6 | import com.intellij.pom.Navigatable; 7 | import com.intellij.psi.*; 8 | import com.intellij.psi.impl.CheckUtil; 9 | import com.intellij.psi.impl.light.LightMethodBuilder; 10 | import com.intellij.psi.impl.light.LightModifierList; 11 | import com.intellij.psi.impl.light.LightTypeParameterListBuilder; 12 | import com.intellij.util.IncorrectOperationException; 13 | import org.jetbrains.annotations.NonNls; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.Collection; 18 | import java.util.Objects; 19 | 20 | public class ObjSqlLightMethodBuilder extends LightMethodBuilder { 21 | private PsiMethod myMethod; 22 | private ASTNode myASTNode; 23 | 24 | public ObjSqlLightMethodBuilder(@NotNull PsiManager manager, @NotNull String name) { 25 | super(manager, name); 26 | } 27 | 28 | public ObjSqlLightMethodBuilder withModifier(@PsiModifier.ModifierConstant @NotNull @NonNls String modifier) { 29 | addModifier(modifier); 30 | return this; 31 | } 32 | 33 | public ObjSqlLightMethodBuilder withModifier(@PsiModifier.ModifierConstant @NotNull @NonNls String... modifiers) { 34 | for (String modifier : modifiers) { 35 | addModifier(modifier); 36 | } 37 | return this; 38 | } 39 | 40 | public ObjSqlLightMethodBuilder withMethodReturnType(PsiType returnType) { 41 | setMethodReturnType(returnType); 42 | return this; 43 | } 44 | 45 | @Override 46 | public void navigate(boolean requestFocus) { 47 | PsiClassUtil.navigate(getProject(), getContainingClass(), (psiClasses -> { 48 | for (PsiClass psiClass : psiClasses) { 49 | PsiMethod[] psiMethods = psiClass.getMethods(); 50 | for (PsiMethod psiMethod : psiMethods) { 51 | if (getName().equals(psiMethod.getName())) { 52 | Navigatable descriptor = PsiNavigationSupport.getInstance().getDescriptor(psiMethod); 53 | if (descriptor != null) { 54 | descriptor.navigate(requestFocus); 55 | return true; 56 | } 57 | } 58 | } 59 | } 60 | return false; 61 | })); 62 | } 63 | 64 | @Override 65 | public boolean canNavigate() { 66 | return PsiNavigationSupport.getInstance().canNavigate(this); 67 | } 68 | 69 | @Override 70 | public boolean canNavigateToSource() { 71 | return false; 72 | } 73 | 74 | @Override 75 | public LightMethodBuilder setMethodReturnType(PsiType returnType) { 76 | return super.setMethodReturnType(returnType); 77 | } 78 | 79 | @Override 80 | public LightMethodBuilder setMethodReturnType(String returnType) { 81 | return super.setMethodReturnType(returnType); 82 | } 83 | 84 | public ObjSqlLightMethodBuilder withParameter(@NotNull String name, @NotNull PsiType type) { 85 | addParameter(name, type); 86 | return this; 87 | } 88 | 89 | public ObjSqlLightMethodBuilder withParameter(@NotNull String name, @NotNull String type) { 90 | addParameter(name, type); 91 | return this; 92 | } 93 | 94 | public ObjSqlLightMethodBuilder withParameter(@NotNull String name, @NotNull PsiType type, boolean isVarArgs) { 95 | addParameter(name, type, isVarArgs); 96 | return this; 97 | } 98 | 99 | public ObjSqlLightMethodBuilder withParameter(@NotNull String name, @NotNull String type, boolean isVarArgs) { 100 | addParameter(name, JavaPsiFacade.getElementFactory(getProject()).createTypeFromText(type, this), isVarArgs); 101 | return this; 102 | } 103 | 104 | public ObjSqlLightMethodBuilder withException(@NotNull PsiClassType type) { 105 | addException(type); 106 | return this; 107 | } 108 | 109 | public ObjSqlLightMethodBuilder withContainingClass(@NotNull PsiClass containingClass) { 110 | setContainingClass(containingClass); 111 | return this; 112 | } 113 | 114 | // add Parameter as is, without wrapping with LightTypeParameter 115 | @Override 116 | public LightMethodBuilder addTypeParameter(PsiTypeParameter parameter) { 117 | ((LightTypeParameterListBuilder) getTypeParameterList()).addParameter(parameter); 118 | return this; 119 | } 120 | 121 | @Override 122 | public PsiElement getParent() { 123 | PsiElement result = super.getParent(); 124 | result = null != result ? result : getContainingClass(); 125 | return result; 126 | } 127 | 128 | @Nullable 129 | @Override 130 | public PsiFile getContainingFile() { 131 | PsiClass containingClass = getContainingClass(); 132 | return containingClass != null ? containingClass.getContainingFile() : null; 133 | } 134 | 135 | @Override 136 | public String getText() { 137 | ASTNode node = getNode(); 138 | if (null != node) { 139 | return node.getText(); 140 | } 141 | return ""; 142 | } 143 | 144 | @Override 145 | public ASTNode getNode() { 146 | if (null == myASTNode) { 147 | final PsiElement myPsiMethod = getOrCreateMyPsiMethod(); 148 | myASTNode = null == myPsiMethod ? null : myPsiMethod.getNode(); 149 | } 150 | return myASTNode; 151 | } 152 | 153 | @Override 154 | public TextRange getTextRange() { 155 | TextRange r = super.getTextRange(); 156 | return r == null ? TextRange.EMPTY_RANGE : r; 157 | } 158 | 159 | private String getAllModifierProperties(LightModifierList modifierList) { 160 | final StringBuilder builder = new StringBuilder(); 161 | for (String modifier : modifierList.getModifiers()) { 162 | if (!PsiModifier.PACKAGE_LOCAL.equals(modifier)) { 163 | builder.append(modifier).append(' '); 164 | } 165 | } 166 | return builder.toString(); 167 | } 168 | 169 | private PsiMethod rebuildMethodFromString() { 170 | PsiMethod result; 171 | try { 172 | final StringBuilder methodTextDeclaration = new StringBuilder(); 173 | methodTextDeclaration.append(getAllModifierProperties((LightModifierList) getModifierList())); 174 | PsiType returnType = getReturnType(); 175 | if (null != returnType && returnType.isValid()) { 176 | methodTextDeclaration.append(returnType.getCanonicalText()).append(' '); 177 | } 178 | methodTextDeclaration.append(getName()); 179 | methodTextDeclaration.append('('); 180 | if (getParameterList().getParametersCount() > 0) { 181 | for (PsiParameter parameter : getParameterList().getParameters()) { 182 | methodTextDeclaration.append(parameter.getType().getCanonicalText()).append(' ').append(parameter.getName()).append(','); 183 | } 184 | methodTextDeclaration.deleteCharAt(methodTextDeclaration.length() - 1); 185 | } 186 | methodTextDeclaration.append(')'); 187 | methodTextDeclaration.append('{').append(" ").append('}'); 188 | 189 | final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); 190 | 191 | result = elementFactory.createMethodFromText(methodTextDeclaration.toString(), getContainingClass()); 192 | if (null != getBody()) { 193 | result.getBody().replace(getBody()); 194 | } 195 | } catch (Exception ex) { 196 | result = null; 197 | } 198 | return result; 199 | } 200 | 201 | @Override 202 | public PsiElement copy() { 203 | final PsiElement myPsiMethod = getOrCreateMyPsiMethod(); 204 | return null == myPsiMethod ? null : myPsiMethod.copy(); 205 | } 206 | 207 | private PsiElement getOrCreateMyPsiMethod() { 208 | if (null == myMethod) { 209 | myMethod = rebuildMethodFromString(); 210 | } 211 | return myMethod; 212 | } 213 | 214 | @NotNull 215 | @Override 216 | public PsiElement[] getChildren() { 217 | final PsiElement myPsiMethod = getOrCreateMyPsiMethod(); 218 | return null == myPsiMethod ? PsiElement.EMPTY_ARRAY : myPsiMethod.getChildren(); 219 | } 220 | 221 | @Override 222 | public String toString() { 223 | return getClass().getSimpleName() + "#" + getName(); 224 | } 225 | 226 | @Override 227 | public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException { 228 | // just add new element to the containing class 229 | final PsiClass containingClass = getContainingClass(); 230 | if (null != containingClass) { 231 | CheckUtil.checkWritable(containingClass); 232 | return containingClass.add(newElement); 233 | } 234 | return null; 235 | } 236 | 237 | @Override 238 | public boolean equals(Object o) { 239 | if (this == o) { 240 | return true; 241 | } 242 | 243 | if (!(o instanceof PsiMethod)) { 244 | return false; 245 | } 246 | 247 | PsiMethod that = (PsiMethod) o; 248 | if (!getName().equals(that.getName())) { 249 | return false; 250 | } 251 | if (isConstructor() != that.isConstructor()) { 252 | return false; 253 | } 254 | final PsiClass containingClass = getContainingClass(); 255 | final PsiClass thatContainingClass = that.getContainingClass(); 256 | if (containingClass != null ? !containingClass.equals(thatContainingClass) : thatContainingClass != null) { 257 | return false; 258 | } 259 | if (!getModifierList().equals(that.getModifierList())) { 260 | return false; 261 | } 262 | if (!getParameterList().equals(that.getParameterList())) { 263 | return false; 264 | } 265 | return Objects.equals(getReturnType().getPresentableText(), that.getReturnType().getPresentableText()); 266 | } 267 | 268 | @Override 269 | public int hashCode() { 270 | // should be constant because of RenameJavaMethodProcessor#renameElement and fixNameCollisionsWithInnerClassMethod(...) 271 | return 1; 272 | } 273 | 274 | @Override 275 | public void delete() throws IncorrectOperationException { 276 | // simple do nothing 277 | } 278 | 279 | @Override 280 | public void checkDelete() throws IncorrectOperationException { 281 | // simple do nothing 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ObjSqlPsiAugmentProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.RecursionGuard; 5 | import com.intellij.openapi.util.RecursionManager; 6 | import com.intellij.psi.*; 7 | import com.intellij.psi.augment.PsiAugmentProvider; 8 | import com.intellij.psi.impl.source.PsiExtensibleClass; 9 | import com.intellij.psi.search.GlobalSearchScope; 10 | import com.intellij.psi.util.CachedValueProvider; 11 | import com.intellij.psi.util.CachedValuesManager; 12 | import com.intellij.psi.util.PsiModificationTracker; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.Collections; 19 | import java.util.List; 20 | 21 | public class ObjSqlPsiAugmentProvider extends PsiAugmentProvider { 22 | 23 | public static final String DOMAIN_MODEL_CLASSNAME = "com.github.braisdom.objsql.annotations.DomainModel"; 24 | 25 | private static final List LANG_PRIMARY_TYPES = Arrays.asList(new String[]{"Long", "Integer", "String", "Short"}); 26 | 27 | @NotNull 28 | @Override 29 | protected List getAugments(@NotNull PsiElement element, @NotNull Class type, @Nullable String nameHint) { 30 | final List result = Collections.emptyList(); 31 | 32 | if ((type != PsiClass.class && type != PsiField.class && type != PsiMethod.class) 33 | || !(element instanceof PsiExtensibleClass)) { 34 | return result; 35 | } 36 | 37 | final PsiClass psiClass = (PsiClass) element; 38 | if (psiClass.isAnnotationType() || psiClass.isInterface()) { 39 | return result; 40 | } 41 | 42 | PsiAnnotation psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiClass, DOMAIN_MODEL_CLASSNAME); 43 | if (psiAnnotation == null) 44 | return result; 45 | 46 | final List cachedValue; 47 | if (type == PsiMethod.class) 48 | cachedValue = CachedValuesManager.getCachedValue(element, new MethodCachedValueProvider<>(type, psiClass)); 49 | else if (type == PsiField.class) 50 | cachedValue = CachedValuesManager.getCachedValue(element, new FieldCachedValueProvider<>(type, psiClass)); 51 | else if (type == PsiClass.class) 52 | cachedValue = CachedValuesManager.getCachedValue(element, new ClassCachedValueProvider<>(type, psiClass)); 53 | else return result; 54 | 55 | return null != cachedValue ? cachedValue : result; 56 | } 57 | 58 | private static class FieldCachedValueProvider extends ObjSqlCachedValueProvider { 59 | private static final RecursionGuard ourGuard = RecursionManager.createGuard("objsql.augment.field"); 60 | 61 | FieldCachedValueProvider(Class type, PsiClass psiClass) { 62 | super(type, psiClass, ourGuard); 63 | } 64 | } 65 | 66 | private static class MethodCachedValueProvider extends ObjSqlCachedValueProvider { 67 | private static final RecursionGuard ourGuard = RecursionManager.createGuard("objsql.augment.method"); 68 | 69 | MethodCachedValueProvider(Class type, PsiClass psiClass) { 70 | super(type, psiClass, ourGuard); 71 | } 72 | } 73 | 74 | private static class ClassCachedValueProvider extends ObjSqlCachedValueProvider { 75 | private static final RecursionGuard ourGuard = RecursionManager.createGuard("objsql.augment.class"); 76 | 77 | ClassCachedValueProvider(Class type, PsiClass psiClass) { 78 | super(type, psiClass, ourGuard); 79 | } 80 | } 81 | 82 | private abstract static class ObjSqlCachedValueProvider implements CachedValueProvider> { 83 | private final Class type; 84 | private final PsiClass psiClass; 85 | private final RecursionGuard recursionGuard; 86 | 87 | ObjSqlCachedValueProvider(Class type, PsiClass psiClass, RecursionGuard recursionGuard) { 88 | this.type = type; 89 | this.psiClass = psiClass; 90 | this.recursionGuard = recursionGuard; 91 | } 92 | 93 | @Override 94 | public Result> compute() { 95 | return (Result>) recursionGuard.doPreventingRecursion(psiClass, true, () -> { 96 | final List result = new ArrayList<>(); 97 | 98 | if (type == PsiMethod.class) { 99 | SetterGetterMethodBuilder.buildMethod(psiClass, result); 100 | PrimaryKeyBuilder.buildMethod(psiClass, result); 101 | PrimaryKeyBuilder.buildQueryByPrimaryKeyMethod(psiClass, result); 102 | QueryMethodBuilder.buildMethod(psiClass, result); 103 | PersistenceMethodBuilder.buildMethod(psiClass, result); 104 | ModelMethodBuilder.buildMethod(psiClass, result); 105 | TableClassBuilder.buildMethod(psiClass, result); 106 | } else if (type == PsiField.class) { 107 | RelationFieldBuilder.buildField(psiClass, result); 108 | PrimaryKeyBuilder.buildField(psiClass, result); 109 | ModelMethodBuilder.buildField(psiClass, result); 110 | } else if (type == PsiClass.class) { 111 | TableClassBuilder.buildClass(psiClass, result); 112 | } 113 | 114 | return Result.create(result, PsiModificationTracker.MODIFICATION_COUNT); 115 | }); 116 | } 117 | } 118 | 119 | static PsiField getPrimaryKeyField(PsiClass psiClass) { 120 | PsiField[] fields = psiClass.getAllFields(); 121 | for (PsiField field : fields) { 122 | if (field.getAnnotation("com.github.braisdom.objsql.annotations.PrimaryKey") != null) { 123 | return field; 124 | } 125 | } 126 | return null; 127 | } 128 | 129 | static String getPrimaryName(PsiClass psiClass) { 130 | PsiField psiField = getPrimaryKeyField(psiClass); 131 | if (psiField == null) { 132 | PsiAnnotation annotation = psiClass.getAnnotation(DOMAIN_MODEL_CLASSNAME); 133 | if (annotation == null) 134 | return "id"; 135 | else { 136 | PsiAnnotationMemberValue annotationMemberValue = annotation 137 | .findAttributeValue("primaryFieldName"); 138 | if (annotationMemberValue != null) 139 | return annotationMemberValue.getText().replaceAll("^\"|\"$", ""); 140 | else return null; 141 | } 142 | } else { 143 | return psiField.getName(); 144 | } 145 | } 146 | 147 | static PsiType getPrimaryType(PsiClass psiClass) { 148 | PsiField psiField = getPrimaryKeyField(psiClass); 149 | if (psiField == null) { 150 | Project project = psiClass.getProject(); 151 | String rawPrimaryTypeName = "Integer"; 152 | PsiAnnotation annotation = psiClass.getAnnotation(DOMAIN_MODEL_CLASSNAME); 153 | if (annotation != null) { 154 | PsiAnnotationMemberValue annotationMemberValue = annotation.findAttributeValue("primaryClass"); 155 | if (annotationMemberValue != null) 156 | rawPrimaryTypeName = annotationMemberValue.getText(); 157 | String[] rawPrimaryTypePart = rawPrimaryTypeName.split("\\."); 158 | String primaryTypeName = String.join(".", 159 | Arrays.copyOfRange(rawPrimaryTypePart, 0, rawPrimaryTypePart.length - 1)); 160 | if (LANG_PRIMARY_TYPES.contains(primaryTypeName)) 161 | primaryTypeName = String.format("java.lang.%s", primaryTypeName); 162 | 163 | return PsiType.getTypeByName(primaryTypeName, project, GlobalSearchScope.allScope(project)); 164 | } else { 165 | return PsiType.getTypeByName("java.lang.Long", project, GlobalSearchScope.allScope(project)); 166 | } 167 | } else { 168 | return psiField.getType(); 169 | } 170 | } 171 | 172 | static PsiType getProjectType(String qName, Project project) { 173 | return PsiType.getTypeByName(qName, 174 | project, GlobalSearchScope.allScope(project)); 175 | } 176 | 177 | static boolean hasType(String qName, Project project) { 178 | return PsiType.getTypeByName(qName, 179 | project, GlobalSearchScope.allScope(project)).resolve() != null; 180 | } 181 | 182 | static PsiType createParameterType(Project project, String qName, String... parameters) { 183 | return createParameterType(project, (PsiClassType) getProjectType(qName, project), parameters); 184 | } 185 | 186 | static PsiType createParameterType(Project project, PsiClassType classType, String... parameters) { 187 | PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); 188 | PsiClass psiClass = classType.resolve(); 189 | if (psiClass != null && psiClass.getTypeParameters() != null && 190 | psiClass.getTypeParameters().length == parameters.length) { 191 | List psiTypes = new ArrayList<>(); 192 | for (String parameter : parameters) 193 | psiTypes.add(getProjectType(parameter, project)); 194 | return factory.createType(classType.resolve(), psiTypes.toArray(new PsiType[]{})); 195 | } else return factory.createType(classType.resolve()); 196 | } 197 | 198 | static boolean checkMethodExists(PsiClass psiClass, PsiMethod psiMethod) { 199 | PsiMethod[] methods = psiClass.findMethodsByName(psiMethod.getName(), true); 200 | for (PsiMethod method : methods) { 201 | if(!(method instanceof ObjSqlLightMethodBuilder)) { 202 | PsiParameterList psiParameterList1 = method.getParameterList(); 203 | PsiParameterList psiParameterList2 = psiMethod.getParameterList(); 204 | 205 | if (psiParameterList1.isEmpty() && psiParameterList2.isEmpty()) { 206 | return true; 207 | } else if (psiParameterList1.getParametersCount() == psiParameterList2.getParametersCount()) { 208 | int sameCount = 0; 209 | int parameterLength = psiParameterList1.getParameters().length; 210 | PsiParameter[] psiElements1 = psiParameterList1.getParameters(); 211 | PsiParameter[] psiElements2 = psiParameterList2.getParameters(); 212 | 213 | for (int i = 0; i < parameterLength; i++) { 214 | if (psiElements1[i].getType().equals(psiElements2[i].getType())) { 215 | sameCount++; 216 | } 217 | } 218 | if (parameterLength == sameCount) { 219 | return true; 220 | } 221 | } 222 | } 223 | } 224 | return false; 225 | } 226 | 227 | } 228 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ObjSqlSourcePositionProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.debugger.SourcePosition; 4 | import com.intellij.debugger.engine.PositionManagerImpl; 5 | import com.intellij.debugger.engine.SourcePositionProvider; 6 | import com.intellij.debugger.impl.DebuggerContextImpl; 7 | import com.intellij.debugger.ui.tree.NodeDescriptor; 8 | import com.intellij.openapi.compiler.CompilerPaths; 9 | import com.intellij.openapi.editor.Editor; 10 | import com.intellij.openapi.module.ModuleManager; 11 | import com.intellij.openapi.project.Project; 12 | import com.intellij.openapi.vfs.PlatformVirtualFileManager; 13 | import com.intellij.openapi.vfs.VirtualFile; 14 | import com.intellij.psi.PsiElement; 15 | import com.intellij.psi.PsiFile; 16 | import com.intellij.psi.PsiJavaFile; 17 | import com.intellij.psi.util.PsiUtil; 18 | import org.jetbrains.annotations.NotNull; 19 | import org.jetbrains.annotations.Nullable; 20 | 21 | public class ObjSqlSourcePositionProvider extends SourcePositionProvider { 22 | @Override 23 | protected @Nullable SourcePosition computeSourcePosition(@NotNull NodeDescriptor descriptor, 24 | @NotNull Project project, 25 | @NotNull DebuggerContextImpl context, 26 | boolean nearest) { 27 | return new ObjSqlSourcePosition(project, context.getSourcePosition(), 1); 28 | } 29 | 30 | private class ObjSqlSourcePosition extends PositionManagerImpl.JavaSourcePosition { 31 | 32 | private final Project project; 33 | 34 | public ObjSqlSourcePosition(Project project, SourcePosition delegate, int lambdaOrdinal) { 35 | super(delegate, lambdaOrdinal); 36 | this.project = project; 37 | } 38 | 39 | @Override 40 | public void navigate(boolean requestFocus) { 41 | super.navigate(requestFocus); 42 | } 43 | 44 | @Override 45 | public boolean canNavigateToSource() { 46 | return super.canNavigateToSource(); 47 | } 48 | 49 | @Override 50 | public SourcePosition mapDelegate(SourcePosition original) { 51 | return super.mapDelegate(original); 52 | } 53 | 54 | @Override 55 | public Editor openEditor(boolean requestFocus) { 56 | return super.openEditor(requestFocus); 57 | } 58 | 59 | @Override 60 | public @NotNull PsiFile getFile() { 61 | String[] outputPaths = CompilerPaths.getOutputPaths(ModuleManager.getInstance(project).getModules()); 62 | String classFileName = "Demo.class"; 63 | String fullClassFileName = String.format("file://%s/%s", outputPaths[0], classFileName); 64 | VirtualFile virtualFile = PlatformVirtualFileManager.getInstance().findFileByUrl(fullClassFileName); 65 | PsiJavaFile psiJavaFile = (PsiJavaFile) PsiUtil.getPsiFile(project, virtualFile); 66 | return psiJavaFile; 67 | } 68 | 69 | @Override 70 | public PsiElement getElementAt() { 71 | return super.getElementAt(); 72 | } 73 | 74 | @Override 75 | public int getLine() { 76 | return super.getLine(); 77 | } 78 | 79 | @Override 80 | public boolean canNavigate() { 81 | return super.canNavigate(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/ObjsqlLightFieldBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.ide.util.PsiNavigationSupport; 4 | import com.intellij.pom.Navigatable; 5 | import com.intellij.psi.*; 6 | import com.intellij.psi.impl.light.LightFieldBuilder; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class ObjsqlLightFieldBuilder extends LightFieldBuilder { 10 | 11 | public ObjsqlLightFieldBuilder(@NotNull String name, @NotNull PsiType type, @NotNull PsiElement navigationElement) { 12 | super(name, type, navigationElement); 13 | } 14 | 15 | @Override 16 | public void navigate(boolean requestFocus) { 17 | PsiClassUtil.navigate(getProject(), getContainingClass(), (psiClasses -> { 18 | for (PsiClass psiClass : psiClasses) { 19 | PsiField[] psiFields = psiClass.getFields(); 20 | for (PsiField psiField : psiFields) { 21 | if (getName().equals(psiField.getName())) { 22 | Navigatable descriptor = PsiNavigationSupport.getInstance().getDescriptor(psiField); 23 | if (descriptor != null) { 24 | descriptor.navigate(requestFocus); 25 | return true; 26 | } 27 | } 28 | } 29 | } 30 | return false; 31 | })); 32 | } 33 | 34 | @Override 35 | public boolean canNavigate() { 36 | return PsiNavigationSupport.getInstance().canNavigate(this); 37 | } 38 | 39 | @Override 40 | public boolean canNavigateToSource() { 41 | return canNavigate(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/PersistenceMethodBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiClassType; 6 | import com.intellij.psi.PsiModifier; 7 | import com.intellij.psi.PsiType; 8 | import com.intellij.psi.search.GlobalSearchScope; 9 | 10 | import java.util.List; 11 | 12 | import static com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider.*; 13 | 14 | final class PersistenceMethodBuilder { 15 | 16 | static void buildMethod(PsiClass psiClass, List result) { 17 | buildCreatePersistence(psiClass.getProject(), psiClass, result); 18 | buildCreate(psiClass.getProject(), psiClass, result); 19 | buildCreateArray(psiClass.getProject(), psiClass, result); 20 | buildUpdate(psiClass.getProject(), psiClass, result); 21 | buildUpdate2(psiClass.getProject(), psiClass, result); 22 | buildDestroy(psiClass.getProject(), psiClass, result); 23 | buildDestroy2(psiClass.getProject(), psiClass, result); 24 | buildSave(psiClass.getProject(), psiClass, result); 25 | buildValidate(psiClass.getProject(), psiClass, result); 26 | buildExecute(psiClass.getProject(), psiClass, result); 27 | buildNewInstanceFrom(psiClass.getProject(), psiClass, result); 28 | buildNewInstance3From(psiClass.getProject(), psiClass, result); 29 | } 30 | 31 | private static void buildCreatePersistence(Project project, PsiClass psiClass, List result) { 32 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), 33 | "createPersistence"); 34 | PsiType psiType = getProjectType("com.github.braisdom.objsql.Persistence", project); 35 | methodBuilder.withMethodReturnType(psiType) 36 | .withContainingClass(psiClass) 37 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 38 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 39 | 40 | if(!checkMethodExists(psiClass, methodBuilder)) 41 | result.add(methodBuilder); 42 | } 43 | 44 | private static void buildCreate(Project project, PsiClass psiClass, List result) { 45 | ObjSqlLightMethodBuilder createBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "create"); 46 | PsiType psiType = getProjectType(psiClass.getQualifiedName(), project); 47 | createBuilder.withParameter("dirtyObject", getProjectType(psiClass.getQualifiedName(), project)) 48 | .withParameter("skipValidation", PsiType.BOOLEAN) 49 | .withMethodReturnType(psiType) 50 | .withContainingClass(psiClass) 51 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 52 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 53 | 54 | if(!checkMethodExists(psiClass, createBuilder)) 55 | result.add(createBuilder); 56 | } 57 | 58 | private static void buildCreateArray(Project project, PsiClass psiClass, List result) { 59 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "create"); 60 | methodBuilder.withParameter("dirtyObjects", getProjectType(psiClass.getQualifiedName(), project).createArrayType()) 61 | .withParameter("skipValidation", PsiType.BOOLEAN) 62 | .withMethodReturnType(PsiType.INT.createArrayType()) 63 | .withContainingClass(psiClass) 64 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 65 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 66 | 67 | if(!checkMethodExists(psiClass, methodBuilder)) 68 | result.add(methodBuilder); 69 | } 70 | 71 | private static void buildValidate(Project project, PsiClass psiClass, List result) { 72 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "validate"); 73 | PsiType psiType = getProjectType("com.github.braisdom.objsql.Validator.Violation", project); 74 | methodBuilder.withMethodReturnType(psiType.createArrayType()) 75 | .withContainingClass(psiClass) 76 | .withModifier(PsiModifier.PUBLIC, PsiModifier.FINAL); 77 | 78 | if(!checkMethodExists(psiClass, methodBuilder)) 79 | result.add(methodBuilder); 80 | } 81 | 82 | private static void buildSave(Project project, PsiClass psiClass, List result) { 83 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "save"); 84 | methodBuilder.withParameter("skipValidation", PsiType.BOOLEAN) 85 | .withMethodReturnType(getProjectType(psiClass.getQualifiedName(), project)) 86 | .withContainingClass(psiClass) 87 | .withModifier(PsiModifier.PUBLIC, PsiModifier.FINAL) 88 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 89 | 90 | if(!checkMethodExists(psiClass, methodBuilder)) 91 | result.add(methodBuilder); 92 | } 93 | 94 | private static void buildUpdate(Project project, PsiClass psiClass, List result) { 95 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "update"); 96 | PsiType primaryType = getPrimaryType(psiClass); 97 | String primaryKeyName = getPrimaryName(psiClass); 98 | methodBuilder 99 | .withParameter(primaryKeyName, primaryType) 100 | .withParameter("dirtyObject", getProjectType(psiClass.getQualifiedName(), project)) 101 | .withParameter("skipValidation", PsiType.BOOLEAN) 102 | .withMethodReturnType(getProjectType(psiClass.getQualifiedName(), project)) 103 | .withContainingClass(psiClass) 104 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 105 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 106 | 107 | if(!checkMethodExists(psiClass, methodBuilder)) 108 | result.add(methodBuilder); 109 | } 110 | 111 | private static void buildUpdate2(Project project, PsiClass psiClass, List result) { 112 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "update"); 113 | methodBuilder 114 | .withParameter("updates", getProjectType("java.lang.String", project)) 115 | .withParameter("predicates", getProjectType("java.lang.String", project)) 116 | .withParameter("args", "java.lang.Object", true) 117 | .withMethodReturnType(PsiType.INT) 118 | .withContainingClass(psiClass) 119 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 120 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 121 | 122 | if(!checkMethodExists(psiClass, methodBuilder)) 123 | result.add(methodBuilder); 124 | } 125 | 126 | private static void buildDestroy(Project project, PsiClass psiClass, List result) { 127 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "destroy"); 128 | PsiType primaryType = getPrimaryType(psiClass); 129 | String primaryKeyName = getPrimaryName(psiClass); 130 | methodBuilder 131 | .withParameter(primaryKeyName, primaryType) 132 | .withMethodReturnType(PsiType.INT) 133 | .withContainingClass(psiClass) 134 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 135 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 136 | 137 | if(!checkMethodExists(psiClass, methodBuilder)) 138 | result.add(methodBuilder); 139 | } 140 | 141 | private static void buildDestroy2(Project project, PsiClass psiClass, List result) { 142 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "destroy"); 143 | methodBuilder 144 | .withParameter("predicates", getProjectType("java.lang.String", project)) 145 | .withParameter("args", "java.lang.Object", true) 146 | .withMethodReturnType(PsiType.INT) 147 | .withContainingClass(psiClass) 148 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 149 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 150 | 151 | if(!checkMethodExists(psiClass, methodBuilder)) 152 | result.add(methodBuilder); 153 | } 154 | 155 | private static void buildExecute(Project project, PsiClass psiClass, List result) { 156 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "execute"); 157 | methodBuilder 158 | .withParameter("sql", getProjectType("java.lang.String", project)) 159 | .withParameter("args", getProjectType("java.lang.Object", project), true) 160 | .withMethodReturnType(PsiType.INT) 161 | .withContainingClass(psiClass) 162 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 163 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 164 | 165 | if(!checkMethodExists(psiClass, methodBuilder)) 166 | result.add(methodBuilder); 167 | } 168 | 169 | private static void buildNewInstanceFrom(Project project, PsiClass psiClass, List result) { 170 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "newInstanceFrom"); 171 | methodBuilder 172 | .withParameter("properties", getProjectType("java.util.Map", project)) 173 | .withParameter("underLine", PsiType.BOOLEAN) 174 | .withMethodReturnType(getProjectType(psiClass.getQualifiedName(), project)) 175 | .withContainingClass(psiClass) 176 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL); 177 | 178 | if(!checkMethodExists(psiClass, methodBuilder)) 179 | result.add(methodBuilder); 180 | } 181 | 182 | private static void buildNewInstance3From(Project project, PsiClass psiClass, List result) { 183 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "newInstanceFrom"); 184 | methodBuilder 185 | .withParameter("properties", getProjectType("java.util.Map", project)) 186 | .withMethodReturnType(getProjectType(psiClass.getQualifiedName(), project)) 187 | .withContainingClass(psiClass) 188 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL); 189 | 190 | if(!checkMethodExists(psiClass, methodBuilder)) 191 | result.add(methodBuilder); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/PrimaryKeyBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiField; 6 | import com.intellij.psi.PsiModifier; 7 | import com.intellij.psi.PsiType; 8 | import com.intellij.psi.impl.light.LightFieldBuilder; 9 | import com.intellij.psi.search.GlobalSearchScope; 10 | 11 | import java.util.List; 12 | 13 | import static com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider.*; 14 | import static com.github.braisdom.objsql.intellij.SetterGetterMethodBuilder.upperFirstChar; 15 | 16 | final class PrimaryKeyBuilder { 17 | 18 | static void buildField(PsiClass psiClass, List result) { 19 | PsiField primaryKeyField = getPrimaryKeyField(psiClass); 20 | 21 | if(primaryKeyField == null) { 22 | PsiType primaryType = getPrimaryType(psiClass); 23 | String primaryName = getPrimaryName(psiClass); 24 | ObjsqlLightFieldBuilder primaryBuilder = new ObjsqlLightFieldBuilder(primaryName, primaryType, psiClass); 25 | primaryBuilder.setModifiers(PsiModifier.PRIVATE); 26 | primaryBuilder.setContainingClass(psiClass); 27 | 28 | result.add(primaryBuilder); 29 | } 30 | } 31 | 32 | static void buildMethod(PsiClass psiClass, List result) { 33 | PsiField primaryKeyField = getPrimaryKeyField(psiClass); 34 | 35 | if(primaryKeyField == null) { 36 | Project project = psiClass.getProject(); 37 | PsiType primaryType = getPrimaryType(psiClass); 38 | String primaryName = getPrimaryName(psiClass); 39 | 40 | String setterName = String.format("set%s", upperFirstChar(primaryName)); 41 | String getterName = String.format("get%s", upperFirstChar(primaryName)); 42 | 43 | ObjSqlLightMethodBuilder setterMethodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), setterName); 44 | ObjSqlLightMethodBuilder getterMethodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), getterName); 45 | 46 | setterMethodBuilder.withParameter(primaryName, primaryType) 47 | .withMethodReturnType(PsiType.getTypeByName(psiClass.getQualifiedName(), 48 | project, GlobalSearchScope.allScope(project))) 49 | .withContainingClass(psiClass) 50 | .withModifier(PsiModifier.PUBLIC); 51 | 52 | 53 | getterMethodBuilder.withMethodReturnType(primaryType) 54 | .withContainingClass(psiClass) 55 | .withModifier(PsiModifier.PUBLIC); 56 | 57 | if (!checkMethodExists(psiClass, setterMethodBuilder)) { 58 | result.add(setterMethodBuilder); 59 | } 60 | 61 | if (!checkMethodExists(psiClass, getterMethodBuilder)) { 62 | result.add(getterMethodBuilder); 63 | } 64 | } 65 | } 66 | 67 | static void buildQueryByPrimaryKeyMethod(PsiClass psiClass, List result) { 68 | Project project = psiClass.getProject(); 69 | PsiType primaryType = getPrimaryType(psiClass); 70 | String primaryName = getPrimaryName(psiClass); 71 | ObjSqlLightMethodBuilder queryByPrimaryBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), 72 | "queryByPrimaryKey"); 73 | 74 | queryByPrimaryBuilder.withParameter(primaryName, primaryType) 75 | .withParameter("relations", PsiType.getTypeByName( 76 | "com.github.braisdom.objsql.relation.Relationship", 77 | project, GlobalSearchScope.allScope(project)), true) 78 | .withMethodReturnType(PsiType.getTypeByName(psiClass.getQualifiedName(), 79 | project, GlobalSearchScope.allScope(project))) 80 | .withContainingClass(psiClass) 81 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL); 82 | 83 | if (!checkMethodExists(psiClass, queryByPrimaryBuilder)) { 84 | result.add(queryByPrimaryBuilder); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/PsiAnnotationSearchUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.util.Key; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | import com.intellij.psi.*; 6 | import com.intellij.psi.impl.source.SourceJavaCodeReference; 7 | import com.intellij.util.ArrayUtil; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.lang.annotation.Annotation; 12 | import java.util.Collection; 13 | import java.util.regex.Pattern; 14 | 15 | public class PsiAnnotationSearchUtil { 16 | private static final Key LOMBOK_ANNOTATION_FQN_KEY = Key.create("LOMBOK_ANNOTATION_FQN"); 17 | 18 | @Nullable 19 | public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String annotationFQN) { 20 | return findAnnotationQuick(psiModifierListOwner.getModifierList(), annotationFQN); 21 | } 22 | 23 | @Nullable 24 | public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String... annotationFQNs) { 25 | return findAnnotationQuick(psiModifierListOwner.getModifierList(), annotationFQNs); 26 | } 27 | 28 | @Nullable 29 | public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Class annotationType) { 30 | return findAnnotationQuick(psiModifierListOwner.getModifierList(), annotationType.getName()); 31 | } 32 | 33 | @Nullable 34 | public static PsiAnnotation findAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Class... annotationTypes) { 35 | if (annotationTypes.length == 1) { 36 | return findAnnotation(psiModifierListOwner, annotationTypes[0]); 37 | } 38 | 39 | final String[] qualifiedNames = new String[annotationTypes.length]; 40 | for (int i = 0; i < annotationTypes.length; i++) { 41 | qualifiedNames[i] = annotationTypes[i].getName(); 42 | } 43 | return findAnnotationQuick(psiModifierListOwner.getModifierList(), qualifiedNames); 44 | } 45 | 46 | @Nullable 47 | private static PsiAnnotation findAnnotationQuick(@Nullable PsiAnnotationOwner annotationOwner, @NotNull String qualifiedName) { 48 | if (annotationOwner == null) { 49 | return null; 50 | } 51 | 52 | PsiAnnotation[] annotations = annotationOwner.getAnnotations(); 53 | if (annotations.length == 0) { 54 | return null; 55 | } 56 | 57 | final String shortName = StringUtil.getShortName(qualifiedName); 58 | 59 | for (PsiAnnotation annotation : annotations) { 60 | PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement(); 61 | if (null != referenceElement) { 62 | final String referenceName = referenceElement.getReferenceName(); 63 | if (shortName.equals(referenceName)) { 64 | 65 | if (referenceElement.isQualified() && referenceElement instanceof SourceJavaCodeReference) { 66 | String possibleFullQualifiedName = ((SourceJavaCodeReference) referenceElement).getClassNameText(); 67 | if (qualifiedName.equals(possibleFullQualifiedName)) { 68 | return annotation; 69 | } 70 | } 71 | 72 | final String annotationQualifiedName = getAndCacheFQN(annotation, referenceName); 73 | if (null != annotationQualifiedName && qualifiedName.endsWith(annotationQualifiedName)) { 74 | return annotation; 75 | } 76 | } 77 | } 78 | } 79 | 80 | return null; 81 | } 82 | 83 | @Nullable 84 | private static PsiAnnotation findAnnotationQuick(@Nullable PsiAnnotationOwner annotationOwner, @NotNull String... qualifiedNames) { 85 | if (annotationOwner == null || qualifiedNames.length == 0) { 86 | return null; 87 | } 88 | 89 | PsiAnnotation[] annotations = annotationOwner.getAnnotations(); 90 | if (annotations.length == 0) { 91 | return null; 92 | } 93 | 94 | final String[] shortNames = new String[qualifiedNames.length]; 95 | for (int i = 0; i < qualifiedNames.length; i++) { 96 | shortNames[i] = StringUtil.getShortName(qualifiedNames[i]); 97 | } 98 | 99 | for (PsiAnnotation annotation : annotations) { 100 | final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement(); 101 | if (null != referenceElement) { 102 | final String referenceName = referenceElement.getReferenceName(); 103 | if (ArrayUtil.find(shortNames, referenceName) > -1) { 104 | 105 | if (referenceElement.isQualified() && referenceElement instanceof SourceJavaCodeReference) { 106 | final String possibleFullQualifiedName = ((SourceJavaCodeReference) referenceElement).getClassNameText(); 107 | 108 | if (ArrayUtil.find(qualifiedNames, possibleFullQualifiedName) > -1) { 109 | return annotation; 110 | } 111 | } 112 | 113 | final String annotationQualifiedName = getAndCacheFQN(annotation, referenceName); 114 | if (ArrayUtil.find(qualifiedNames, annotationQualifiedName) > -1) { 115 | return annotation; 116 | } 117 | } 118 | } 119 | } 120 | 121 | return null; 122 | } 123 | 124 | @Nullable 125 | private static String getAndCacheFQN(@NotNull PsiAnnotation annotation, @Nullable String referenceName) { 126 | String annotationQualifiedName = annotation.getCopyableUserData(LOMBOK_ANNOTATION_FQN_KEY); 127 | // if not cached or cache is not up to date (because existing annotation was renamed for example) 128 | if (null == annotationQualifiedName || (null != referenceName && !annotationQualifiedName.endsWith(".".concat(referenceName)))) { 129 | annotationQualifiedName = annotation.getQualifiedName(); 130 | if (null != annotationQualifiedName && annotationQualifiedName.indexOf('.') > -1) { 131 | annotation.putCopyableUserData(LOMBOK_ANNOTATION_FQN_KEY, annotationQualifiedName); 132 | } 133 | } 134 | return annotationQualifiedName; 135 | } 136 | 137 | public static boolean isAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Class annotationType) { 138 | return null != findAnnotation(psiModifierListOwner, annotationType); 139 | } 140 | 141 | public static boolean isAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull String annotationFQN) { 142 | return null != findAnnotation(psiModifierListOwner, annotationFQN); 143 | } 144 | 145 | public static boolean isNotAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Class annotationType) { 146 | return !isAnnotatedWith(psiModifierListOwner, annotationType); 147 | } 148 | 149 | public static boolean isAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Class... annotationTypes) { 150 | return null != findAnnotation(psiModifierListOwner, annotationTypes); 151 | } 152 | 153 | public static boolean isNotAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Class... annotationTypes) { 154 | return !isAnnotatedWith(psiModifierListOwner, annotationTypes); 155 | } 156 | 157 | public static boolean isAnnotatedWith(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull final Pattern annotationPattern) { 158 | final PsiModifierList psiModifierList = psiModifierListOwner.getModifierList(); 159 | if (psiModifierList != null) { 160 | for (PsiAnnotation psiAnnotation : psiModifierList.getAnnotations()) { 161 | final String suspect = getSimpleNameOf(psiAnnotation); 162 | if (annotationPattern.matcher(suspect).matches()) { 163 | return true; 164 | } 165 | } 166 | } 167 | return false; 168 | } 169 | 170 | @NotNull 171 | public static String getSimpleNameOf(@NotNull PsiAnnotation psiAnnotation) { 172 | PsiJavaCodeReferenceElement referenceElement = psiAnnotation.getNameReferenceElement(); 173 | return StringUtil.notNullize(null == referenceElement ? null : referenceElement.getReferenceName()); 174 | } 175 | 176 | public static boolean checkAnnotationsSimpleNameExistsIn(@NotNull PsiModifierListOwner modifierListOwner, @NotNull Collection annotationNames) { 177 | final PsiModifierList modifierList = modifierListOwner.getModifierList(); 178 | if (null != modifierList) { 179 | for (PsiAnnotation psiAnnotation : modifierList.getAnnotations()) { 180 | final String simpleName = getSimpleNameOf(psiAnnotation); 181 | if (annotationNames.contains(simpleName)) { 182 | return true; 183 | } 184 | } 185 | } 186 | return false; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/PsiClassUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.compiler.ex.CompilerPathsEx; 4 | import com.intellij.openapi.module.ModuleManager; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.ui.Messages; 7 | import com.intellij.openapi.vfs.PlatformVirtualFileManager; 8 | import com.intellij.openapi.vfs.VirtualFile; 9 | import com.intellij.psi.PsiClass; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.psi.PsiField; 12 | import com.intellij.psi.PsiJavaFile; 13 | import com.intellij.psi.impl.source.PsiExtensibleClass; 14 | import com.intellij.psi.util.PsiUtil; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.Arrays; 18 | import java.util.Collection; 19 | import java.util.stream.Collectors; 20 | 21 | /** 22 | * @author Plushnikov Michail 23 | */ 24 | public class PsiClassUtil { 25 | 26 | @FunctionalInterface 27 | public interface NavigateAction { 28 | 29 | boolean apply(PsiClass[] psiClasses); 30 | } 31 | 32 | /** 33 | * Workaround to get all of original Fields of the psiClass, without calling PsiAugmentProvider infinitely 34 | * 35 | * @param psiClass psiClass to collect all of fields from 36 | * @return all intern fields of the class 37 | */ 38 | @NotNull 39 | public static Collection collectClassFieldsIntern(@NotNull PsiClass psiClass) { 40 | if (psiClass instanceof PsiExtensibleClass) { 41 | return ((PsiExtensibleClass) psiClass).getOwnFields(); 42 | } else { 43 | return filterPsiElements(psiClass, PsiField.class); 44 | } 45 | } 46 | 47 | private static Collection filterPsiElements(@NotNull PsiClass psiClass, @NotNull Class desiredClass) { 48 | return Arrays.stream(psiClass.getChildren()).filter(desiredClass::isInstance).map(desiredClass::cast).collect(Collectors.toList()); 49 | } 50 | 51 | public static void navigate(Project project, PsiClass containingClass, NavigateAction action) { 52 | String qualifiedName = containingClass.getQualifiedName(); 53 | String[] outputPaths = CompilerPathsEx.getOutputPaths(ModuleManager.getInstance(project).getModules()); 54 | 55 | String classFileName = qualifiedName.replaceAll("\\.", "/") + ".class"; 56 | 57 | for(String outputPath : outputPaths) { 58 | String fullClassFileName = String.format("file://%s/%s", outputPath, classFileName); 59 | VirtualFile virtualFile = PlatformVirtualFileManager.getInstance().findFileByUrl(fullClassFileName); 60 | if(virtualFile != null) { 61 | PsiJavaFile psiJavaFile = (PsiJavaFile) PsiUtil.getPsiFile(project, virtualFile); 62 | PsiClass[] psiClasses = psiJavaFile.getClasses(); 63 | if(action.apply(psiClasses)) 64 | return; 65 | } 66 | } 67 | 68 | String message = String.format("Cannot find '%s', \nyou can rebuild project and retry.", classFileName); 69 | Messages.showErrorDialog(project, message, "Error"); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/QueryMethodBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.*; 5 | import com.intellij.psi.search.GlobalSearchScope; 6 | 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | import static com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider.*; 11 | 12 | final class QueryMethodBuilder { 13 | 14 | static void buildMethod(PsiClass psiClass, List result) { 15 | buildCreateQuery(psiClass.getProject(), psiClass, result); 16 | buildCount(psiClass.getProject(), psiClass, result); 17 | buildQuery(psiClass.getProject(), psiClass, result); 18 | buildPagedQuery(psiClass.getProject(), psiClass, result); 19 | buildQuery2(psiClass.getProject(), psiClass, result); 20 | buildPagedQuery2(psiClass.getProject(), psiClass, result); 21 | buildQuery3(psiClass.getProject(), psiClass, result); 22 | buildQueryFirst(psiClass.getProject(), psiClass, result); 23 | buildQueryFirst2(psiClass.getProject(), psiClass, result); 24 | buildQueryAll(psiClass.getProject(), psiClass, result); 25 | buildPagedQueryAll(psiClass.getProject(), psiClass, result); 26 | buildQueryableField(psiClass.getProject(), psiClass, result); 27 | } 28 | 29 | private static void buildCreateQuery(Project project, PsiClass psiClass, List result) { 30 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "createQuery"); 31 | PsiType psiType = getProjectType("com.github.braisdom.objsql.Query", project); 32 | methodBuilder.withMethodReturnType(psiType) 33 | .withContainingClass(psiClass) 34 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 35 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 36 | 37 | if(!checkMethodExists(psiClass, methodBuilder)) 38 | result.add(methodBuilder); 39 | } 40 | 41 | private static void buildCount(Project project, PsiClass psiClass, List result) { 42 | ObjSqlLightMethodBuilder countMethodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "count"); 43 | countMethodBuilder.withParameter("predicate", "java.lang.String") 44 | .withParameter("args", "java.lang.Object", true) 45 | .withMethodReturnType(PsiType.LONG) 46 | .withContainingClass(psiClass) 47 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 48 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 49 | 50 | ObjSqlLightMethodBuilder countAllMethodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "countAll"); 51 | countAllMethodBuilder.withMethodReturnType(PsiType.LONG) 52 | .withContainingClass(psiClass) 53 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 54 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 55 | 56 | 57 | if(!checkMethodExists(psiClass, countMethodBuilder)) 58 | result.add(countMethodBuilder); 59 | 60 | if(!checkMethodExists(psiClass, countAllMethodBuilder)) 61 | result.add(countAllMethodBuilder); 62 | } 63 | 64 | private static void buildQuery(Project project, PsiClass psiClass, List result) { 65 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "query"); 66 | PsiType returnType = createParameterType(project, "java.util.List", psiClass.getQualifiedName()); 67 | methodBuilder.withParameter("predicate", "java.lang.String") 68 | .withParameter("args", "java.lang.Object", true) 69 | .withMethodReturnType(returnType) 70 | .withContainingClass(psiClass) 71 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 72 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 73 | 74 | if(!checkMethodExists(psiClass, methodBuilder)) 75 | result.add(methodBuilder); 76 | } 77 | 78 | private static void buildPagedQuery(Project project, PsiClass psiClass, List result) { 79 | if(hasType("com.github.braisdom.objsql.pagination.PagedList", project)) { 80 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "pagedQuery"); 81 | PsiType returnType = createParameterType(project, "com.github.braisdom.objsql.pagination.PagedList", psiClass.getQualifiedName()); 82 | methodBuilder.withParameter("page", "com.github.braisdom.objsql.pagination.Page") 83 | .withParameter("predicate", "java.lang.String") 84 | .withParameter("args", "java.lang.Object", true) 85 | .withMethodReturnType(returnType) 86 | .withContainingClass(psiClass) 87 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 88 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 89 | 90 | if (!checkMethodExists(psiClass, methodBuilder)) 91 | result.add(methodBuilder); 92 | } 93 | } 94 | 95 | private static void buildQuery2(Project project, PsiClass psiClass, List result) { 96 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "query"); 97 | PsiType returnType = createParameterType(project, "java.util.List", psiClass.getQualifiedName()); 98 | methodBuilder.withParameter("predicate", "java.lang.String") 99 | .withParameter("relations", 100 | getProjectType("com.github.braisdom.objsql.relation.Relationship", project).createArrayType()) 101 | .withParameter("args", "java.lang.Object", true) 102 | .withMethodReturnType(returnType) 103 | .withContainingClass(psiClass) 104 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 105 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 106 | 107 | if(!checkMethodExists(psiClass, methodBuilder)) 108 | result.add(methodBuilder); 109 | } 110 | 111 | private static void buildPagedQuery2(Project project, PsiClass psiClass, List result) { 112 | if(hasType("com.github.braisdom.objsql.pagination.PagedList", project)) { 113 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "pagedQuery"); 114 | PsiType returnType = createParameterType(project, "com.github.braisdom.objsql.pagination.PagedList", psiClass.getQualifiedName()); 115 | methodBuilder.withParameter("page", "com.github.braisdom.objsql.pagination.Page") 116 | .withParameter("predicate", "java.lang.String") 117 | .withParameter("relations", 118 | getProjectType("com.github.braisdom.objsql.relation.Relationship", project).createArrayType()) 119 | .withParameter("args", "java.lang.Object", true) 120 | .withMethodReturnType(returnType) 121 | .withContainingClass(psiClass) 122 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 123 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 124 | 125 | if (!checkMethodExists(psiClass, methodBuilder)) 126 | result.add(methodBuilder); 127 | } 128 | } 129 | 130 | private static void buildQuery3(Project project, PsiClass psiClass, List result) { 131 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "queryBySql"); 132 | PsiType returnType = createParameterType(project, "java.util.List", psiClass.getQualifiedName()); 133 | methodBuilder.withParameter("predicate", "java.lang.String") 134 | .withParameter("args", "java.lang.Object", true) 135 | .withMethodReturnType(returnType) 136 | .withContainingClass(psiClass) 137 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 138 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 139 | 140 | if(!checkMethodExists(psiClass, methodBuilder)) 141 | result.add(methodBuilder); 142 | } 143 | 144 | private static void buildQueryAll(Project project, PsiClass psiClass, List result) { 145 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "queryAll"); 146 | PsiType returnType = createParameterType(project, "java.util.List", psiClass.getQualifiedName()); 147 | methodBuilder.withParameter("relations", "com.github.braisdom.objsql.relation.Relationship", true) 148 | .withMethodReturnType(returnType) 149 | .withContainingClass(psiClass) 150 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 151 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 152 | 153 | if(!checkMethodExists(psiClass, methodBuilder)) 154 | result.add(methodBuilder); 155 | } 156 | 157 | private static void buildPagedQueryAll(Project project, PsiClass psiClass, List result) { 158 | if(hasType("com.github.braisdom.objsql.pagination.PagedList", project)) { 159 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "pagedQueryAll"); 160 | PsiType returnType = createParameterType(project, "com.github.braisdom.objsql.pagination.PagedList", psiClass.getQualifiedName()); 161 | methodBuilder.withParameter("page", "com.github.braisdom.objsql.pagination.Page") 162 | .withParameter("relations", "com.github.braisdom.objsql.relation.Relationship", true) 163 | .withMethodReturnType(returnType) 164 | .withContainingClass(psiClass) 165 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 166 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 167 | 168 | if (!checkMethodExists(psiClass, methodBuilder)) 169 | result.add(methodBuilder); 170 | } 171 | } 172 | 173 | private static void buildQueryFirst(Project project, PsiClass psiClass, List result) { 174 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "queryFirst"); 175 | PsiType returnType = getProjectType(psiClass.getQualifiedName(), project); 176 | methodBuilder.withParameter("predicate", "java.lang.String") 177 | .withParameter("relations", 178 | getProjectType("com.github.braisdom.objsql.relation.Relationship", project).createArrayType()) 179 | .withParameter("args", "java.lang.Object", true) 180 | .withMethodReturnType(returnType) 181 | .withContainingClass(psiClass) 182 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 183 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 184 | 185 | if(!checkMethodExists(psiClass, methodBuilder)) 186 | result.add(methodBuilder); 187 | } 188 | 189 | private static void buildQueryFirst2(Project project, PsiClass psiClass, List result) { 190 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), "queryFirst"); 191 | PsiType returnType = getProjectType(psiClass.getQualifiedName(), project); 192 | methodBuilder.withParameter("predicate", "java.lang.String") 193 | .withParameter("args", "java.lang.Object", true) 194 | .withMethodReturnType(returnType) 195 | .withContainingClass(psiClass) 196 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 197 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 198 | 199 | if(!checkMethodExists(psiClass, methodBuilder)) 200 | result.add(methodBuilder); 201 | } 202 | 203 | private static void buildQueryableField(Project project, PsiClass psiClass, List result) { 204 | Collection fields = PsiClassUtil.collectClassFieldsIntern(psiClass); 205 | for(PsiField field : fields) { 206 | PsiAnnotation annotation = field 207 | .getAnnotation("com.github.braisdom.objsql.annotations.Queryable"); 208 | if(annotation != null) { 209 | PsiAnnotationMemberValue rawManyValue = annotation.findAttributeValue("many"); 210 | Boolean returnsMany = rawManyValue == null ? false : Boolean.parseBoolean(rawManyValue.getText()); 211 | String methodName = WordUtil.camelize(String.format("%s_%s", "queryBy", field.getName()), true); 212 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), methodName); 213 | 214 | PsiType returnType; 215 | if(returnsMany) 216 | returnType = createParameterType(project, "java.util.List", psiClass.getQualifiedName()); 217 | else 218 | returnType = createParameterType(project, psiClass.getQualifiedName()); 219 | 220 | 221 | methodBuilder.withParameter("value", field.getType()) 222 | .withParameter("name", "com.github.braisdom.objsql.relation.Relationship", true) 223 | .withMethodReturnType(returnType) 224 | .withContainingClass(psiClass) 225 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) 226 | .withException(PsiClassType.getTypeByName("java.sql.SQLException", project, GlobalSearchScope.allScope(project))); 227 | 228 | if(!checkMethodExists(psiClass, methodBuilder)) 229 | result.add(methodBuilder); 230 | } 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/RelationFieldBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.*; 5 | import com.intellij.psi.impl.light.LightFieldBuilder; 6 | import com.intellij.psi.search.GlobalSearchScope; 7 | 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | final class RelationFieldBuilder { 12 | 13 | private static final String RELATION_ANNOTATION = "com.github.braisdom.objsql.annotations.Relation"; 14 | 15 | static void buildField(PsiClass psiClass, List result) { 16 | final Project project = psiClass.getProject(); 17 | Collection fields = PsiClassUtil.collectClassFieldsIntern(psiClass); 18 | for (PsiField field : fields) { 19 | PsiAnnotation annotation = field.getAnnotation(RELATION_ANNOTATION); 20 | if (annotation != null) { 21 | PsiType primaryType = PsiType.getTypeByName("com.github.braisdom.objsql.relation.Relationship", 22 | project, GlobalSearchScope.allScope(project)); 23 | String fieldName = genFieldName(field, annotation); 24 | if(fieldName != null) { 25 | ObjsqlLightFieldBuilder primaryBuilder = new ObjsqlLightFieldBuilder(fieldName, primaryType, psiClass); 26 | primaryBuilder.setModifiers(PsiModifier.PUBLIC, PsiModifier.FINAL, PsiModifier.STATIC); 27 | primaryBuilder.setContainingClass(psiClass); 28 | 29 | result.add(primaryBuilder); 30 | } 31 | } 32 | } 33 | } 34 | 35 | static String genFieldName(PsiField psiField, PsiAnnotation annotationValue) { 36 | String value = annotationValue.findAttributeValue("relationType").getText(); 37 | if ("RelationType.HAS_MANY".equalsIgnoreCase(value)) { 38 | return WordUtil.underscore(String.format("%s_%s", "HAS_MANY", psiField.getName())).toUpperCase(); 39 | } else if ("RelationType.HAS_ONE".equalsIgnoreCase(value)) { 40 | return WordUtil.underscore(String.format("%s_%s", "HAS_ONE", psiField.getName())).toUpperCase(); 41 | } else if ("RelationType.BELONGS_TO".equalsIgnoreCase(value)) { 42 | return WordUtil.underscore(String.format("%s_%s", "BELONGS_TO", psiField.getName())).toUpperCase(); 43 | } 44 | return WordUtil.underscore(String.format("%s_%s", "HAS_MANY", psiField.getName())).toUpperCase(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/SetterGetterMethodBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiField; 6 | import com.intellij.psi.PsiModifier; 7 | import com.intellij.psi.PsiType; 8 | import com.intellij.psi.search.GlobalSearchScope; 9 | 10 | import java.util.Collection; 11 | import java.util.List; 12 | 13 | import static com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider.checkMethodExists; 14 | 15 | final class SetterGetterMethodBuilder { 16 | 17 | static void buildMethod(PsiClass psiClass, List result) { 18 | final Project project = psiClass.getProject(); 19 | Collection fields = PsiClassUtil.collectClassFieldsIntern(psiClass); 20 | for (PsiField field : fields) { 21 | String setterName = String.format("set%s", upperFirstChar(field.getName())); 22 | String getterName = String.format("%s%s", isBoolean(field.getType()) ? "is" : "get", 23 | upperFirstChar(field.getName())); 24 | ObjSqlLightMethodBuilder setterMethodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), setterName); 25 | ObjSqlLightMethodBuilder getterMethodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), getterName); 26 | 27 | setterMethodBuilder.withParameter(field.getName(), field.getType()) 28 | .withMethodReturnType(PsiType.getTypeByName(psiClass.getQualifiedName(), 29 | project, GlobalSearchScope.allScope(project))) 30 | .withContainingClass(psiClass) 31 | .withModifier(PsiModifier.PUBLIC); 32 | if(!checkMethodExists(psiClass, setterMethodBuilder)) 33 | result.add(setterMethodBuilder); 34 | 35 | getterMethodBuilder.withMethodReturnType(field.getType()) 36 | .withContainingClass(psiClass) 37 | .withModifier(PsiModifier.PUBLIC); 38 | 39 | if(!checkMethodExists(psiClass, getterMethodBuilder)) 40 | result.add(getterMethodBuilder); 41 | } 42 | } 43 | 44 | static boolean isBoolean(PsiType type) { 45 | String typeText = type.getCanonicalText(); 46 | return typeText.equalsIgnoreCase("boolean") || 47 | typeText.equalsIgnoreCase("java.lang.Boolean"); 48 | } 49 | 50 | static String upperFirstChar(String str) { 51 | if(str == null || str.length() == 0) { 52 | return str; 53 | } else { 54 | char[] ch = str.toCharArray(); 55 | if (ch[0] >= 'a' && ch[0] <= 'z') { 56 | ch[0] = (char) (ch[0] - 32); 57 | } 58 | return new String(ch); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/TableClassBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import com.intellij.psi.*; 4 | import com.intellij.psi.impl.light.LightFieldBuilder; 5 | import com.intellij.psi.impl.light.LightModifierList; 6 | import com.intellij.psi.impl.light.LightPsiClassBuilder; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collection; 11 | import java.util.List; 12 | 13 | import static com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider.*; 14 | 15 | final class TableClassBuilder { 16 | 17 | private static final String CLASS_NAME_TABLE = "Table"; 18 | 19 | static void buildClass(PsiClass psiClass, List result) { 20 | String qualifiedName = psiClass.getQualifiedName() + "." + CLASS_NAME_TABLE; 21 | List psiFields = new ArrayList<>(); 22 | 23 | ObjSqlLightClassBuilder classBuilder = new ObjSqlLightClassBuilder(psiClass, "Table", qualifiedName) { 24 | @NotNull 25 | @Override 26 | public PsiField[] getFields() { 27 | return psiFields.toArray(new PsiField[]{}); 28 | } 29 | 30 | @Override 31 | public PsiFile getContainingFile() { 32 | return psiClass.getContainingFile(); 33 | } 34 | }; 35 | LightModifierList modifier = classBuilder.getModifierList(); 36 | 37 | modifier.addModifier(PsiModifier.PUBLIC); 38 | modifier.addModifier(PsiModifier.STATIC); 39 | modifier.addModifier(PsiModifier.FINAL); 40 | classBuilder.setContainingClass(psiClass); 41 | classBuilder.setNavigationElement(psiClass); 42 | classBuilder.getExtendsList().addReference("com.github.braisdom.objsql.sql.AbstractTable"); 43 | classBuilder.addMethod(createPrivateConstructor(psiClass, classBuilder)); 44 | 45 | buildTableFields(psiClass, classBuilder, psiFields); 46 | buildPrimaryField(psiClass, classBuilder, psiFields); 47 | 48 | result.add(classBuilder); 49 | } 50 | 51 | static void buildMethod(PsiClass psiClass, List result) { 52 | PsiClass[] innerClasses = psiClass.getInnerClasses(); 53 | for (PsiClass innerClass : innerClasses) { 54 | if(innerClass.getName().equals("Table")) { 55 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder( 56 | psiClass.getManager(), "asTable"); 57 | PsiType returnType = JavaPsiFacade.getElementFactory(innerClass.getProject()) 58 | .createTypeFromText("Table", psiClass); 59 | methodBuilder.withMethodReturnType(returnType) 60 | .withContainingClass(psiClass) 61 | .withModifier(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL); 62 | 63 | if(!checkMethodExists(psiClass, methodBuilder)) 64 | result.add(methodBuilder); 65 | break; 66 | } 67 | } 68 | } 69 | 70 | private static PsiMethod createPrivateConstructor(PsiClass psiClass, PsiClass innerClass) { 71 | ObjSqlLightMethodBuilder methodBuilder = new ObjSqlLightMethodBuilder(psiClass.getManager(), innerClass.getName()); 72 | methodBuilder.withContainingClass(psiClass) 73 | .withMethodReturnType(PsiType.VOID) 74 | .withModifier(PsiModifier.PRIVATE) 75 | .setConstructor(true); 76 | return methodBuilder; 77 | } 78 | 79 | private static void buildPrimaryField(PsiClass psiClass, PsiClass innerClass, List psiFields) { 80 | PsiType fieldType = getProjectType("com.github.braisdom.objsql.sql.Column", psiClass.getProject()); 81 | String primaryName = getPrimaryName(psiClass); 82 | 83 | if(primaryName != null) { 84 | ObjsqlLightFieldBuilder fieldBuilder = new ObjsqlLightFieldBuilder(primaryName, fieldType, psiClass); 85 | fieldBuilder.setModifiers(PsiModifier.PUBLIC, PsiModifier.FINAL); 86 | fieldBuilder.setContainingClass(innerClass); 87 | 88 | psiFields.add(fieldBuilder); 89 | } 90 | } 91 | 92 | private static void buildTableFields(PsiClass psiClass, PsiClass innerClass, List psiFields) { 93 | Collection fields = PsiClassUtil.collectClassFieldsIntern(psiClass); 94 | for (PsiField field : fields) { 95 | PsiAnnotation transientAnn = field.getAnnotation("com.github.braisdom.objsql.annotations.Transient"); 96 | PsiAnnotation relationAnn = field.getAnnotation("com.github.braisdom.objsql.annotations.Relation"); 97 | if(transientAnn == null && relationAnn == null) { 98 | PsiClassType columnClassType = (PsiClassType) getProjectType("com.github.braisdom.objsql.sql.Column", 99 | psiClass.getProject()); 100 | ObjsqlLightFieldBuilder fieldBuilder = new ObjsqlLightFieldBuilder(field.getName(), columnClassType, psiClass); 101 | fieldBuilder.setModifiers(PsiModifier.PUBLIC, PsiModifier.FINAL); 102 | fieldBuilder.setContainingClass(innerClass); 103 | psiFields.add(fieldBuilder); 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/WordUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.braisdom.objsql.intellij; 2 | 3 | import java.util.*; 4 | 5 | 6 | /** 7 | *

Conversion between singular and plural form of a noun word.

8 | * 9 | * @author (Fei) John Chen 10 | */ 11 | public class WordUtil { 12 | 13 | private static final Map resolvedSingle2Plurals = new HashMap(); 14 | private static final List resolvedPlurals = new ArrayList(); 15 | private static final Map resolvedPlural2Singles = new HashMap(); 16 | private static final List resolvedSingles = new ArrayList(); 17 | 18 | public static final Map single2plurals = new HashMap(); 19 | public static final List plurals = new ArrayList(); 20 | public static final Map plural2singles = new HashMap(); 21 | public static final List singles = new ArrayList(); 22 | 23 | static { 24 | //Irregular plurals: 25 | single2plurals.put("child", "children"); 26 | single2plurals.put("corpus", "corpora"); 27 | single2plurals.put("foot", "feet"); 28 | single2plurals.put("goose", "geese"); 29 | single2plurals.put("louse", "lice"); 30 | single2plurals.put("man", "men"); 31 | single2plurals.put("mouse", "mice"); 32 | single2plurals.put("ox", "oxen"); 33 | single2plurals.put("person", "people"); 34 | single2plurals.put("tooth", "teeth"); 35 | single2plurals.put("woman", "women"); 36 | 37 | //Some nouns do not change at all: 38 | single2plurals.put("cod", "cod"); 39 | single2plurals.put("deer", "deer"); 40 | single2plurals.put("fish", "fish"); 41 | single2plurals.put("offspring", "offspring"); 42 | single2plurals.put("perch", "perch"); 43 | single2plurals.put("sheep", "sheep"); 44 | single2plurals.put("trout", "trout"); 45 | single2plurals.put("species", "species"); 46 | single2plurals.put("series", "series"); 47 | 48 | //Other nouns that do not change: 49 | single2plurals.put("data", "data"); 50 | single2plurals.put("dice", "dice"); 51 | single2plurals.put("media", "media"); 52 | 53 | //Singular ends in -us, plural ends in -i: alumnus/alumni, focus/foci, nucleus/nuclei, 54 | //octopus/octopi, radius/radii, stimulus/stimuli, virus/viri 55 | //Exceptions to the above 56 | single2plurals.put("bus", "buses"); 57 | 58 | //Singular ends in -ex, plural ends in -ices: appendix/appendices, index/indices 59 | single2plurals.put("index", "indices"); 60 | single2plurals.put("vertex", "vertices"); 61 | 62 | //These include nouns that are traditionally plural, but are also used for singular forms: 63 | single2plurals.put("barracks", "barracks"); 64 | single2plurals.put("crossroads", "crossroads"); 65 | single2plurals.put("die", "dice"); 66 | single2plurals.put("gallows", "gallows"); 67 | single2plurals.put("headquarters", "headquarters"); 68 | single2plurals.put("means", "means"); 69 | single2plurals.put("series", "series"); 70 | single2plurals.put("species", "species"); 71 | 72 | //Exception to Rule 6: Some nouns ending in f or fe are made plural 73 | //by changing f or fe to ves. with the following exceptions: 74 | single2plurals.put("chief", "chiefs"); 75 | single2plurals.put("chef", "chefs"); 76 | single2plurals.put("dwarf", "dwarfs"); 77 | single2plurals.put("hoof", "hoofs"); 78 | single2plurals.put("kerchief", "kerchiefs"); 79 | single2plurals.put("fife", "fifes"); 80 | single2plurals.put("proof", "proofs");//m-w.com 81 | single2plurals.put("roof", "roofs"); 82 | single2plurals.put("safe", "safes"); 83 | single2plurals.put("mischief", "mischiefs"); 84 | single2plurals.put("grief", "griefs"); 85 | 86 | //Rule 7b: All musical terms ending in -o have plurals ending in just -s. 87 | single2plurals.put("cello", "cellos"); 88 | single2plurals.put("photo", "photos"); 89 | single2plurals.put("solo", "solos"); 90 | single2plurals.put("soprano", "sopranos"); 91 | single2plurals.put("studio", "studios"); 92 | 93 | //Exception to Rule 7: Most nouns ending in o preceded by a consonant 94 | //is formed into a plural by adding es with the following exceptions: 95 | single2plurals.put("canto", "cantos"); 96 | single2plurals.put("lasso", "lassos"); 97 | single2plurals.put("halo", "halos"); 98 | single2plurals.put("memento", "mementos"); 99 | single2plurals.put("photo", "photos"); 100 | single2plurals.put("sirocco", "siroccos"); 101 | 102 | //Rule 7c: Plural forms of words ending in -o (-os): 103 | single2plurals.put("albino", "albinos"); 104 | single2plurals.put("armadillo", "armadillos"); 105 | single2plurals.put("auto", "autos"); 106 | single2plurals.put("bravo", "bravos"); 107 | single2plurals.put("bronco", "broncos"); 108 | single2plurals.put("canto", "cantos"); 109 | single2plurals.put("casino", "casinos"); 110 | single2plurals.put("combo", "combos"); 111 | single2plurals.put("gazebo", "gazebos"); 112 | single2plurals.put("inferno", "infernos"); 113 | single2plurals.put("kangaroo", "kangaroos"); 114 | single2plurals.put("kilo", "kilos"); 115 | single2plurals.put("kimono", "kimonos"); 116 | single2plurals.put("logo", "logos"); 117 | single2plurals.put("maraschino", "maraschinos"); 118 | single2plurals.put("memo", "memos"); 119 | single2plurals.put("photo", "photos"); 120 | single2plurals.put("pimento", "pimentos"); 121 | single2plurals.put("poncho", "ponchos"); 122 | single2plurals.put("pro", "pros"); 123 | single2plurals.put("sombrero", "sombreros"); 124 | single2plurals.put("taco", "tacos"); 125 | single2plurals.put("tattoo", "tattoos"); 126 | single2plurals.put("torso", "torsos"); 127 | single2plurals.put("tobacco", "tobaccos"); 128 | single2plurals.put("typo", "typos"); 129 | 130 | //Rule 7c: Plural forms of words ending in -o (-oes): 131 | single2plurals.put("echo", "echoes"); 132 | single2plurals.put("embargo", "embargoes"); 133 | single2plurals.put("hero", "heroes"); 134 | single2plurals.put("potato", "potatoes"); 135 | single2plurals.put("tomato", "tomatoes"); 136 | single2plurals.put("torpedo", "torpedoes"); 137 | single2plurals.put("veto", "vetoes"); 138 | 139 | //Rule 7c: Plural forms of words ending in -o (-os or -oes): 140 | single2plurals.put("avocado", "avocados"); 141 | single2plurals.put("buffalo", "buffaloes"); 142 | single2plurals.put("cargo", "cargoes"); 143 | single2plurals.put("desperado", "desperadoes"); 144 | single2plurals.put("dodo", "dodoes"); 145 | single2plurals.put("domino", "dominoes"); 146 | single2plurals.put("ghetto", "ghettos"); 147 | single2plurals.put("grotto", "grottoes"); 148 | single2plurals.put("hobo", "hoboes"); 149 | single2plurals.put("innuendo", "innuendoes"); 150 | single2plurals.put("lasso", "lassos"); 151 | single2plurals.put("mango", "mangoes"); 152 | single2plurals.put("mosquito", "mosquitoes"); 153 | single2plurals.put("motto", "mottoes"); 154 | single2plurals.put("mulatto", "mulattos"); 155 | single2plurals.put("no", "noes"); 156 | single2plurals.put("peccadillo", "peccadilloes"); 157 | single2plurals.put("tornado", "tornadoes"); 158 | single2plurals.put("volcano", "volcanoes"); 159 | single2plurals.put("zero", "zeros"); 160 | 161 | //others 162 | single2plurals.put("forum", "forums"); 163 | 164 | //Things that come in pairs 165 | plurals.add("binoculars"); 166 | plurals.add("forceps"); 167 | plurals.add("jeans"); 168 | plurals.add("glasses"); 169 | plurals.add("pajamas"); 170 | plurals.add("pants"); 171 | plurals.add("scissors"); 172 | plurals.add("shorts"); 173 | plurals.add("tongs"); 174 | plurals.add("trousers"); 175 | plurals.add("tweezers"); 176 | 177 | //Nouns that end in -s but have no singular (aggregate nouns) 178 | plurals.add("accommodations"); 179 | plurals.add("amends"); 180 | plurals.add("archives"); 181 | plurals.add("arms"); 182 | plurals.add("bellows"); 183 | plurals.add("bowels"); 184 | plurals.add("brains"); 185 | plurals.add("clothes"); 186 | plurals.add("communications"); 187 | plurals.add("congratulations"); 188 | plurals.add("contents"); 189 | plurals.add("dregs"); 190 | plurals.add("goods"); 191 | plurals.add("measles"); 192 | plurals.add("mumps"); 193 | plurals.add("oats"); 194 | plurals.add("pinchers"); 195 | plurals.add("shears"); 196 | plurals.add("snuffers"); 197 | plurals.add("stairs"); 198 | plurals.add("thanks"); 199 | plurals.add("vespers"); 200 | plurals.add("victuals"); 201 | 202 | //Nouns that are plural but do not end in -s 203 | plurals.add("children"); 204 | plurals.add("cattle"); 205 | plurals.add("corpora"); 206 | plurals.add("data"); 207 | plurals.add("men"); 208 | plurals.add("people"); 209 | plurals.add("police"); 210 | plurals.add("women"); 211 | 212 | //Nouns that are always singular -- uncountable 213 | singles.add("cooper"); 214 | singles.add("corn"); 215 | singles.add("cotton"); 216 | singles.add("gold"); 217 | singles.add("information"); 218 | singles.add("money"); 219 | singles.add("news"); 220 | singles.add("rice"); 221 | singles.add("silver"); 222 | singles.add("sugar"); 223 | singles.add("wheat"); 224 | 225 | //plural2singles.put("data", "data"); 226 | //plural2singles.put("media", "media"); 227 | plural2singles.put("dice", "dice"); 228 | plural2singles.put("indices", "index"); 229 | plural2singles.put("vertices", "vertex"); 230 | plural2singles.put("movies", "movie"); 231 | plural2singles.put("viri", "virus"); 232 | 233 | plural2singles.put("axes", "axis"); 234 | plural2singles.put("crises", "crisis"); 235 | plural2singles.put("analyses", "analysis"); 236 | plural2singles.put("diagnoses", "diagnosis"); 237 | plural2singles.put("synopses", "synopsis"); 238 | plural2singles.put("theses", "thesis"); 239 | plural2singles.put("moves", "move"); 240 | plural2singles.put("caves", "cave"); 241 | plural2singles.put("toes", "toe"); 242 | 243 | //merge plural2singles with single2plurals 244 | for (Map.Entry entry : single2plurals.entrySet()) { 245 | String sk = entry.getKey(); 246 | String sv = entry.getValue(); 247 | String pv = plural2singles.get(sv); 248 | if (pv == null) { 249 | plural2singles.put(sv, sk); 250 | } 251 | } 252 | 253 | //merge single2plurals with plural2singles 254 | for (Map.Entry entry : plural2singles.entrySet()) { 255 | String pk = entry.getKey(); 256 | String pv = entry.getValue(); 257 | String sv = single2plurals.get(pv); 258 | if (sv == null) { 259 | single2plurals.put(pv, pk); 260 | } 261 | } 262 | } 263 | 264 | /** 265 | * Returns a pluralized word. 266 | * 267 | * @param word the word to be converted to plural form 268 | * @return pluralized string 269 | */ 270 | public static String pluralize(String word) { 271 | if (word == null || "".equals(word)) return word; 272 | 273 | String plform = resolvedSingle2Plurals.get(word); 274 | if (plform == null && (resolvedPlurals.contains(word) || resolvedPlural2Singles.containsKey(word))) { 275 | plform = word; 276 | } 277 | if (plform != null) return plform; 278 | 279 | String tmp = word.toLowerCase(); 280 | plform = single2plurals.get(tmp); 281 | if (plform == null && (plurals.contains(tmp) || singles.contains(tmp) || plural2singles.containsKey(tmp))) { 282 | plform = tmp; 283 | } 284 | 285 | if (plform != null) { 286 | ; 287 | } 288 | //Rule #5: For words that end in -is, change the -is to -es to make the plural form 289 | else if (tmp.endsWith("is")) { 290 | plform = replaceLast(tmp, "is", "es"); 291 | } 292 | //Singular ends in -ix, plural ends in -ices: appendix/appendices, index/indices 293 | else if (tmp.endsWith("ix")) { 294 | plform = replaceLast(tmp, "ix", "ices"); 295 | } 296 | //Singular ends in -us, plural ends in -i: alumnus/alumni, focus/foci, nucleus/nuclei, 297 | //octopus/octopi, radius/radii, stimulus/stimuli, virus/viri 298 | else if (tmp.endsWith("us")) { 299 | plform = replaceLast(tmp, "us", "i"); 300 | } 301 | //Rule #2: For words that end in a "hissing" sound (-s, -z, -x, -ch, -sh), add an -es to form the plural. 302 | //Note: I removed tmp.endsWith("s") || as this cause "posts"->"postses". 303 | else if (!tmp.endsWith("es") && (tmp.endsWith("z") || 304 | tmp.endsWith("x") || tmp.endsWith("ch") || tmp.endsWith("sh"))) { 305 | plform = tmp + "es"; 306 | } 307 | else if (tmp.endsWith("y")) { 308 | //Rule #3: If the word ends in a vowel plus -y (-ay, -ey, -iy, -oy, -uy), add an -s to the word. 309 | if (tmp.endsWith("ay") || tmp.endsWith("ey") || tmp.endsWith("iy") || 310 | tmp.endsWith("oy") || tmp.endsWith("uy")) { 311 | plform = word + "s"; 312 | } 313 | //Rule #4: If the word ends in a consonant plus -y, change the -y into -ie and add an -s to form the plural. 314 | else { 315 | plform = replaceLast(tmp, "y", "ies"); 316 | } 317 | } 318 | //Rule #6: Some words that end in -f or -fe have plurals that end in -ves. 319 | else if (tmp.endsWith("f")) { 320 | plform = replaceLast(tmp, "f", "ves"); 321 | } 322 | else if (tmp.endsWith("fe")) { 323 | plform = replaceLast(tmp, "fe", "ves"); 324 | } 325 | //Rule #7: The plurals of words ending in -o are formed by either adding -s or by adding -es 326 | else if (tmp.endsWith("o")) { 327 | //All words that end in a vowel plus -o (-ao, -eo, -io, -oo, -uo) have plurals that end in just -s: 328 | if (tmp.endsWith("ao") || tmp.endsWith("eo") || tmp.endsWith("io") || 329 | tmp.endsWith("oo") || tmp.endsWith("uo")) { 330 | plform = word + "s"; 331 | } 332 | //All musical terms ending in -o have plurals ending in just -s. 333 | //Most others by adding -es with exceptions 334 | else { 335 | plform = word + "es"; 336 | } 337 | } 338 | //Singular ends in -um, plural ends in -a: datum/data, curriculum/curricula 339 | else if (tmp.endsWith("um")) { 340 | plform = replaceLast(tmp, "um", "a"); 341 | } 342 | //Singular ends in -on, plural ends in -a: criterion/criteria, phenomenon/phenomena 343 | else if (tmp.endsWith("on") && !tmp.endsWith("ation")) { 344 | plform = replaceLast(tmp, "on", "a"); 345 | } 346 | //Singular ends in -a, plural ends in -ae: alumna/alumnae, formula/formulae, antenna/antennae 347 | else if (tmp.endsWith("a")) { 348 | plform = replaceLast(tmp, "a", "ae"); 349 | } 350 | //Singular ends in -eau, plural ends in -eaux: bureau/bureaux, beau/beaux 351 | else if (tmp.endsWith("eau")) { 352 | plform = replaceLast(tmp, "eau", "eaux"); 353 | } 354 | //special 355 | else if (tmp.endsWith("man")) { 356 | plform = replaceLast(tmp, "man", "men"); 357 | } 358 | //Rule #1: Add an -s to form the plural of most words. 359 | else if (!tmp.endsWith("s")){ 360 | plform = word + "s"; 361 | } 362 | //Rule #8: The plurals of single capital letters, acronyms, and Arabic numerals 363 | //(1,2,3,...) take an -s WITHOUT an apostrophe: 364 | else if (word.toUpperCase().equals(word)) { 365 | plform = word + "s"; 366 | } 367 | else { 368 | plform = tmp; 369 | resolvedPlurals.add(word); 370 | return word; 371 | } 372 | 373 | //check cases 374 | boolean caseChanged = false; 375 | int wl = word.length(); 376 | int pl = plform.length(); 377 | char[] pChars = plform.toCharArray(); 378 | int length = (wl < pl)?wl:pl; 379 | for (int i = 0; i < length; i++) { 380 | char wChar = word.charAt(i); 381 | char pChar = plform.charAt(i); 382 | if (((int)wChar - (int)pChar) == -32) { 383 | pChars[i] = wChar; 384 | caseChanged = true; 385 | } 386 | } 387 | 388 | if (caseChanged) plform = new String(pChars); 389 | if (!plform.equalsIgnoreCase(word)) { 390 | resolvedSingle2Plurals.put(word, plform); 391 | resolvedPlural2Singles.put(plform, word); 392 | } 393 | 394 | return plform; 395 | } 396 | 397 | 398 | 399 | /** 400 | * Returns a singularized word from a plural word. 401 | * 402 | * @param word the word to be converted to singular form 403 | * @return singularized string 404 | */ 405 | public static String singularize(String word) { 406 | if (word == null || "".equals(word)) return word; 407 | 408 | String sgform = resolvedPlural2Singles.get(word); 409 | if (sgform == null && (resolvedSingles.contains(word) || resolvedSingle2Plurals.containsKey(word))) { 410 | sgform = word; 411 | } 412 | if (sgform != null) return sgform; 413 | 414 | String tmp = word.toLowerCase(); 415 | sgform = plural2singles.get(tmp); 416 | if (sgform == null && (plurals.contains(tmp) || singles.contains(tmp) || single2plurals.containsKey(tmp))) { 417 | sgform = tmp; 418 | } 419 | 420 | if (sgform != null) { 421 | ; 422 | } 423 | else if (tmp.endsWith("ices")) { 424 | sgform = replaceLast(tmp, "ices", "ix"); 425 | } 426 | else if (tmp.endsWith("i")) { 427 | sgform = replaceLast(tmp, "i", "us"); 428 | } 429 | else if (tmp.endsWith("ses") && !tmp.endsWith("bases") || 430 | tmp.endsWith("zes") || tmp.endsWith("xes") || 431 | tmp.endsWith("ches") || tmp.endsWith("shes")) { 432 | sgform = replaceLast(tmp, "es", ""); 433 | } 434 | else if (tmp.endsWith("ays") || tmp.endsWith("eys") || tmp.endsWith("iys") || 435 | tmp.endsWith("oys") || tmp.endsWith("uys")) { 436 | sgform = replaceLast(tmp, "ys", "y"); 437 | } 438 | else if (tmp.endsWith("ies")) { 439 | sgform = replaceLast(tmp, "ies", "y"); 440 | } 441 | //Rule #7 442 | else if (tmp.endsWith("aos") || tmp.endsWith("eos") || tmp.endsWith("ios") || 443 | tmp.endsWith("oos") || tmp.endsWith("uos")) { 444 | sgform = replaceLast(tmp, "os", "o"); 445 | } 446 | //Rule #7 447 | else if (tmp.endsWith("oes")) { 448 | sgform = replaceLast(tmp, "oes", "o"); 449 | } 450 | else if (tmp.endsWith("ives")) { 451 | sgform = replaceLast(tmp, "ves", "fe"); 452 | } 453 | else if (tmp.endsWith("lves") || tmp.endsWith("rves") || tmp.endsWith("aves")) { 454 | sgform = replaceLast(tmp, "ves", "f"); 455 | } 456 | else if (tmp.endsWith("ae")) { 457 | sgform = replaceLast(tmp, "ae", "a"); 458 | } 459 | else if (tmp.endsWith("eaux")) { 460 | sgform = replaceLast(tmp, "eaux", "eau"); 461 | } 462 | else if (tmp.endsWith("men")) { 463 | sgform = replaceLast(tmp, "men", "man"); 464 | } 465 | else if (tmp.endsWith("s")) { 466 | sgform = replaceLast(tmp, "s", ""); 467 | } 468 | else { 469 | sgform = tmp; 470 | resolvedSingles.add(word); 471 | return word; 472 | } 473 | 474 | //check cases 475 | boolean caseChanged = false; 476 | int wl = word.length(); 477 | int pl = sgform.length(); 478 | char[] sChars = sgform.toCharArray(); 479 | int length = (wl < pl)?wl:pl; 480 | for (int i = 0; i < length; i++) { 481 | char wChar = word.charAt(i); 482 | char pChar = sgform.charAt(i); 483 | if (((int)wChar - (int)pChar) == -32) { 484 | sChars[i] = wChar; 485 | caseChanged = true; 486 | } 487 | } 488 | 489 | if (caseChanged) sgform = new String(sChars); 490 | if (!sgform.equalsIgnoreCase(word)) { 491 | resolvedPlural2Singles.put(word, sgform); 492 | resolvedSingle2Plurals.put(sgform, word); 493 | } 494 | 495 | return sgform; 496 | } 497 | 498 | /** 499 | * Replaces the last occurance of an old symbol with a new symbol. 500 | * 501 | * @param data the original string 502 | * @param oldSymbol the old symbols to be replaced 503 | * @param newSymbol the corresponding new symbol 504 | * @return a new string 505 | */ 506 | public static String replaceLast(String data, String oldSymbol, String newSymbol) { 507 | if (data == null || data.indexOf(oldSymbol) == -1) return data; 508 | 509 | int lastIndex = data.lastIndexOf(oldSymbol); 510 | int oldLength = oldSymbol.length(); 511 | String result = data.substring(0, lastIndex) + newSymbol + 512 | data.substring(lastIndex + oldLength); 513 | 514 | return result; 515 | } 516 | 517 | /** 518 | * Adds more pairs of single and plural words. 519 | * 520 | * @param single singular form of the word 521 | * @param plural plural form of the word 522 | */ 523 | public static void addPlural(String single, String plural) { 524 | resolvedSingle2Plurals.put(single, plural); 525 | resolvedPlural2Singles.put(plural, single); 526 | } 527 | 528 | /** 529 | * Converts string to Camel case. 530 | * 531 | * @param word the word to be converted to camelized form 532 | * @return a camelized string 533 | */ 534 | public static String camelize(String word) { 535 | return camelize(word, false); 536 | } 537 | 538 | /** 539 | * Converts string to Camel case. If firstLetterInLowerCase 540 | * is true, then the first letter of the result string is in lower case. 541 | * 542 | *
543 |      * Examples:
544 |      *   camelize("hello")               "Hello"
545 |      *   camelize("hello world")         "Hello world"
546 |      *   camelize("active_record")       "ActiveRecord"
547 |      *   camelize("active_record", true) "activeRecord"
548 |      * 
549 | * 550 | * @param word the word to be converted to camelized form 551 | * @param firstLetterInLowerCase true if the first character should be in lower case 552 | * @return a camelized string 553 | */ 554 | public static String camelize(String word, boolean firstLetterInLowerCase) { 555 | if (word == null || "".equals(word)) return word; 556 | 557 | String result = ""; 558 | if (word.indexOf('_') != -1) { 559 | StringBuilder sb = new StringBuilder(); 560 | int count = 0; 561 | StringTokenizer st = new StringTokenizer(word, "_"); 562 | while(st.hasMoreTokens()) { 563 | String token = st.nextToken(); 564 | count++; 565 | if (count == 1) { 566 | sb.append(camelizeOneWord(token, firstLetterInLowerCase)); 567 | } 568 | else { 569 | sb.append(camelizeOneWord(token, false)); 570 | } 571 | } 572 | result = sb.toString(); 573 | } 574 | else { 575 | result = camelizeOneWord(word, firstLetterInLowerCase); 576 | } 577 | return result; 578 | } 579 | 580 | private static String camelizeOneWord(String word, boolean firstLetterInLowerCase) { 581 | if (word == null || "".equals(word)) return word; 582 | 583 | String firstChar = word.substring(0,1); 584 | String result = (firstLetterInLowerCase)?firstChar.toLowerCase():firstChar.toUpperCase(); 585 | if (word.length() > 1) { 586 | result += word.substring(1); 587 | } 588 | return result; 589 | } 590 | 591 | /** 592 | * underscore is the reverse of camelize method. 593 | * 594 | *
595 |      * Examples:
596 |      *   underscore("Hello world")    "hello world"
597 |      *   underscore("ActiveRecord")   "active_record"
598 |      *   underscore("The RedCross")   "the red_cross"
599 |      *   underscore("ABCD")           "abcd"
600 |      * 
601 | * 602 | * @param phase the original string 603 | * @return an underscored string 604 | */ 605 | public static String underscore(String phase) { 606 | if (phase == null || "".equals(phase)) return phase; 607 | 608 | phase = phase.replace('-', '_'); 609 | StringBuilder sb = new StringBuilder(); 610 | int total = phase.length(); 611 | for (int i = 0; i < total; i++) { 612 | char c = phase.charAt(i); 613 | if (i == 0) { 614 | if (isInA2Z(c)) { 615 | sb.append(("" + c).toLowerCase()); 616 | } 617 | else { 618 | sb.append(c); 619 | } 620 | } 621 | else { 622 | if (isInA2Z(c)) { 623 | if (isIna2z(phase.charAt(i-1))) { 624 | sb.append(("_" + c).toLowerCase()); 625 | } 626 | else { 627 | sb.append(("" + c).toLowerCase()); 628 | } 629 | } 630 | else { 631 | sb.append(c); 632 | } 633 | } 634 | } 635 | return sb.toString(); 636 | } 637 | 638 | private static String A2Z = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 639 | private static String a2z = "abcdefghijklmnopqrstuvwxyz"; 640 | 641 | private static boolean isInA2Z(char c) { 642 | return (A2Z.indexOf(c) != -1)?true:false; 643 | } 644 | 645 | private static boolean isIna2z(char c) { 646 | return (a2z.indexOf(c) != -1)?true:false; 647 | } 648 | 649 | /** 650 | * Replaces all dashes and underscores by spaces and capitalizes all the words. 651 | * 652 | *
653 |      * Examples:
654 |      *   titleize("ch 1:  Java-ActiveRecordIsFun")   "Ch 1:  Java Active Record Is Fun"
655 |      * 
656 | * 657 | * @param phase the original string 658 | * @return a titleized string 659 | */ 660 | public static String titleize(String phase) { 661 | if (phase == null || "".equals(phase)) return phase; 662 | 663 | phase = humanize(phase); 664 | StringBuilder sb = new StringBuilder(); 665 | int total = phase.length(); 666 | for (int i = 0; i < total; i++) { 667 | char c = phase.charAt(i); 668 | if (i == 0) { 669 | if (isIna2z(c)) { 670 | sb.append(("" + c).toUpperCase()); 671 | } 672 | else { 673 | sb.append(c); 674 | } 675 | } 676 | else { 677 | if (isIna2z(c) && ' ' == phase.charAt(i-1)) { 678 | sb.append(("" + c).toUpperCase()); 679 | } 680 | else { 681 | sb.append(c); 682 | } 683 | } 684 | } 685 | return sb.toString(); 686 | } 687 | 688 | /** 689 | * Replaces all dashes and underscores by spaces and capitalizes the first 690 | * word. Also removes 691 | * 692 | *
693 |      * Examples:
694 |      *   humanize("active_record")   "Active record"
695 |      *   humanize("post_id")         "Post"
696 |      * 
697 | * 698 | * @param phase the original string 699 | * @return a humanized string 700 | */ 701 | public static String humanize(String phase) { 702 | if (phase == null || "".equals(phase)) return phase; 703 | phase = underscore(phase); 704 | if (phase.endsWith("_id")) phase += " "; 705 | return camelize(phase.replaceAll("_id ", " ").replace('_', ' ').trim()); 706 | } 707 | 708 | /** 709 | * Returns a database table tableName corresponding to the input entityClass class 710 | * tableName. 711 | * 712 | *
713 |      * Examples:
714 |      *   tableize("Person")     "people"
715 |      *   tableize("LineItem")   "line_items"
716 |      * 
717 | * 718 | * @param modelClassName 719 | * @return the table tableName of the java entityClass class tableName 720 | */ 721 | public static String tableize(String modelClassName) { 722 | return pluralize(underscore(modelClassName)); 723 | } 724 | 725 | /** 726 | * Returns a entityClass class tableName corresponding to the input database 727 | * table tableName. 728 | * 729 | *
730 |      * Examples:
731 |      *   classify("people")     "Person"
732 |      *   classify("line_items")   "LineItem"
733 |      * 
734 | * 735 | * @param tableName java class tableName of the entityClass 736 | * @return a java entityClass class tableName 737 | */ 738 | public static String classify(String tableName) { 739 | return camelize(singularize(tableName)); 740 | } 741 | 742 | public static boolean isEmpty(String str) { 743 | return str == null || str.length() == 0; 744 | } 745 | 746 | public static String removeEnd(String str, String remove) { 747 | if (isEmpty(str) || isEmpty(remove)) { 748 | return str; 749 | } 750 | if (str.endsWith(remove)) { 751 | return str.substring(0, str.length() - remove.length()); 752 | } 753 | return str; 754 | } 755 | 756 | /** 757 | * Returns an ordinalized string. 758 | * 759 | *
760 |      * Examples:
761 |      *   ordinalize(100)    "100th"
762 |      *   ordinalize(1003)   "1003rd"
763 |      * 
764 | * 765 | * @param number the number 766 | * @return an ordinalized string for the number 767 | */ 768 | public static String ordinalize(int number) { 769 | String result = "" + number; 770 | if (result.endsWith("1")) result = result + "st"; 771 | else if (result.endsWith("2")) result = result + "nd"; 772 | else if (result.endsWith("3")) result = result + "rd"; 773 | else result = result + "th"; 774 | return result; 775 | } 776 | } -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/OOComponent.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.codeInsight.daemon.impl.HighlightVisitor; 18 | import com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl; 19 | import com.intellij.openapi.components.ProjectComponent; 20 | import com.intellij.openapi.diagnostic.Logger; 21 | import com.intellij.openapi.extensions.ExtensionPoint; 22 | import com.intellij.openapi.extensions.Extensions; 23 | import com.intellij.openapi.extensions.impl.ExtensionComponentAdapter; 24 | import com.intellij.openapi.extensions.impl.ExtensionPointImpl; 25 | import com.intellij.openapi.project.Project; 26 | import com.intellij.psi.impl.source.tree.JavaElementType; 27 | import com.intellij.psi.impl.source.tree.java.PsiArrayAccessExpressionImpl; 28 | import com.intellij.psi.impl.source.tree.java.PsiBinaryExpressionImpl; 29 | import com.intellij.psi.impl.source.tree.java.PsiPolyadicExpressionImpl; 30 | import com.intellij.psi.impl.source.tree.java.PsiPrefixExpressionImpl; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | import java.util.List; 34 | 35 | public class OOComponent implements ProjectComponent { 36 | private static final Logger LOG = Logger.getInstance("#"+OOComponent.class.getName()); 37 | 38 | private final Project project; 39 | 40 | public OOComponent(Project project) { 41 | this.project = project; 42 | } 43 | 44 | @NotNull @Override 45 | public String getComponentName() { 46 | return "Java Operator Overloading plugin"; 47 | } 48 | 49 | @Override 50 | public void initComponent() { 51 | LOG.info("OO init"); 52 | Util.setJavaElementConstructor(JavaElementType.BINARY_EXPRESSION, PsiOOBinaryExpressionImpl::new); 53 | Util.setJavaElementConstructor(JavaElementType.PREFIX_EXPRESSION, PsiOOPrefixExpressionImpl::new); 54 | Util.setJavaElementConstructor(JavaElementType.POLYADIC_EXPRESSION, PsiOOPolyadicExpressionImpl::new); 55 | Util.setJavaElementConstructor(JavaElementType.ARRAY_ACCESS_EXPRESSION, PsiOOArrayAccessExpressionImpl::new); 56 | 57 | // TODO: replace to project.getExtensionArea() after 2019.3 58 | ExtensionPoint ep = Extensions.getArea(project).getExtensionPoint(HighlightVisitor.EP_HIGHLIGHT_VISITOR); 59 | List hadapters = (List) Util.get(ExtensionPointImpl.class, (ExtensionPointImpl) ep, List.class, "myAdapters"); 60 | for (ExtensionComponentAdapter ca : hadapters) { 61 | if (HighlightVisitorImpl.class.getName().equals(ca.getAssignableToClassName())) { 62 | try { 63 | Util.set(ExtensionComponentAdapter.class, ca, Object.class, OOHighlightVisitorImpl.class, "myImplementationClassOrName"); 64 | } catch (Exception e) { 65 | LOG.error("Can't load transformed OOHighlightVisitorImpl class", e); 66 | } 67 | break; 68 | } 69 | } 70 | } 71 | 72 | @Override 73 | public void disposeComponent() { 74 | LOG.info("OO dispose"); 75 | Util.setJavaElementConstructor(JavaElementType.BINARY_EXPRESSION, PsiBinaryExpressionImpl::new); 76 | Util.setJavaElementConstructor(JavaElementType.PREFIX_EXPRESSION, PsiPrefixExpressionImpl::new); 77 | Util.setJavaElementConstructor(JavaElementType.POLYADIC_EXPRESSION, PsiPolyadicExpressionImpl::new); 78 | Util.setJavaElementConstructor(JavaElementType.ARRAY_ACCESS_EXPRESSION, PsiArrayAccessExpressionImpl::new); 79 | } 80 | 81 | public void projectOpened() {} 82 | public void projectClosed() {} 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/OOHighlightVisitorImpl.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.github.braisdom.objsql.intellij.ObjSqlPsiAugmentProvider; 18 | import com.intellij.codeInsight.daemon.impl.HighlightInfo; 19 | import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder; 20 | import com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl; 21 | import com.intellij.lang.annotation.HighlightSeverity; 22 | import com.intellij.openapi.diagnostic.Logger; 23 | import com.intellij.openapi.util.TextRange; 24 | import com.intellij.psi.*; 25 | import org.jetbrains.annotations.NotNull; 26 | 27 | import java.lang.reflect.Field; 28 | import java.util.List; 29 | 30 | import static com.github.braisdom.objsql.intellij.oo.Util.sneakyThrow; 31 | 32 | public class OOHighlightVisitorImpl extends HighlightVisitorImpl { 33 | 34 | private static final Logger LOGGER = Logger.getInstance(ObjSqlPsiAugmentProvider.class.getName()); 35 | 36 | private HighlightInfoHolder myHolder; 37 | private PsiResolveHelper resolveHelper; 38 | 39 | protected OOHighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) { 40 | super(resolveHelper); 41 | this.resolveHelper = resolveHelper; 42 | } 43 | 44 | @Override 45 | public boolean analyze(@NotNull PsiFile file, boolean updateWholeFile, @NotNull HighlightInfoHolder holder, @NotNull Runnable action) { 46 | myHolder = holder; 47 | try { 48 | return super.analyze(file, updateWholeFile, holder, action); 49 | } finally { 50 | myHolder = null; 51 | } 52 | } 53 | 54 | @Override 55 | public void visitMethod(PsiMethod method) { 56 | super.visitMethod(method); 57 | } 58 | 59 | @Override // Binary OO 60 | public void visitPolyadicExpression(PsiPolyadicExpression expression) { 61 | super.visitPolyadicExpression(expression); 62 | if (isHighlighted(expression)) { 63 | PsiExpression[] operands = expression.getOperands(); 64 | PsiType lType = operands[0].getType(); 65 | for (int i = 1; i < operands.length; i++) { 66 | PsiExpression operand = operands[i]; 67 | PsiType rType = operand.getType(); 68 | // TODO: case A + A + int ? A.add(A) : int 69 | lType = OOResolver.getOOType(lType, rType, expression.getTokenBeforeOperand(operand)); 70 | } 71 | if (lType != OOResolver.NoType) 72 | removeLastHighlight(); 73 | else LOGGER.info("visitPolyadicExpression lType = OOResolver.NoType, lType:" + lType); 74 | } else LOGGER.info("visitPolyadicExpression ignore highlihted"); 75 | } 76 | 77 | @Override // Unary OO 78 | public void visitPrefixExpression(PsiPrefixExpression expression) { 79 | super.visitPrefixExpression(expression); 80 | if (isHighlighted(expression) 81 | && OOResolver.getOOType(expression) != OOResolver.NoType) { 82 | removeLastHighlight(); 83 | } else LOGGER.info("visitPrefixExpression ignore highlihted, Highlighted: " 84 | + isHighlighted(expression) + ", OOType: " + OOResolver.getOOType(expression)); 85 | } 86 | 87 | @Override // Index-Get OO 88 | public void visitExpression(PsiExpression expression) { 89 | super.visitExpression(expression); 90 | if (expression instanceof PsiArrayAccessExpression) { 91 | PsiArrayAccessExpression paa = (PsiArrayAccessExpression) expression; 92 | if (isHighlighted(paa.getArrayExpression()) 93 | && OOResolver.indexGet((PsiArrayAccessExpression) expression) != OOResolver.NoType) 94 | removeLastHighlight(); 95 | else LOGGER.info("visitExpression ignore highlihted, Highlighted: " 96 | + isHighlighted(paa.getArrayExpression()) + ", OOType: " + OOResolver.indexGet((PsiArrayAccessExpression) expression)); 97 | } 98 | } 99 | 100 | @Override 101 | public void visitAssignmentExpression(PsiAssignmentExpression ass) { 102 | super.visitAssignmentExpression(ass); 103 | if ("=".equals(ass.getOperationSign().getText())) { 104 | // Index-Set OO 105 | if (ass.getLExpression() instanceof PsiArrayAccessExpression 106 | && isHighlighted(ass.getLExpression())) { 107 | PsiArrayAccessExpression paa = (PsiArrayAccessExpression) ass.getLExpression(); 108 | if (OOResolver.indexSet(paa, ass.getRExpression()) != OOResolver.NoType) 109 | removeLastHighlight(); 110 | else LOGGER.info("visitAssignmentExpression ignore highlihted, OOType: " 111 | + OOResolver.indexSet(paa, ass.getRExpression())); 112 | } else LOGGER.info("visitAssignmentExpression ignore highlihted, Highlighted: " 113 | + isHighlighted(ass.getLExpression())); 114 | // Implicit type conversion in assignment 115 | if (isHighlighted(ass) && OOResolver.isTypeConvertible(ass.getLExpression().getType(), ass.getRExpression())) 116 | removeLastHighlight(); 117 | else LOGGER.info("visitAssignmentExpression ignore highlihted, Highlighted: " 118 | + isHighlighted(ass) + ", isTypeConvertible: " + OOResolver.isTypeConvertible(ass.getLExpression().getType(), ass.getRExpression())); 119 | } 120 | } 121 | 122 | @Override // Implicit type conversion in variable declaration 123 | public void visitVariable(PsiVariable var) { 124 | super.visitVariable(var); 125 | if (var.hasInitializer() && isHighlighted(var) && OOResolver.isTypeConvertible(var.getType(), var.getInitializer())) 126 | removeLastHighlight(); 127 | else LOGGER.info("visitVariable hasInitializer: " + var.hasInitializer() 128 | + ", isHighlighted: " + isHighlighted(var) + ", isTypeConvertible: " + OOResolver.isTypeConvertible(var.getType(), var.getInitializer())); 129 | } 130 | 131 | private boolean isHighlighted(@NotNull PsiElement expression) { 132 | if (myHolder.hasErrorResults()) { 133 | HighlightInfo hi = myHolder.get(myHolder.size() - 1); 134 | if (hi.getSeverity() != HighlightSeverity.ERROR) return false; 135 | if (expression instanceof PsiVariable) { // workaround for variable declaration incompatible types highlight 136 | PsiVariable v = (PsiVariable) expression; 137 | PsiTypeElement pte = v.getTypeElement(); 138 | if (pte == null) 139 | return false; 140 | TextRange tetr = pte.getTextRange(); 141 | TextRange tr = v.getTextRange(); 142 | return tr != null && tetr != null 143 | && hi.startOffset == tetr.getStartOffset() 144 | && hi.endOffset == tr.getEndOffset(); 145 | } 146 | TextRange tr = expression.getTextRange(); 147 | return hi.startOffset == tr.getStartOffset() && hi.endOffset == tr.getEndOffset(); 148 | } 149 | return false; 150 | } 151 | 152 | // TODO: what highlightInfo to delete? 153 | private void removeLastHighlight() { 154 | // remove highlight 155 | List myInfos = (List) Util.get(HighlightInfoHolder.class, myHolder, List.class, "myInfos", "f"); 156 | myInfos.remove(myHolder.size() - 1); 157 | // update error count 158 | Field fmyErrorCount = Util.findField(HighlightInfoHolder.class, int.class, "myErrorCount", "b"); 159 | try { 160 | fmyErrorCount.setInt(myHolder, fmyErrorCount.getInt(myHolder) - 1); 161 | } catch (IllegalAccessException e) { 162 | throw sneakyThrow(e); 163 | } 164 | } 165 | 166 | @Override 167 | @NotNull 168 | public OOHighlightVisitorImpl clone() { 169 | return new OOHighlightVisitorImpl(resolveHelper); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/OOMethods.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | /** Caution this file is symlinked in all plugins */ 21 | public interface OOMethods { 22 | Map binary = new HashMap() {{ 23 | put("+", "plus"); 24 | put("-", "minus"); 25 | put("*", "times"); 26 | put("/", "div"); 27 | put("%", "rem"); 28 | put("<", "lt"); 29 | put(">", "gt"); 30 | put("<=", "le"); 31 | put(">=", "ge"); 32 | put("&&", "and"); 33 | put("||", "or"); 34 | }}; 35 | String revSuffix = "Rev"; 36 | Map unary = new HashMap() {{ 37 | put("-", "negate"); // jdk7 38 | put("---", "negate"); // jdk8 39 | put("~", "not"); 40 | }}; 41 | String indexGet = "get"; 42 | String[] indexSet = new String[]{"set", "put"}; 43 | String[] valueOf = new String[]{"valueOf", "of"}; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/OOResolver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.openapi.project.Project; 18 | import com.intellij.psi.*; 19 | import com.intellij.psi.util.TypeConversionUtil; 20 | import org.jetbrains.annotations.NotNull; 21 | import org.jetbrains.annotations.Nullable; 22 | 23 | public class OOResolver { 24 | public static final PsiType NoType = TypeConversionUtil.NULL_TYPE; 25 | 26 | private OOResolver() { 27 | } 28 | 29 | public static @NotNull PsiType getOOType(PsiBinaryExpression e) { 30 | if (e == null || e.getROperand() == null) 31 | return NoType; 32 | return getOOType(e.getLOperand().getType(), e.getROperand().getType(), e.getOperationSign()); 33 | } 34 | 35 | public static @NotNull PsiType getOOType(PsiType left, PsiType right, PsiJavaToken op) { 36 | if (op == null) return NoType; 37 | String methodname = OOMethods.binary.get(op.getText()); 38 | if (methodname != null && right != null) { 39 | PsiType res = resolveMethod(left, methodname, right); 40 | if (res == null) 41 | res = resolveMethod(right, methodname + OOMethods.revSuffix, left); 42 | if (res != null) 43 | return res; 44 | } 45 | return NoType; 46 | } 47 | 48 | public static @NotNull PsiType getOOType(PsiPrefixExpression e) { 49 | if (e == null || e.getOperand() == null) 50 | return NoType; 51 | String methodName = OOMethods.unary.get(e.getOperationSign().getText()); 52 | if (methodName != null) { 53 | PsiType res = resolveMethod(e.getOperand(), methodName); 54 | if (res != null) 55 | return res; 56 | } 57 | return NoType; 58 | } 59 | 60 | public static @NotNull PsiType indexGet(PsiArrayAccessExpression e) { 61 | if (e == null || e.getIndexExpression() == null) 62 | return NoType; 63 | PsiType res = resolveMethod(e.getArrayExpression(), OOMethods.indexGet, e.getIndexExpression()); 64 | return res != null ? res : NoType; 65 | } 66 | 67 | public static @NotNull PsiType indexSet(PsiArrayAccessExpression paa, PsiExpression value) { 68 | if (paa == null) return NoType; 69 | for (String method : OOMethods.indexSet) { 70 | PsiType res = resolveMethod(paa.getArrayExpression(), method, paa.getIndexExpression(), value); 71 | if (res != null) return res; 72 | } 73 | return NoType; 74 | } 75 | 76 | public static boolean isTypeConvertible(PsiType to, PsiExpression from) { 77 | if (from != null) 78 | for (String methodName : OOMethods.valueOf) 79 | if (resolveMethod(from.getProject(), from.getContext(), to.getCanonicalText(), methodName, from) != null) 80 | return true; 81 | return false; 82 | } 83 | 84 | public static @Nullable PsiType resolveMethod(PsiExpression receiver, String methodName, @NotNull PsiExpression... args) { 85 | return resolveMethod(receiver.getProject(), receiver.getContext(), receiver.getText(), methodName, args); 86 | } 87 | 88 | public static @Nullable PsiType resolveMethod(Project proj, PsiElement context, String clas, String methodName, @NotNull PsiExpression... args) { 89 | StringBuilder sb = new StringBuilder(); 90 | sb.append(clas).append(".").append(methodName).append("("); 91 | boolean comma = false; 92 | for (PsiExpression arg : args) { 93 | if (comma) 94 | sb.append(","); 95 | sb.append(arg.getText()); 96 | comma = true; 97 | } 98 | sb.append(")"); 99 | PsiExpression exp = JavaPsiFacade.getElementFactory(proj).createExpressionFromText(sb.toString(), context); 100 | return exp.getType(); 101 | /*if (clas == null || methodName == null) return null; 102 | PsiType[] argTypes = new PsiType[args.length]; 103 | for (int i = 0; i < args.length; i++) { 104 | if (args[i] == null) return null; 105 | argTypes[i] = args[i].getType(); 106 | } 107 | return resolveMethod(clas.getType(), methodName, argTypes);*/ 108 | } 109 | 110 | public static @Nullable PsiType resolveMethod(@Nullable PsiType type, String methodName, @NotNull PsiType... argTypes) { 111 | if (!(type instanceof PsiClassType) || methodName == null) return null; 112 | for (PsiType a : argTypes) 113 | if (a == null) 114 | return null; 115 | PsiClassType clas = (PsiClassType) type; 116 | PsiSubstitutor subst = clas.resolveGenerics().getSubstitutor(); 117 | PsiClass psiClass = clas.resolve(); 118 | if (psiClass == null) 119 | return null; 120 | PsiMethod[] methods = psiClass.findMethodsByName(methodName, true); 121 | for (PsiMethod method : methods) { 122 | PsiParameter[] parameters = method.getParameterList().getParameters(); 123 | for (int i = 0; i < argTypes.length; i++) { 124 | PsiType argType = argTypes[i]; 125 | if(i < parameters.length) { 126 | PsiType methodArgType = parameters[i].getType(); 127 | if(argType.isConvertibleFrom(methodArgType)) 128 | return subst.substitute(method.getReturnType()); 129 | } else return null; 130 | } 131 | } 132 | return null; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/PsiOOArrayAccessExpressionImpl.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.psi.PsiType; 18 | import com.intellij.psi.impl.source.tree.java.PsiArrayAccessExpressionImpl; 19 | 20 | public class PsiOOArrayAccessExpressionImpl extends PsiArrayAccessExpressionImpl { 21 | @Override 22 | public PsiType getType() { 23 | PsiType res = super.getType(); 24 | return res != null ? res : OOResolver.indexGet(this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/PsiOOBinaryExpressionImpl.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.psi.PsiBinaryExpression; 18 | import com.intellij.psi.PsiExpression; 19 | import com.intellij.psi.PsiType; 20 | import com.intellij.psi.impl.source.resolve.JavaResolveCache; 21 | import com.intellij.psi.impl.source.tree.java.PsiBinaryExpressionImpl; 22 | import com.intellij.psi.tree.IElementType; 23 | import com.intellij.psi.util.TypeConversionUtil; 24 | import com.intellij.util.Function; 25 | 26 | public class PsiOOBinaryExpressionImpl extends PsiBinaryExpressionImpl { 27 | 28 | @Override 29 | public PsiType getType() { 30 | return JavaResolveCache.getInstance(getProject()) 31 | .getType(this, (Function) e -> { 32 | if (TypeConversionUtil.isBinaryOperatorApplicable(e.getOperationTokenType(), 33 | e.getLOperand(), e.getROperand(), false)) { 34 | return doGetType((PsiBinaryExpressionImpl) e); 35 | } 36 | return OOResolver.getOOType(PsiOOBinaryExpressionImpl.this); 37 | }); 38 | } 39 | 40 | private static PsiType doGetType(PsiBinaryExpressionImpl param) { 41 | PsiExpression lOperand = param.getLOperand(); 42 | PsiExpression rOperand = param.getROperand(); 43 | if (rOperand == null) return null; 44 | PsiType rType = rOperand.getType(); 45 | IElementType sign = param.getOperationTokenType(); 46 | // optimization: if we can calculate type based on right type only 47 | PsiType type = TypeConversionUtil.calcTypeForBinaryExpression(null, rType, sign, false); 48 | if (type != TypeConversionUtil.NULL_TYPE) return type; 49 | 50 | PsiType lType = lOperand.getType(); 51 | return TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, sign, true); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/PsiOOPolyadicExpressionImpl.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.psi.PsiExpression; 18 | import com.intellij.psi.PsiType; 19 | import com.intellij.psi.impl.source.resolve.JavaResolveCache; 20 | import com.intellij.psi.impl.source.tree.java.PsiPolyadicExpressionImpl; 21 | import com.intellij.psi.tree.IElementType; 22 | import com.intellij.psi.util.TypeConversionUtil; 23 | import com.intellij.util.Function; 24 | import com.intellij.util.NullableFunction; 25 | 26 | public class PsiOOPolyadicExpressionImpl extends PsiPolyadicExpressionImpl { 27 | @Override 28 | public PsiType getType() { 29 | return JavaResolveCache.getInstance(getProject()).getType(this, OO_TYPE_EVALUATOR); 30 | } 31 | 32 | private static final Function OO_TYPE_EVALUATOR = new NullableFunction() { 33 | @Override 34 | public PsiType fun(PsiPolyadicExpressionImpl param) { 35 | // copied from com.intellij.psi.impl.source.tree.java.PsiPolyadicExpressionImpl.doGetType 36 | PsiExpression[] operands = param.getOperands(); 37 | PsiType lType = null; 38 | 39 | IElementType sign = param.getOperationTokenType(); 40 | for (int i = 1; i < operands.length; i++) { 41 | PsiType rType = operands[i].getType(); 42 | // optimization: if we can calculate type based on right type only 43 | PsiType type = TypeConversionUtil.calcTypeForBinaryExpression(null, rType, sign, false); 44 | if (type != TypeConversionUtil.NULL_TYPE) return type; 45 | if (lType == null) lType = operands[0].getType(); 46 | PsiType oldlType = lType; 47 | lType = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, sign, true); 48 | 49 | // try OO if something wrong 50 | if (!TypeConversionUtil.isBinaryOperatorApplicable(sign, oldlType, rType, false)) 51 | lType = OOResolver.getOOType(oldlType, rType, param.getTokenBeforeOperand(operands[i])); 52 | } 53 | return lType; 54 | } 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/PsiOOPrefixExpressionImpl.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.psi.PsiType; 18 | import com.intellij.psi.impl.source.tree.java.PsiPrefixExpressionImpl; 19 | 20 | public class PsiOOPrefixExpressionImpl extends PsiPrefixExpressionImpl { 21 | @Override 22 | public PsiType getType() { 23 | PsiType res = super.getType(); 24 | return res != null ? res : OOResolver.getOOType(this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/braisdom/objsql/intellij/oo/Util.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Artem Melentyev 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.github.braisdom.objsql.intellij.oo; 16 | 17 | import com.intellij.lang.ASTNode; 18 | import com.intellij.psi.impl.source.tree.JavaElementType; 19 | import com.intellij.psi.tree.IElementType; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | import java.lang.reflect.Field; 23 | import java.util.Arrays; 24 | import java.util.function.Supplier; 25 | 26 | public class Util { 27 | private Util() {} 28 | 29 | public static @NotNull Field findField(Class clas, Class type, String... fields) { 30 | for (String field : fields) { 31 | try { 32 | Field f = clas.getDeclaredField(field); 33 | if (f.getType() == type) { 34 | f.setAccessible(true); 35 | return f; 36 | } 37 | } catch (NoSuchFieldException e) { 38 | // continue 39 | } 40 | } 41 | Field found = null; 42 | int count = 0; 43 | for (Field f : clas.getDeclaredFields()) { 44 | if (f.getType() == type) { 45 | count++; 46 | found = f; 47 | } 48 | } 49 | if (count != 1) 50 | sneakyThrow(new NoSuchFieldException(String.format("Can't find %s fields in %s class", Arrays.toString(fields), clas.getName()))); 51 | found.setAccessible(true); 52 | return found; 53 | } 54 | 55 | public static Object get(Class clas, T obj, @NotNull Class type, String... fields) { 56 | try { 57 | return findField(clas, type, fields).get(obj); 58 | } catch (IllegalAccessException e) { 59 | throw sneakyThrow(e); 60 | } 61 | } 62 | 63 | public static void set(Class clas, Object obj, Class type, Object val, String... fields) { 64 | try { 65 | findField(clas, type, fields).set(obj, val); 66 | } catch (Exception e) { 67 | throw sneakyThrow(e); 68 | } 69 | } 70 | 71 | public static void setJavaElementConstructor(IElementType et, Supplier constructor) { 72 | set(JavaElementType.JavaCompositeElementType.class, et, Supplier.class, constructor, "myConstructor", "a"); 73 | } 74 | 75 | public static RuntimeException sneakyThrow(Throwable ex) { 76 | return Util.sneakyThrowInner(ex); 77 | } 78 | private static T sneakyThrowInner(Throwable ex) throws T { 79 | throw (T) ex; 80 | } 81 | } -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.github.braisdom.object-sql-intellij 3 | ObjectiveSql 4 | ObjectiveSql 5 | 1.3.4 6 | 7 | Tools Integration 8 | Filling the generated elements for ObjectSql. Discuss, review, and share code with your 10 | team in your JetBrains. The compile error of auto-generated code will be suppressed, and 11 | it implements code completion with PsiAugmentProvider in the IntelliJ

12 |

Supported annotations of ObjectiveSql:

13 |
    14 |
  • @DomainModel
  • 15 |
  • @Column
  • 16 |
  • @PrimaryKey
  • 17 |
  • @Queryable
  • 18 |
  • @Transactional
  • 19 |
  • @Relation
  • 20 |
  • @Transient
  • 21 |
22 |

See more: ObjectiveSql

23 | ]]>
24 | V1.0

26 |

1. Generating setter and getter methods for model who has annotation @DomainModel

27 |

2. Generating query and persistence methods for model who has annotation @DomainModel

28 |

3. Generating query method for field who has annotation @Queryable

29 |

4. Generating relation method for field who has annotation @Relation

30 |

...

31 | ]]>
32 | 33 | com.intellij.modules.lang 34 | com.intellij.modules.platform 35 | com.intellij.modules.java 36 | 37 | 38 | 39 | com.github.braisdom.objsql.intellij.oo.OOComponent 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
--------------------------------------------------------------------------------