summaryrefslogtreecommitdiff
path: root/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2013-10-15 19:49:27 -0700
committerTor Norbye <tnorbye@google.com>2013-10-15 19:49:46 -0700
commit767536605379e492929a763f4a585cb4f499b9f6 (patch)
treeb82400bd5a1609a29dfb9d40d4b54cfac2daaabd /plugins/InspectionGadgets/InspectionGadgetsAnalysis/src
parent32218cc024d27dc92563b5b45007c94057c1c423 (diff)
downloadidea-767536605379e492929a763f4a585cb4f499b9f6.tar.gz
Snapshot 246ebf4786ef75849985fa5fba6015155ebac527 from idea/132.637 of git://git.jetbrains.org/idea/community.git
246ebf4: better gradient colors for Darcula 8833be9: should be opaque 9a1a2f2: fix darcula text fields 001ed5d: add "perflib" from tools-base module to build c348af4: Github: do not provide Git AuthData for wrong host 7424aca: Github: compare hosts case-insensitive 7ce90f4: fix double Shift on Windows 050b38c: check value of Required annotation; do not check required attributes of dom elements in XmlHighlightingVisitor; revive testing of required attribute validation in PluginXmlFunctionalTest 59d7274: IDEA-114873 (Add Package Info item to New submenu) c4d7c3e: codestyle fix 9f3e60a: trace about substitutor once per derived class, in order to avoid excessive logging 27952b2: moved FinderRecursivePanel to platform-impl 94b9f06: IDEA-114850 Unreadable "No files are open" text 1fd5b2d: removing nested frameworks 4098566: capitalization (IDEA-81968) 10f8420: diagnose incorrect MixinEP registration (IDEA-113506) 35689ca: add apiVersion parameter to build.xml so that Android Studio can use exact platform build they're compatible with (IDEA-114596) cb53ae1: Multiline support for regexp editor ddef70e: Lens mode (hint location fixes) f8d6bf8: disable escaper for balloons 99d486d: check for language 26fa119: support for java regexp modifiers 925000e: Ability to handle regexps with modifiers 67f1c14: automake is run only for the project where current user activity is going on (IDEA-104064) d5cad13: fix naturalCompare() edge case c1f7724: Merge remote-tracking branch 'origin/master' 862fb67: proper bounds for search everywhere button d21dc3f: new shortcut for search everywhere 4283182: completely new UI 50e5c52: colors for white theme 08f4c9e: don't paint parent's background 0ed4058: active icon for Search Everywhere 17a6674: don't reset row height 52f84a7: IDEA-114694 Shift-Space is a terrible default shortcut for Search Everywhere 099ead0: dfa: exception handling reworked no more gosub-return causing equal states differing by offset stack only don't visit outer finally without visiting inner one 3744d2c: IDEA-114736 Bug in code completion inside instanceof block 377acad: correctly initialize semaphore for all BasicFuture implementations 81bfb1e: Lens mode (mouse wheel support & many fixes) 81d90a7: Get rid of extra UISettings notifications 2fb0092: Github: fix UrlToHost function 75f4e1f3: plugin advertisement: show disabled plugin name 8ed1b68: plugins advertisement: enabled installed plugin 53ad76d: IDEA-114708 Wrong Up/Down action interpretation in consoles (irb/Bash) e818b6e: use fileEditor's editor instead of some random editor from dataContext bd152a4: IDEA-89857 automatically adds required attributes in dom-based xml; insert correct endings for View/ViewGroup tags 7988d09: test for not building stubs for java files in module but not under source roots, in library but not in class root 131353b: IDEA-112134 $SELECTION$ variable doesn't work as true variable, but as $END$ cac9208f: item 1 of IDEA-95649 (Darcula: Settings -> File Templates doesn't follow theme colors) ab2d2ca: remove color to display file template descriptions nicely under Darcula 7fb7911: use correct company name in version info (IDEA-82623) 5bd4249: WEB-8027 long single line values in debugger hang IntelliJ + review 4710a08: show editor notification for text mapped files about known plugins from the repository 62c87af: logging for incorrect move eab3d4c: plugin advertising: stop if update was disabled 25584ad: Add MONTH_NAME_SHORT and MONTH_NAME_FULL definition & improve file template descriptions 4f10bd1: CR-IC-2706 (logging added) eef188b: Add diagnostic info of invalid template ranges fd7c9d0: EA-50616 618a573: license added? d29c66e: Drivers management refactored f280f8b: update netty (attempt to understand why nodejs disconnected on second run, but it was not netty fault) 15d9033: selecting right project type 4111497: http://ea.jetbrains.com/browser/ea_problems/50978 65eff28: EA-50605 - NPE: AbstractExternalSystemTaskConfigurationType.generateName f43865d: Slightly reworked formatter markers' UI in accordance with IDEA-114583 8e51528: give file template description a bit more room 9d2f4f9: CR-IC-2705, fixed for Mac 55b6603: fix default file template descriptions 6fd90c1: Revert optimization, because MAC tests fail. d11966f: IDEA-114766 Gradle: module dependency scope ignored while project info resolving 359ddf8: IDEA-114647 (fsnotifier size check updated) 0f10404: license added 780fa6e: allow watching exFAT (IDEA-114647) f8dc1eb: lib license added efb3281: testdata for IDEA-67591 993fb34: highlighting for incompatible return types in type parameter inheritors (IDEA-57274) e03245e: Cleanup (comment) 51a77de: platform: garbage production by FIleWatcher reduced 06b198e: Cleanup (typo; dead code) d8729d5: platform: partial refresh fixed af0637c: Merge remote-tracking branch 'origin/master' 121ee3e: Add helper method for pretty-printing JSON in TaskUtil class. Improve logging in GenericRepository. 461c6d7: testng: parameterized template (IDEA-114746) 5a50ed8: do not detach copyright updater on project closed (IDEA-114186) f06771b: restart infer nullity when library already exist (IDEA-114163) b33fa7f: effectively final: check flow at variable start (IDEA-114737) 46e9f4b: testdata for IDEA-57252 82b6b16: testdata for IDEA-67518 6a9313c: type parameter in bounds check: separate wildcards with type param in bound efc19ab: new inference: do not ignore meaningful upper bounds cbff339: Optimization: don't use FileUtil.pathsEqual() , paths returned by FileWatcher is already canonical. 2723de7: don't fold already concise getters (EA-50804) 17dae78: IDEA-114699 Live template without description shows "NULL" 56e5602: a simpler way to setup live templates in tests 3ea2e38: Jediterm updated. a47f9d3: Change cache lookup logic in XML and JSON response handlers 4ce5dec: Don't urlencode "serverUrl" template variable in GenericRepository fields 38c05d9: IDEA-114076 Unit tests can't be executed with a JRE 1.5 because junit-rt.jar is compiled with JRE 6.0 as target bb8bb2a: moved to analysis 376fe99: moved to analysis ff48d6d: moved to analysis 3fcf2d5: moved to analysis 1825351: moved to analysis 563ffda: moved to analysis dc477a1: moved to analysis 3c18086: moved to analysis 472bab7: moved to analysis 473e45d: moved to analysis 65f35d7: moved to analysis a36aaf6: moved to analysis 5f10c64: moved to analysis c3bf35d: moved to analysis b6fbbb6: moved to analysis 6a9d91b: moved to analysis 7582706: moved to analysis ef37a6c: moved to analysis 1ea667f: moved to analysis 8985a7e: moved to analysis 37691e0: moved to analysis 08ba033: moved to analysis f069df4: moved to analysis 3ac7210: moved to analysis 5e9a1e1: moved to analysis 74ecd51: moved to analysis 33f20b1: moved to analysis 936f232: read action da37289: moved to analysis e0e3724: moved to analysis 53e0050: moved to analysis 5240818: moved to analysis 50f7722: moved to analysis 8b64b6d: moved to analysis 62c27c4: moved to analysis 0dba483: moved to analysis c7bfbeb: moved to analysis 6bf16de: moved to analysis 180ea57: moved to analysis b8fcd01: moved to analysis b19c765: moved to analysis 636378c: moved to analysis 7c63c331: moved to analysis b47e90d: moved to analysis 44e0bd5: moved to analysis 4957a2c: moved to analysis bad582a: moved to analysis 2a4c6df: moved to analysis bf5ae61: moved to analysis f547ee5: moved to analysis c6d5ca6: moved to analysis c3dc3f2: moved to analysis 27f40d2: moved to analysis 82cc0c1: moved to analysis e309872: moved to analysis c6806d7: moved to analysis 66b131c: test fix 5819121: moved to analysis ace2035: moved to analysis 300fed6: moved to analysis 73d5646: moved to analysis 1efaa3b: moved to analysis 930eabe: moved to analysis 34c381d: moved to analysis 8094570: moved to analysis bb3273c: moved to analysis aec65a6: moved to analysis cbc892a: moved to analysis b42dc77: moved to analysis ba6923d: moved to analysis 2283aa0: moved to analysis 1aeb0d3: moved to analysis e08c9f1: moved to analysis 03cd373: moved to analysis caaf810: moved to analysis 0e924cf: moved to analysis f3e0d0a: moved to analysis 51ec5ea: moved to analysis 94fb66f: moved to analysis 6aaaaae: moved to analysis 08e51ae: moved to analysis cf12745: moved to analysis b34f44f: moved to analysis 37f3cdc: moved to analysis 036a2b6: moved to analysis 4931ffa: moved to analysis 8e59ca1: moved to analysis 02c0c01: moved to analysis 89a55b0: moved to analysis cba23f4: moved to analysis 1b1fb1c: moved to analysis bd725cd: moved to analysis dfcc51d: moved to analysis fad8af3: moved to analysis 827e5a5: moved to analysis 2360dcd: moved to analysis 008c56a: moved to analysis 758ba60: moved to analysis 731c642: moved to analysis d5adf28: moved to analysis b892f8b: moved to analysis 7513254: moved to analysis e3a752c: moved to analysis 03219ce: moved to analysis f06ad8a: moved to analysis 2c4614a: moved to analysis 4e076dd: moved to analysis 7f3ee23: moved to analysis 50835cc: moved to analysis ff01a67: moved to analysis 084113a: moved to analysis e197319: moved to analysis 1d7f251: moved to analysis e2fc894: moved to analysis d48b36b: EA-50870 - IAE: GroovyPropertyUtils.getGetterNameNonBoolean 0fb3c6e: IDEA-57747 (Idea X - CTRL+SHIFT+Left/Right Arrow functionality) 2cbff34: Github: use standard YesNoDialog 53782b5: Github: use strict class check a42b1d9: when launching build process or javac server suppress libraries from 'ext' directories to ensure compiler is loaded from correct location f40dfd1: OC-8512 Exception when typing on empty line at non-zero column during indexing 917a3a1: cleanup c821ba0: moved to analysis 56da4ee: moved to core 38dbce1: cleanup d8bd506: ForkJoin support 9f4a9d0: moved to analysis da9996b: moved to analysis f44d265: fix due to CR-IC-2640 comment 75b7026: Merge remote-tracking branch 'origin/master' 48e70d3: used lower level char buffer instead of document.getText() due to CR-IC-2640 comment 1271549: project structure: increased default size of source roots tree a24ebae: Merge remote-tracking branch 'origin/master' a9fc3c6: cleanup adb2f16: diagnostics for EA-50397 - assert: TextRange.<init> 2244946: EA-50612 - NPE: EditorWindow$.run a64cbc3: Logger renamed to more specific name 2cbf40b: EA-50756 - NPE: DefaultXmlExtension.getAvailableTagNames diagnostics c25431e: new inference: skip inference for nested call when nested call was initially requested to be inferred 5fda195: detailed diagnostic for compiler class loading problems c178ebf: workaround for EA-49915, EA-50599 5e7f578: go to the errors first by default 42ad23d: when matching local variables slots and variable names from sources take into account loop and catch statements 69424d4: run test method from abstract class: ignore non-runnable inheritors; try to retrieve from context implicitly selected inheritor (IDEA-114551) 8e51c80: override: fix param names in javadoc (IDEA-114557) 977e332: PY-11027 (ignore placeholder argument from non-compliant DEs) c3af1f1: Merge remote-tracking branch 'origin/master' fa5fa39: Test skipped for Win XP bad439d: execution tests probably fixed 1e54387: range changed (IDEA-114528) 93c8631: infer nullity: more pessimistic check: check variables first (IDEA-114630) 6fb01cd: global inspections documentation cleanup 087b52a: WEB-445 "Select word at caret" a bit to grabby in class attributes 046efd8: highlight missing package-info.java in editor too b525330: Errors beef6c6: GroovyDirectInheritorsSearcher: avoid unnecessary collection->array copying 0596f3d: remove @NotNull from SortedMap#comparator (IDEA-114655) eb9828f: IDEA-114203: Add new "Options" tab in YouTrack repository editor where user can customize states names 4371063: Delete repository problem notification b8d1054: CR-IC-2693 3f3b474: CR-IC-2690 0ce5ae9: displaying version number in tree 2271eaf: IDEA-114633 (symlink deletion regression fixed) 569a70d: Cleanup (FileUtil tests grouped) 9fdcf65: Cleanup (formatting) ca49f7d: Cleanup (unnecessary condition) 46d04cb: FrameworkLibraryVersion separated from FrameworkVersion a8fc158: recognize IBM JDK from WebSphere 8 (IDEA-90661) 65f1157: Merge branch 'svn1_8_new' f165eb7: named NodeRendererImpl constructor; adjust test expectations 117f86f: corrected e173999: FrameworkGroupVersion dropped 9948d9d: Merge remote-tracking branch 'origin/master' 76f6788: fix exception on some linux machines f6f6664: IDEA-114517 Use server url (and not repository url) as authentication realm for https server certificate 5e77c10: IDEA-114517 Force certificate errors checking before credentials error checking 13c6c0a: Merge remote-tracking branch 'origin/master' 784bfa5: Merge remote-tracking branch 'origin/master' 9f25ff8: jdk8 compilation 80265c1: plugin advertiser: escape # in feature implementation efc8a3d: EA-50528 - MJE: JsonReader.syntaxError 2e10f33: IDEA-99241 (Report package naming convention violations in the editor) 1cc2fa4: made fields final 4374c69: replace exception-driven control flow with the proper one f0cba21: moved to analysis d9b6c0f: moved to psi f8c15cf: moved to psi 836e381: cleanup 2e0029d: moved to analysis 6484602: make TempFileSystem extends LocalFileSystem to simplify clients and tests 662eb80: cleanup 0ebcf72: moved to analysis 250fff4: moved to analysis 3906227: moved to analysis a24ae6d: moved to analysis e8fc8c6: moved to psi 7a468ca: moved method to core 82060fd: cleanup 04c524c: reduce dependency on LocalFileSystem 8cdab66: frameworks tree refactored 9b45d86: WEB-9563 There is a bug with Emmet and BEM namings 29ecf27: guess DTD by public id #WEB-9546 fixed c697898: JavaEE frameworks sorted out 6dc8386: less side effects 99e0eae: test is back e2d2093: Gradle: gradle-native deps added 7507dc5: do not autoscroll when in focus, e.g. selection changing action may be triggered directly from structure 346c501: add model change support & some formatting d6ff1a1: Merge remote-tracking branch 'origin/master' b6a044a: Respect auto-save and auto-sync settings. e1f4afb: IDEA-60234 Automatically unwrap groovy.lang.Reference in the debugger 0dcb367: make topic final c5ce0b8: IDEA-114604 Evaluate Expression doesn't change context after navigating call stack +review f9411d3: cleanup 89d03b1: overrides 147d5ea: cleanup aef6c9e: extracted method to avoid code duplication 4cffaf3: on rebuild clear system caches for compilers run internally in IDEA f72bc3d: add darcula green color 31d24b4: better colors for darcula 4ef7b0c: glow color for IntelliJ laf 36aad83: refactor button and checkbox 9181562: search field style for IntelliJ LaF cff6f4b: use triangles in IntelliJ LaF trees c4ebcef: add IntelliJ LaF dee1ff7: IntelliJ laf a152352: customize Darcula LaF from IntelliJ LaF 6e97b12: tree icons for IntelliJ LaF 69dbc89: inference: do not check return type during inference; separate highlighting check 9e060c7: cast 51f471a: Format pom.xml on create new module. 2624ec6: IDEA-114593 Debugger: Show variable information when no debug info 1918d6e: overrides, nullability c463545: platform: race between JNA and environment loading fixed 943cea6: Accidentally forget to add annotator to plugin.xml 0dc87d5: IDEA-50801 Evaluate expression: expand root node automatically +review 79c7ba5: overrides 5e841a7: fix testdata 7c84b97: Update JqlAnnotator to highlight JqlIdentifiers as constants, not as strings, to be consistent with YouTrack queries colors e0ac1f1: Merge remote-tracking branch 'origin/master' dfc9912: fixed PY-10964 Extract variable doesn't work as expected inside brackets fixed PY-10221 Refactor->Extract->Variable may break square bracket symmetry and may break user input 9c38ae3: Extract pretty-printing of XML responses to helper method in TaskUtil, use StringUtil.notNullize in YouTrackIntellisense models. 6c49b66: IDEA-114523 Fixed svn executable version parsing - support arbitrary text after version (in executable output) 7157489: Make myWorkspaceMap and myUnresolvedCollector volatile. 35e76f4: Comment for getNameThroughCopies method added cb377a5: spelling fixed b5eeae5: svn: Refactored RootUrlInfo - utilize underlying Node instance (instead of just copying fields) b615000: IDEA-113670 Reformat+rearrange per-language setting [CR-IC-2682] b37e22e: Merge remote-tracking branch 'origin/master' 7a40a2c: svn: @NotNull/@Nullable for NestedCopyInfo and RootUrlInfo parameters 05e6734: cleanup 60b90f9: cleanup 6e534ce: update netty (07 oct 4.1 Alpha build) Updated, but ref error was our fault, it is not netty bug. b1d9994: inference: filter out inaccessible for method ref methods 56be1b2: svn: Updated detection if svn roots were changed - added error roots tracking 265806c: svn: Simplified svn executable validation logic - removed explicit major version check 3aadab0: svn: Removed check "if working copy format of project root is compatible with command line client" (during svn executable validation) be91b71: svn: Added notification about errors during svn roots detection 7e742f4: Merge remote-tracking branch 'origin/master' 1c1e2ee: svn: Extracted showing "Subversion Working Copies Information" panel to separate method 16b2321: EA-50707 - assert: TextRange.<init> 35546a0: new inference: ignore captured variables incorporation phase 8c0d7a1: testRunner: wording (IDEA-114500) as attached state is everywhere checked separately 9641ede: plugins notification: hide notification before dialog is shown 3ecdadc: ctors closed 199a379: framework roles 2d68bc5: platform: hidden Windows root dir with NIO2 attribute reader fixed 5ff5b2e: IDEA-113961 (ownership checking) 498d04f: IDEA-113961 (permissions in file attributes deprecated and interned) d9f1d4f: Cleanup (pointless assertion) 415b782: svn: Implemented ability to view svn roots detection errors in "Subversion Working Copies Information" panel f1ecb53: svn: Refactored RootUrlInfo - utilize Node instance on which RootUrlInfo is based b726526: svn: Implemented ability to detect svn roots when working copy format does not correspond to used client (SVNKit or executable could not perform commands on the working copy - for instance, when client is old or working copy upgrade required) 67bdd3a: svn: Implemented ability to resolve client factory and working copy format without checking detected svn roots b15784f: add some ways for reuse in DB part & cleanup 8dae62f: do not proceed with painting if placeHolder text was really painted, i.e. skip error markup, selection, etc 5795402: new inference: reject explicitly typed lambda as pertinent to applicability if its return statements are poly ae3b46c: new inference: temp: ignore inferred Object at first stage 8d2b3e3: new inference: accept methods in lambda return statement as poly without additional checks 5c40157: fixed NPE 5bf3698: Reimplement select word tests for CSS, CoffeeScript, Ruby, Python, Sass, Scss and Less a99db1d: Add test utility method for select word action testing 203e791: prefer variants without leading underscores when case sensitivity=first letter (OC-3547) 4af89f65: IDEA-114514 Grammar error in "Library already exists" dialog 215044f: Allow current element selection in StructureViewer for non-editors. 4ddd1f8: dont' copy editor markup model in language console f2ec48d: extends and implements clauses should always exist in type definitions c3ef7a1: GroovyBlockWithRange f0b2208: Merge remote-tracking branch 'origin/master' c495919: Merge remote-tracking branch 'origin/master' 7ae82a0: Save documents on switch to terminal refresh VFS on switch from it (PY-10944). 14cc2d5: IDEA-114534 Gradle: cancelation of gradle tasks for "out-of-process" mode 4684ba7: Add package-info.java checking to "Declaration has problems in Javadoc references" inspection 53c1eff: [log] Move logProvider extension point to the right place: vcs-log.xml b667798: decode file name for quickfix #WEB-9559 fixed bb34511: new inference: ignore inferred wildcards in return position 74aa35f: new inference: postpone resolve as long as possible 506188d: new inference: mark unresolved calls as poly expressions 3b99b77: Refactor annotator to use visitor 57f9383: Add annotator for inspecting some common errors in JQL queries c889c0a: svn: Refactored vcs roots detection - CopiesDetector moved/renamed to separate class, detection output extracted to separate class cf66975: svn: Forced status command result contain repository root url (resolved with corresponding info command) 2a7389c: svn: Refactored Node class to have notnull fields 69d918e: svn: Refactored WCInfo - utilize RootUrlInfo on which WCInfo is based (instead of just copying fields) a9da4bc: svn: Refactored RootUrlInfo - removed setType() usages where possible 5f09493: svn: Refactored nested copy detection - removed unused code 6eee591: svn: Refactored nested copy detection - extractions, renames, simplified logic b3eeb5e: svn: Refactored nested copy detection - use instance instead of static methods 238c879: svn: Refactored nested copy detection - removed Real class 38db9bf: svn: Refactored nested copy detection - moves, renames dd8b94c: svn: Refactored nested copy detection - simplified data structures for storing nested copies (while collecting changes with ChangeProvider) 8fbc758: svn: Refactored filtering roots that are not actually working copies - methods extracted, logic simplified 66608ee: svn: Refactored inner/external working copies detection - removed unused code 06f90ae: svn: Refactored inner/external working copies detection - methods extracted, logic simplified b44d86f: svn: Refactored nested copies detection by folder status - simplified code flow e397390: svn: Replaced working copy format detection using SVNStatus.getWorkingCopyFormat() with SvnVcs.getWorkingCopyFormat() (1.7 and 1.8 both have "12" entries file format and previously 1.7 was always returned for command line status command) f0a4f49: svn: Refactored working copy format detection for rollback missing files/directories - do not use SVNStatus.getWorkingCopyFormat() 0bdd518: svn: Refactored getting changelist name from SVNStatus - removed duplication and check if working copy format supports change lists 054bf7f: svn: Refactored CommandUtil.escape (simplified) e211be2: svn: Removed unused WorkingCopyFormat parameter from StatusReceiver 8d5fffd: svn: Fixed "upgrade working copy format" dialog - always make current working copy format enabled Change-Id: I928a2caf9bf9d566fb9f556ce39acb5111119c9c
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis/src')
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java179
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspection.java6
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseSharedLocalInspection.java45
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledCompareToInspectionBase.java63
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledEqualsInspectionBase.java62
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledHashcodeInspectionBase.java63
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledToStringInspectionBase.java63
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspectionBase.java68
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspectionBase.java81
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspectionBase.java78
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/EmptyClassInspectionBase.java172
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspectionBase.java94
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspectionBase.java60
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspectionBase.java77
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionBase.java61
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspectionBase.java75
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/PublicConstructorInspectionBase.java101
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassInspectionBase.java72
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspectionBase.java151
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspectionBase.java112
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspectionBase.java118
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspectionBase.java105
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/ThrowsRuntimeExceptionInspectionBase.java66
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/TooBroadCatchInspectionBase.java182
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspectionBase.java126
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/imports/StaticImportInspectionBase.java317
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionBase.java74
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java163
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java102
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspectionBase.java157
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspectionBase.java75
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverriddenMethodCallDuringObjectConstructionInspection.java81
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/internationalization/MagicCharacterInspectionBase.java80
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java74
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java92
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java80
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspectionBase.java86
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AssertAsNameInspectionBase.java101
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/EnumAsNameInspectionBase.java101
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java88
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java76
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java115
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java128
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java72
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java72
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java129
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java72
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java255
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java236
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspectionBase.java111
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithoutLoggerInspectionBase.java119
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java273
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggerInitializedWithForeignClassInspectionBase.java202
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggingConditionDisagreesWithLogStatementInspection.java355
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspectionBase.java112
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java128
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PublicMethodWithoutLoggingInspectionBase.java142
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/StringConcatenationArgumentToLogCallInspection.java303
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoCommentInspection.java54
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoUtil.java42
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ZeroLengthArrayInitializationInspectionBase.java91
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java223
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspectionBase.java195
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java920
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java547
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java272
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java158
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java189
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java214
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java568
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryWithIdenticalCatchesInspection.java247
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java336
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java325
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java337
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/AnnotationNamingConventionInspectionBase.java93
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/BooleanMethodNameMustStartWithQuestionInspectionBase.java123
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspectionBase.java90
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspectionBase.java94
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamingConventionInspectionBase.java98
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConfusingMainMethodInspectionBase.java88
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConstantNamingConventionInspectionBase.java103
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConventionInspection.java96
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/DollarSignInNameInspectionBase.java89
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedClassNamingConventionInspectionBase.java93
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedConstantNamingConventionInspectionBase.java86
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspectionBase.java83
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java102
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspectionBase.java95
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InterfaceNamingConventionInspectionBase.java93
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspectionBase.java133
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspectionBase.java74
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspectionBase.java81
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNamesDifferOnlyByCaseInspectionBase.java87
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonBooleanMethodNameMayNotStartWithQuestionInspectionBase.java125
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspectionBase.java74
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedMethodsWithSameNumberOfParametersInspection.java108
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java75
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/PackageNamingConventionInspection.java186
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspectionBase.java115
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNamingConventionInspectionBase.java103
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/QuestionableNameInspectionBase.java113
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StandardVariableNamesInspectionBase.java155
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java92
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspectionBase.java114
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/TypeParameterNamingConventionInspectionBase.java96
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspectionBase.java76
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/OverlyComplexArithmeticExpressionInspectionBase.java156
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspectionBase.java102
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/ToArrayCallWithZeroLengthArrayArgumentInspectionBase.java105
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/ExternalizableWithoutPublicNoArgConstructorInspectionBase.java93
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/NonSerializableFieldInSerializableClassInspectionBase.java95
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspectionBase.java90
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspectionBase.java96
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspectionBase.java56
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldVisitor.java79
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspectionBase.java43
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassVisitor.java63
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInspectionBase.java71
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/ChainedMethodCallInspectionBase.java91
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java88
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspectionBase.java213
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspectionBase.java135
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ExtendsThreadInspectionBase.java72
123 files changed, 16436 insertions, 14 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java
new file mode 100644
index 000000000000..9015fe3aabb4
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.booleanIsAlwaysInverted;
+
+import com.intellij.analysis.AnalysisScope;
+import com.intellij.codeInsight.daemon.GroupNames;
+import com.intellij.codeInspection.*;
+import com.intellij.codeInspection.reference.*;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+public class BooleanMethodIsAlwaysInvertedInspectionBase extends GlobalJavaBatchInspectionTool {
+ private static final Key<Boolean> ALWAYS_INVERTED = Key.create("ALWAYS_INVERTED_METHOD");
+
+ private static boolean hasNonInvertedCalls(final RefMethod refMethod) {
+ final Boolean alwaysInverted = refMethod.getUserData(ALWAYS_INVERTED);
+ if (alwaysInverted == null) return true;
+ if (refMethod.isExternalOverride()) return true;
+ if (refMethod.isReferenced() && !alwaysInverted.booleanValue()) return true;
+ final Collection<RefMethod> superMethods = refMethod.getSuperMethods();
+ for (RefMethod superMethod : superMethods) {
+ if (hasNonInvertedCalls(superMethod)) return true;
+ }
+ return false;
+ }
+
+ private static void traverseSuperMethods(RefMethod refMethod,
+ GlobalJavaInspectionContext globalContext,
+ GlobalJavaInspectionContext.UsagesProcessor processor) {
+ final Collection<RefMethod> superMethods = refMethod.getSuperMethods();
+ for (RefMethod superMethod : superMethods) {
+ traverseSuperMethods(superMethod, globalContext, processor);
+ }
+ globalContext.enqueueMethodUsagesProcessor(refMethod, processor);
+ }
+
+ private static void checkMethodCall(RefElement refWhat, final PsiElement element) {
+ if (!(refWhat instanceof RefMethod)) return;
+ final RefMethod refMethod = (RefMethod)refWhat;
+ final PsiElement psiElement = refMethod.getElement();
+ if (!(psiElement instanceof PsiMethod)) return;
+ final PsiMethod psiMethod = (PsiMethod)psiElement;
+ if (!PsiType.BOOLEAN.equals(psiMethod.getReturnType())) return;
+ element.accept(new JavaRecursiveElementVisitor() {
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression call) {
+ super.visitMethodCallExpression(call);
+ final PsiReferenceExpression methodExpression = call.getMethodExpression();
+ if (methodExpression.isReferenceTo(psiMethod)) {
+ if (isInvertedMethodCall(methodExpression)) return;
+ refMethod.putUserData(ALWAYS_INVERTED, Boolean.FALSE);
+ }
+ }
+ });
+ }
+
+ private static boolean isInvertedMethodCall(final PsiReferenceExpression methodExpression) {
+ final PsiPrefixExpression prefixExpression = PsiTreeUtil.getParentOfType(methodExpression, PsiPrefixExpression.class);
+ if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) return true; //don't flag super calls
+ if (prefixExpression != null) {
+ final IElementType tokenType = prefixExpression.getOperationTokenType();
+ if (tokenType.equals(JavaTokenType.EXCL)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionsBundle.message("boolean.method.is.always.inverted.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String getGroupDisplayName() {
+ return GroupNames.DATA_FLOW_ISSUES;
+ }
+
+ @Override
+ @NotNull
+ @NonNls
+ public String getShortName() {
+ return "BooleanMethodIsAlwaysInverted";
+ }
+
+ @Override
+ @Nullable
+ public RefGraphAnnotator getAnnotator(@NotNull final RefManager refManager) {
+ return new BooleanInvertedAnnotator();
+ }
+
+ @Override
+ public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity,
+ @NotNull AnalysisScope scope,
+ @NotNull final InspectionManager manager,
+ @NotNull final GlobalInspectionContext globalContext) {
+ if (refEntity instanceof RefMethod) {
+ RefMethod refMethod = (RefMethod)refEntity;
+ if (!refMethod.isReferenced()) return null;
+ if (hasNonInvertedCalls(refMethod)) return null;
+ if (!refMethod.getSuperMethods().isEmpty()) return null;
+ final PsiMethod psiMethod = (PsiMethod)refMethod.getElement();
+ final PsiIdentifier psiIdentifier = psiMethod.getNameIdentifier();
+ if (psiIdentifier != null) {
+ return new ProblemDescriptor[]{manager.createProblemDescriptor(psiIdentifier,
+ InspectionsBundle
+ .message("boolean.method.is.always.inverted.problem.descriptor"),
+ (LocalQuickFix)getQuickFix(null),
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)};
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager,
+ @NotNull final GlobalJavaInspectionContext context,
+ @NotNull final ProblemDescriptionsProcessor descriptionsProcessor) {
+ manager.iterate(new RefJavaVisitor() {
+ @Override
+ public void visitMethod(@NotNull final RefMethod refMethod) {
+ if (descriptionsProcessor.getDescriptions(refMethod) != null) { //suspicious method -> need to check external usages
+ final GlobalJavaInspectionContext.UsagesProcessor usagesProcessor = new GlobalJavaInspectionContext.UsagesProcessor() {
+ @Override
+ public boolean process(PsiReference psiReference) {
+ final PsiElement psiReferenceExpression = psiReference.getElement();
+ if (psiReferenceExpression instanceof PsiReferenceExpression &&
+ !isInvertedMethodCall((PsiReferenceExpression)psiReferenceExpression)) {
+ descriptionsProcessor.ignoreElement(refMethod);
+ }
+ return false;
+ }
+ };
+ traverseSuperMethods(refMethod, context, usagesProcessor);
+ }
+ }
+ });
+ return false;
+ }
+
+ private static class BooleanInvertedAnnotator extends RefGraphAnnotator {
+ @Override
+ public void onInitialize(RefElement refElement) {
+ if (refElement instanceof RefMethod) {
+ final PsiElement element = refElement.getElement();
+ if (!(element instanceof PsiMethod)) return;
+ if (((PsiMethod)element).getReturnType() != PsiType.BOOLEAN) return;
+ refElement.putUserData(ALWAYS_INVERTED, Boolean.TRUE); //initial mark boolean methods
+ }
+ }
+
+ @Override
+ public void onMarkReferenced(RefElement refWhat, RefElement refFrom, boolean referencedFromClassInitializer) {
+ checkMethodCall(refWhat, refFrom.getElement());
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspection.java
index cc50b2af1124..d8b12a9f9843 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ public abstract class BaseInspection extends BaseJavaBatchLocalInspectionTool {
@Override
@NotNull
- public final String getShortName() {
+ public String getShortName() {
if (m_shortName == null) {
final Class<? extends BaseInspection> aClass = getClass();
final String name = aClass.getName();
@@ -150,7 +150,7 @@ public abstract class BaseInspection extends BaseJavaBatchLocalInspectionTool {
for (List<String> out : outs) {
out.clear();
}
- int iMax = strings.size();
+ final int iMax = strings.size();
for (int i = 0; i < iMax; i += outs.length) {
for (int j = 0; j < outs.length; j++) {
final List<String> out = outs[j];
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseSharedLocalInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseSharedLocalInspection.java
new file mode 100644
index 000000000000..561ed26b4c97
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseSharedLocalInspection.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig;
+
+import com.intellij.codeInspection.GlobalInspectionTool;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public abstract class BaseSharedLocalInspection<T extends GlobalInspectionTool> extends BaseInspection {
+
+ protected final T mySettingsDelegate;
+
+ public BaseSharedLocalInspection(T settingsDelegate) {
+ mySettingsDelegate = settingsDelegate;
+ }
+
+ @NotNull
+ @Override
+ public final String getShortName() {
+ return mySettingsDelegate.getShortName();
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public final String getDisplayName() {
+ return mySettingsDelegate.getDisplayName();
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledCompareToInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledCompareToInspectionBase.java
new file mode 100644
index 000000000000..75a6909949c5
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledCompareToInspectionBase.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.bugs;
+
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameterList;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class MisspelledCompareToInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "misspelled.compareto.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "misspelled.compareto.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MisspelledCompareToVisitor();
+ }
+
+ private static class MisspelledCompareToVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //note: no call to super
+ @NonNls final String methodName = method.getName();
+ if (!"compareto".equals(methodName)) {
+ return;
+ }
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() != 1) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledEqualsInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledEqualsInspectionBase.java
new file mode 100644
index 000000000000..8bba89165852
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledEqualsInspectionBase.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.bugs;
+
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameterList;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class MisspelledEqualsInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "misspelled.equals.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "misspelled.equals.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MisspelledEqualsVisitor();
+ }
+
+ private static class MisspelledEqualsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //note: no call to super
+ @NonNls final String methodName = method.getName();
+ if (!"equal".equals(methodName)) {
+ return;
+ }
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() != 1) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledHashcodeInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledHashcodeInspectionBase.java
new file mode 100644
index 000000000000..435cfed288d0
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledHashcodeInspectionBase.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.bugs;
+
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameterList;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class MisspelledHashcodeInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "misspelled.hashcode.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "misspelled.hashcode.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MisspelledHashcodeVisitor();
+ }
+
+ private static class MisspelledHashcodeVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //note: no call to super
+ @NonNls final String methodName = method.getName();
+ if (!"hashcode".equals(methodName)) {
+ return;
+ }
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() != 0) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledToStringInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledToStringInspectionBase.java
new file mode 100644
index 000000000000..4fd6e42d13f3
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MisspelledToStringInspectionBase.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.bugs;
+
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameterList;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class MisspelledToStringInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "misspelled.tostring.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "misspelled.tostring.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MisspelledToStringVisitor();
+ }
+
+ private static class MisspelledToStringVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //note: no call to super
+ @NonNls final String methodName = method.getName();
+ if (!"tostring".equals(methodName)) {
+ return;
+ }
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() != 0) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspectionBase.java
new file mode 100644
index 000000000000..38222c79290d
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspectionBase.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiEnumConstantInitializer;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class AnonymousInnerClassInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "anonymous.inner.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "anonymous.inner.class.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new AnonymousInnerClassVisitor();
+ }
+
+ private static class AnonymousInnerClassVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //no call to super here, to avoid double counting
+ }
+
+ @Override
+ public void visitAnonymousClass(@NotNull PsiAnonymousClass aClass) {
+ super.visitAnonymousClass(aClass);
+ if (aClass instanceof PsiEnumConstantInitializer) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspectionBase.java
new file mode 100644
index 000000000000..dec9e2e662d2
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspectionBase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.util.FileTypeUtils;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ClassInTopLevelPackageInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "ClassWithoutPackageStatement";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "class.in.top.level.package.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "class.in.top.level.package.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassInTopLevelPackageVisitor();
+ }
+
+ private static class ClassInTopLevelPackageVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (FileTypeUtils.isInServerPageFile(aClass)) {
+ return;
+ }
+ if (ClassUtils.isInnerClass(aClass)) {
+ return;
+ }
+ final PsiFile file = aClass.getContainingFile();
+ if (!(file instanceof PsiJavaFile)) {
+ return;
+ }
+ if (((PsiJavaFile)file).getPackageStatement() != null) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspectionBase.java
new file mode 100644
index 000000000000..3726e6aa38ea
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspectionBase.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.util.FileTypeUtils;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class ClassNameDiffersFromFileNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "class.name.differs.from.file.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "class.name.differs.from.file.name.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassNameDiffersFromFileNameVisitor();
+ }
+
+ private static class ClassNameDiffersFromFileNameVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (FileTypeUtils.isInServerPageFile(aClass)) {
+ return;
+ }
+ final PsiElement parent = aClass.getParent();
+ if (!(parent instanceof PsiJavaFile)) {
+ return;
+ }
+ final PsiJavaFile file = (PsiJavaFile)parent;
+ final String className = aClass.getName();
+ if (className == null) {
+ return;
+ }
+ final String fileName = file.getName();
+ final int prefixIndex = fileName.indexOf((int)'.');
+ if (prefixIndex < 0) {
+ return;
+ }
+ final String filenameWithoutPrefix =
+ fileName.substring(0, prefixIndex);
+ if (className.equals(filenameWithoutPrefix)) {
+ return;
+ }
+ registerClassError(aClass, file);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/EmptyClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/EmptyClassInspectionBase.java
new file mode 100644
index 000000000000..490f08156919
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/EmptyClassInspectionBase.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.util.FileTypeUtils;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.AddToIgnoreIfAnnotatedByListQuickFix;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class EmptyClassInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreClassWithParameterization = false;
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreThrowables = true;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("empty.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ final Object element = infos[0];
+ if (element instanceof PsiAnonymousClass) {
+ return InspectionGadgetsBundle.message("empty.anonymous.class.problem.descriptor");
+ }
+ else if (element instanceof PsiClass) {
+ return InspectionGadgetsBundle.message("empty.class.problem.descriptor");
+ }
+ else {
+ return InspectionGadgetsBundle.message("empty.class.file.without.class.problem.descriptor");
+ }
+ }
+
+ @NotNull
+ @Override
+ protected InspectionGadgetsFix[] buildFixes(Object... infos) {
+ final Object info = infos[0];
+ if (!(info instanceof PsiModifierListOwner)) {
+ return InspectionGadgetsFix.EMPTY_ARRAY;
+ }
+ return AddToIgnoreIfAnnotatedByListQuickFix.build((PsiModifierListOwner)info, ignorableAnnotations);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new EmptyClassVisitor();
+ }
+
+ private class EmptyClassVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitFile(PsiFile file) {
+ if (!(file instanceof PsiJavaFile)) {
+ return;
+ }
+ final PsiJavaFile javaFile = (PsiJavaFile)file;
+ if (javaFile.getClasses().length != 0) {
+ return;
+ }
+ @NonNls final String fileName = javaFile.getName();
+ if ("package-info.java".equals(fileName)) {
+ return;
+ }
+ registerError(file, file);
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //don't call super, to prevent drilldown
+ if (FileTypeUtils.isInServerPageFile(aClass.getContainingFile())) {
+ return;
+ }
+ if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ final PsiMethod[] constructors = aClass.getConstructors();
+ if (constructors.length > 0) {
+ return;
+ }
+ final PsiMethod[] methods = aClass.getMethods();
+ if (methods.length > 0) {
+ return;
+ }
+ final PsiField[] fields = aClass.getFields();
+ if (fields.length > 0) {
+ return;
+ }
+ final PsiClassInitializer[] initializers = aClass.getInitializers();
+ if (initializers.length > 0) {
+ return;
+ }
+ if (ignoreClassWithParameterization && isSuperParametrization(aClass)) {
+ return;
+ }
+ if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) {
+ return;
+ }
+ if (ignoreThrowables && InheritanceUtil.isInheritor(aClass, "java.lang.Throwable")) {
+ return;
+ }
+ registerClassError(aClass, aClass);
+ }
+
+ private boolean hasTypeArguments(PsiReferenceList extendsList) {
+ if (extendsList == null) {
+ return false;
+ }
+ final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
+ for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
+ final PsiReferenceParameterList parameterList = referenceElement.getParameterList();
+ if (parameterList == null) {
+ continue;
+ }
+ final PsiType[] typeArguments = parameterList.getTypeArguments();
+ if (typeArguments.length != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isSuperParametrization(PsiClass aClass) {
+ if (!(aClass instanceof PsiAnonymousClass)) {
+ final PsiReferenceList extendsList = aClass.getExtendsList();
+ final PsiReferenceList implementsList = aClass.getImplementsList();
+ return hasTypeArguments(extendsList) || hasTypeArguments(implementsList);
+ }
+ final PsiAnonymousClass anonymousClass = (PsiAnonymousClass)aClass;
+ final PsiJavaCodeReferenceElement reference = anonymousClass.getBaseClassReference();
+ final PsiReferenceParameterList parameterList = reference.getParameterList();
+ if (parameterList == null) {
+ return false;
+ }
+ final PsiTypeElement[] elements = parameterList.getTypeParameterElements();
+ for (PsiTypeElement element : elements) {
+ if (element != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspectionBase.java
new file mode 100644
index 000000000000..5f4dbd1a0d36
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspectionBase.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiTypeParameter;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class InnerClassOnInterfaceInspectionBase extends BaseInspection {
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreInnerInterfaces = false;
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "InnerClassOfInterface";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "inner.class.on.interface.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final PsiClass parentInterface = (PsiClass)infos[0];
+ final String interfaceName = parentInterface.getName();
+ return InspectionGadgetsBundle.message(
+ "inner.class.on.interface.problem.descriptor", interfaceName);
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new InnerClassOnInterfaceVisitor();
+ }
+
+ private class InnerClassOnInterfaceVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (!aClass.isInterface() || aClass.isAnnotationType()) {
+ return;
+ }
+ final PsiClass[] innerClasses = aClass.getInnerClasses();
+ for (final PsiClass innerClass : innerClasses) {
+ if (isInnerClass(innerClass)) {
+ registerClassError(innerClass, aClass);
+ }
+ }
+ }
+
+ private boolean isInnerClass(PsiClass innerClass) {
+ if (innerClass.isEnum()) {
+ return false;
+ }
+ if (innerClass.isAnnotationType()) {
+ return false;
+ }
+ if (innerClass instanceof PsiTypeParameter ||
+ innerClass instanceof PsiAnonymousClass) {
+ return false;
+ }
+ return !(innerClass.isInterface() && m_ignoreInnerInterfaces);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspectionBase.java
new file mode 100644
index 000000000000..a35a0336a281
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspectionBase.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDeclarationStatement;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class LimitedScopeInnerClassInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "limited.scope.inner.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "limited.scope.inner.class.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new LimitedScopeInnerClassVisitor();
+ }
+
+ private static class LimitedScopeInnerClassVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.getParent() instanceof PsiDeclarationStatement) {
+ registerClassError(aClass);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspectionBase.java
new file mode 100644
index 000000000000..7a14ddfade53
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspectionBase.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiJavaFile;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class MultipleTopLevelClassesInFileInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "multiple.top.level.classes.in.file.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "multiple.top.level.classes.in.file.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MultipleTopLevelClassesInFileVisitor();
+ }
+
+ private static class MultipleTopLevelClassesInFileVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (!(aClass.getParent() instanceof PsiJavaFile)) {
+ return;
+ }
+ final PsiJavaFile file = (PsiJavaFile)aClass.getParent();
+ if (file == null) {
+ return;
+ }
+ int numClasses = 0;
+ final PsiElement[] children = file.getChildren();
+ for (final PsiElement child : children) {
+ if (child instanceof PsiClass) {
+ numClasses++;
+ }
+ }
+ if (numClasses <= 1) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionBase.java
new file mode 100644
index 000000000000..f8a156a3e708
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionBase.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.UtilityClassUtil;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+public class NonFinalUtilityClassInspectionBase extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("non.final.utility.class.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("non.final.utility.class.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NonFinalUtilityClassVisitor();
+ }
+
+ private static class NonFinalUtilityClassVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (!UtilityClassUtil.isUtilityClass(aClass)) {
+ return;
+ }
+ if (aClass.hasModifierProperty(PsiModifier.FINAL) ||
+ aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ registerClassError(aClass, aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspectionBase.java
new file mode 100644
index 000000000000..c5da22a20be1
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspectionBase.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ProtectedMemberInFinalClassInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("protected.member.in.final.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("protected.member.in.final.class.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ProtectedMemberInFinalClassVisitor();
+ }
+
+ private static class ProtectedMemberInFinalClassVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ if (!method.hasModifierProperty(PsiModifier.PROTECTED)) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null || !containingClass.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ if (MethodUtils.hasSuper(method)) {
+ return;
+ }
+ registerModifierError(PsiModifier.PROTECTED, method, PsiModifier.PROTECTED);
+ }
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ if (!field.hasModifierProperty(PsiModifier.PROTECTED)) {
+ return;
+ }
+ final PsiClass containingClass = field.getContainingClass();
+ if (containingClass == null || !containingClass.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ registerModifierError(PsiModifier.PROTECTED, field, PsiModifier.PROTECTED);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/PublicConstructorInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/PublicConstructorInspectionBase.java
new file mode 100644
index 000000000000..ef9c1fbcebea
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/PublicConstructorInspectionBase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiParameterList;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+public class PublicConstructorInspectionBase extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("public.constructor.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ if (((Boolean)infos[0]).booleanValue()) {
+ return InspectionGadgetsBundle.message("public.default.constructor.problem.descriptor");
+ }
+ else {
+ return InspectionGadgetsBundle.message("public.constructor.problem.descriptor");
+ }
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new PublicConstructorVisitor();
+ }
+
+ private static class PublicConstructorVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ super.visitMethod(method);
+ if (!method.isConstructor()) {
+ return;
+ }
+ if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
+ return;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass == null || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ if (SerializationUtils.isExternalizable(aClass)) {
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() == 0) {
+ return;
+ }
+ }
+ registerMethodError(method, Boolean.FALSE);
+ }
+
+ @Override
+ public void visitClass(PsiClass aClass) {
+ super.visitClass(aClass);
+ if (aClass.isInterface() || aClass.isEnum()) {
+ return;
+ }
+ if (!aClass.hasModifierProperty(PsiModifier.PUBLIC) || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ final PsiMethod[] constructors = aClass.getConstructors();
+ if (constructors.length > 0) {
+ return;
+ }
+ if (SerializationUtils.isExternalizable(aClass)) {
+ return;
+ }
+ registerClassError(aClass, Boolean.TRUE);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassInspectionBase.java
new file mode 100644
index 000000000000..a820a19ca93d
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassInspectionBase.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiModifierListOwner;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.AddToIgnoreIfAnnotatedByListQuickFix;
+import com.siyeh.ig.psiutils.UtilityClassUtil;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+
+public class UtilityClassInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("utility.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "utility.class.problem.descriptor");
+ }
+
+ @NotNull
+ @Override
+ protected InspectionGadgetsFix[] buildFixes(Object... infos) {
+ return AddToIgnoreIfAnnotatedByListQuickFix.build((PsiModifierListOwner)infos[0], ignorableAnnotations);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UtilityClassVisitor();
+ }
+
+ private class UtilityClassVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (!UtilityClassUtil.isUtilityClass(aClass)) {
+ return;
+ }
+ if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) {
+ return;
+ }
+ registerClassError(aClass, aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspectionBase.java
new file mode 100644
index 000000000000..67db7be23a02
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspectionBase.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.classlayout;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.searches.ClassInheritorsSearch;
+import com.intellij.util.Query;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.UtilityClassUtil;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class UtilityClassWithoutPrivateConstructorInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreClassesWithOnlyMain = false;
+
+ @Nullable
+ static PsiMethod getNullArgConstructor(PsiClass aClass) {
+ final PsiMethod[] constructors = aClass.getConstructors();
+ for (final PsiMethod constructor : constructors) {
+ final PsiParameterList params = constructor.getParameterList();
+ if (params.getParametersCount() == 0) {
+ return constructor;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("utility.class.without.private.constructor.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("utility.class.without.private.constructor.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UtilityClassWithoutPrivateConstructorVisitor();
+ }
+
+
+ private class UtilityClassWithoutPrivateConstructorVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so that it doesn't drill down to inner classes
+ if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ if (!UtilityClassUtil.isUtilityClass(aClass)) {
+ return;
+ }
+ if (ignoreClassesWithOnlyMain && hasOnlyMain(aClass)) {
+ return;
+ }
+ if (hasPrivateConstructor(aClass)) {
+ return;
+ }
+ if (AnnotationUtil.isAnnotated(aClass, ignorableAnnotations)) {
+ return;
+ }
+ if (aClass.hasModifierProperty(PsiModifier.PRIVATE) && aClass.getConstructors().length == 0) {
+ return;
+ }
+ final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject());
+ final Query<PsiClass> query = ClassInheritorsSearch.search(aClass, scope, true, true);
+ final PsiClass subclass = query.findFirst();
+ if (subclass != null) {
+ return;
+ }
+ registerClassError(aClass, aClass);
+ }
+
+ private boolean hasOnlyMain(PsiClass aClass) {
+ final PsiMethod[] methods = aClass.getMethods();
+ if (methods.length == 0) {
+ return false;
+ }
+ for (PsiMethod method : methods) {
+ if (method.isConstructor()) {
+ continue;
+ }
+ if (!method.hasModifierProperty(PsiModifier.STATIC)) {
+ return false;
+ }
+ if (method.hasModifierProperty(PsiModifier.PRIVATE)) {
+ continue;
+ }
+ if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
+ return false;
+ }
+ final String name = method.getName();
+ if (!name.equals(HardcodedMethodConstants.MAIN)) {
+ return false;
+ }
+ final PsiType returnType = method.getReturnType();
+ if (!PsiType.VOID.equals(returnType)) {
+ return false;
+ }
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() != 1) {
+ return false;
+ }
+ final PsiParameter[] parameters = parameterList.getParameters();
+ final PsiParameter parameter = parameters[0];
+ final PsiType type = parameter.getType();
+ if (!type.equalsToText("java.lang.String[]")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean hasPrivateConstructor(PsiClass aClass) {
+ final PsiMethod[] constructors = aClass.getConstructors();
+ for (final PsiMethod constructor : constructors) {
+ if (constructor.hasModifierProperty(PsiModifier.PRIVATE)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspectionBase.java
new file mode 100644
index 000000000000..c51df92ba104
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspectionBase.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.errorhandling;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiCatchSection;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.PsiTypeElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class BadExceptionCaughtInspectionBase extends BaseInspection {
+ /**
+ * @noinspection PublicField
+ */
+ public final ExternalizableStringSet exceptions =
+ new ExternalizableStringSet(
+ "java.lang.NullPointerException",
+ "java.lang.IllegalMonitorStateException",
+ "java.lang.ArrayIndexOutOfBoundsException"
+ );
+ /**
+ * @noinspection PublicField
+ */
+ public String exceptionsString = "";
+
+ public BadExceptionCaughtInspectionBase() {
+ if (!exceptionsString.isEmpty()) {
+ exceptions.clear();
+ final List<String> strings = StringUtil.split(exceptionsString, ",");
+ for (String string : strings) {
+ exceptions.add(string);
+ }
+ exceptionsString = "";
+ }
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "ProhibitedExceptionCaught";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("bad.exception.caught.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("bad.exception.caught.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BadExceptionCaughtVisitor();
+ }
+
+ private class BadExceptionCaughtVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitCatchSection(PsiCatchSection section) {
+ super.visitCatchSection(section);
+ final PsiParameter parameter = section.getParameter();
+ if (parameter == null) {
+ return;
+ }
+ final PsiTypeElement typeElement = parameter.getTypeElement();
+ if (typeElement == null) {
+ return;
+ }
+ final PsiTypeElement[] childTypeElements = PsiTreeUtil.getChildrenOfType(typeElement, PsiTypeElement.class);
+ if (childTypeElements != null) {
+ for (PsiTypeElement childTypeElement : childTypeElements) {
+ checkTypeElement(childTypeElement);
+ }
+ }
+ else {
+ checkTypeElement(typeElement);
+ }
+ }
+
+ private void checkTypeElement(PsiTypeElement typeElement) {
+ final PsiType type = typeElement.getType();
+ if (exceptions.contains(type.getCanonicalText())) {
+ registerError(typeElement);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspectionBase.java
new file mode 100644
index 000000000000..3cc4dcc1e067
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspectionBase.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.errorhandling;
+
+import com.intellij.codeInsight.TestFrameworks;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.LibraryUtil;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class BadExceptionDeclaredInspectionBase extends BaseInspection {
+ /**
+ * @noinspection PublicField
+ */
+ public final ExternalizableStringSet exceptions =
+ new ExternalizableStringSet(
+ "java.lang.Throwable",
+ "java.lang.Exception",
+ "java.lang.Error",
+ "java.lang.RuntimeException",
+ "java.lang.NullPointerException",
+ "java.lang.ClassCastException",
+ "java.lang.ArrayIndexOutOfBoundsException"
+ );
+ /**
+ * @noinspection PublicField
+ */
+ public String exceptionsString = "";
+ /**
+ * @noinspection PublicField
+ */
+ public boolean ignoreTestCases = false;
+ public boolean ignoreLibraryOverrides = false;
+
+ public BadExceptionDeclaredInspectionBase() {
+ if (!exceptionsString.isEmpty()) {
+ exceptions.clear();
+ final List<String> strings = StringUtil.split(exceptionsString, ",");
+ for (String string : strings) {
+ exceptions.add(string);
+ }
+ exceptionsString = "";
+ }
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "ProhibitedExceptionDeclared";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("bad.exception.declared.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("bad.exception.declared.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BadExceptionDeclaredVisitor();
+ }
+
+ private class BadExceptionDeclaredVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ if (ignoreTestCases) {
+ final PsiClass containingClass = method.getContainingClass();
+ final TestFrameworks testFrameworks = TestFrameworks.getInstance();
+ if (containingClass != null && testFrameworks.isTestOrConfig(containingClass)) {
+ return;
+ }
+ }
+ if (ignoreLibraryOverrides && LibraryUtil.isOverrideOfLibraryMethod(method)) {
+ return;
+ }
+ final PsiReferenceList throwsList = method.getThrowsList();
+ final PsiJavaCodeReferenceElement[] references = throwsList.getReferenceElements();
+ for (PsiJavaCodeReferenceElement reference : references) {
+ final PsiElement element = reference.resolve();
+ if (!(element instanceof PsiClass)) {
+ continue;
+ }
+ final PsiClass thrownClass = (PsiClass)element;
+ final String qualifiedName = thrownClass.getQualifiedName();
+ if (qualifiedName != null && exceptions.contains(qualifiedName)) {
+ registerError(reference);
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspectionBase.java
new file mode 100644
index 000000000000..869bf04baaae
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspectionBase.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.errorhandling;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiExpression;
+import com.intellij.psi.PsiThrowStatement;
+import com.intellij.psi.PsiType;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class BadExceptionThrownInspectionBase extends BaseInspection {
+ @SuppressWarnings("PublicField")
+ public final ExternalizableStringSet exceptions =
+ new ExternalizableStringSet(
+ "java.lang.Throwable",
+ "java.lang.Exception",
+ "java.lang.Error",
+ "java.lang.RuntimeException",
+ "java.lang.NullPointerException",
+ "java.lang.ClassCastException",
+ "java.lang.ArrayIndexOutOfBoundsException"
+ );
+ /**
+ * @noinspection PublicField
+ */
+ public String exceptionsString = "";
+
+ public BadExceptionThrownInspectionBase() {
+ if (!exceptionsString.isEmpty()) {
+ exceptions.clear();
+ final List<String> strings =
+ StringUtil.split(exceptionsString, ",");
+ for (String string : strings) {
+ exceptions.add(string);
+ }
+ exceptionsString = "";
+ }
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "ProhibitedExceptionThrown";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "bad.exception.thrown.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final PsiType type = (PsiType)infos[0];
+ final String exceptionName = type.getPresentableText();
+ return InspectionGadgetsBundle.message(
+ "bad.exception.thrown.problem.descriptor", exceptionName);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BadExceptionThrownVisitor();
+ }
+
+ private class BadExceptionThrownVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitThrowStatement(PsiThrowStatement statement) {
+ super.visitThrowStatement(statement);
+ final PsiExpression exception = statement.getException();
+ if (exception == null) {
+ return;
+ }
+ final PsiType type = exception.getType();
+ if (type == null) {
+ return;
+ }
+ final String text = type.getCanonicalText();
+ if (exceptions.contains(text)) {
+ registerStatementError(statement, type);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/ThrowsRuntimeExceptionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/ThrowsRuntimeExceptionInspectionBase.java
new file mode 100644
index 000000000000..9ee31c3f8799
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/ThrowsRuntimeExceptionInspectionBase.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.errorhandling;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+public class ThrowsRuntimeExceptionInspectionBase extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("throws.runtime.exception.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("throws.runtime.exception.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ThrowsRuntimeExceptionVisitor();
+ }
+
+ private static class ThrowsRuntimeExceptionVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ super.visitMethod(method);
+ final PsiReferenceList throwsList = method.getThrowsList();
+ final PsiJavaCodeReferenceElement[] referenceElements = throwsList.getReferenceElements();
+ for (PsiJavaCodeReferenceElement referenceElement : referenceElements) {
+ final PsiElement target = referenceElement.resolve();
+ if (!(target instanceof PsiClass)) {
+ continue;
+ }
+ final PsiClass aClass = (PsiClass)target;
+ if (!InheritanceUtil.isInheritor(aClass, "java.lang.RuntimeException")) {
+ continue;
+ }
+ final String className = aClass.getName();
+ registerError(referenceElement, className, referenceElement);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/TooBroadCatchInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/TooBroadCatchInspectionBase.java
new file mode 100644
index 000000000000..cc87b0c73224
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/TooBroadCatchInspectionBase.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.errorhandling;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import com.siyeh.ig.psiutils.ExceptionUtils;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+public class TooBroadCatchInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public boolean onlyWarnOnRootExceptions = false;
+ @SuppressWarnings("PublicField")
+ public boolean ignoreInTestCode = false;
+ @SuppressWarnings("PublicField")
+ public boolean ignoreThrown = false;
+
+ protected static TextRange getRangeToSelect(PsiCodeBlock block) {
+ PsiElement first = block.getFirstBodyElement();
+ if (first instanceof PsiWhiteSpace) {
+ first = first.getNextSibling();
+ }
+ if (first == null) {
+ final int offset = block.getTextRange().getStartOffset() + 1;
+ return new TextRange(offset, offset);
+ }
+ PsiElement last = block.getLastBodyElement();
+ if (last instanceof PsiWhiteSpace) {
+ last = last.getPrevSibling();
+ }
+ final TextRange textRange;
+ if (last == null) {
+ textRange = first.getTextRange();
+ }
+ else {
+ textRange = last.getTextRange();
+ }
+ return new TextRange(first.getTextRange().getStartOffset(), textRange.getEndOffset());
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "OverlyBroadCatchBlock";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("too.broad.catch.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ final List<PsiClass> typesMasked = (List<PsiClass>)infos[0];
+ String typesMaskedString = typesMasked.get(0).getName();
+ if (typesMasked.size() == 1) {
+ return InspectionGadgetsBundle.message("too.broad.catch.problem.descriptor", typesMaskedString);
+ }
+ else {
+ //Collections.sort(typesMasked);
+ final int lastTypeIndex = typesMasked.size() - 1;
+ for (int i = 1; i < lastTypeIndex; i++) {
+ typesMaskedString += ", ";
+ typesMaskedString += typesMasked.get(i).getName();
+ }
+ final String lastTypeString = typesMasked.get(lastTypeIndex).getName();
+ return InspectionGadgetsBundle.message("too.broad.catch.problem.descriptor1", typesMaskedString, lastTypeString);
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new TooBroadCatchVisitor();
+ }
+
+ private class TooBroadCatchVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitTryStatement(@NotNull PsiTryStatement statement) {
+ super.visitTryStatement(statement);
+ final PsiCodeBlock tryBlock = statement.getTryBlock();
+ if (tryBlock == null) {
+ return;
+ }
+ if (ignoreInTestCode && TestUtils.isInTestCode(statement)) {
+ return;
+ }
+ final Set<PsiClassType> thrownTypes = ExceptionUtils.calculateExceptionsThrown(tryBlock);
+ final Set<PsiType> caughtTypes = new HashSet<PsiType>(thrownTypes.size());
+ final PsiCatchSection[] catchSections = statement.getCatchSections();
+ for (final PsiCatchSection catchSection : catchSections) {
+ final PsiParameter parameter = catchSection.getParameter();
+ if (parameter == null) {
+ continue;
+ }
+ final PsiType caughtType = parameter.getType();
+ if (caughtType instanceof PsiDisjunctionType) {
+ final PsiDisjunctionType disjunctionType = (PsiDisjunctionType)caughtType;
+ final List<PsiType> types = disjunctionType.getDisjunctions();
+ for (PsiType type : types) {
+ check(thrownTypes, caughtTypes, parameter, type);
+ }
+ }
+ else {
+ if (thrownTypes.isEmpty()) {
+ if (CommonClassNames.JAVA_LANG_EXCEPTION.equals(caughtType.getCanonicalText())) {
+ final PsiTypeElement typeElement = parameter.getTypeElement();
+ if (typeElement == null) {
+ continue;
+ }
+ final PsiClass runtimeExceptionClass = ClassUtils.findClass(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, parameter);
+ registerError(typeElement, Collections.singletonList(runtimeExceptionClass));
+ }
+ }
+ else {
+ check(thrownTypes, caughtTypes, parameter, caughtType);
+ }
+ }
+ }
+ }
+
+ private void check(Set<PsiClassType> thrownTypes, Set<PsiType> caughtTypes, PsiParameter parameter, PsiType caughtType) {
+ final List<PsiClass> maskedExceptions = findMaskedExceptions(thrownTypes, caughtTypes, caughtType);
+ if (maskedExceptions.isEmpty()) {
+ return;
+ }
+ final PsiTypeElement typeElement = parameter.getTypeElement();
+ if (typeElement == null) {
+ return;
+ }
+ registerError(typeElement, maskedExceptions);
+ }
+
+ private List<PsiClass> findMaskedExceptions(Set<PsiClassType> thrownTypes, Set<PsiType> caughtTypes, PsiType caughtType) {
+ if (thrownTypes.contains(caughtType)) {
+ if (ignoreThrown) {
+ return Collections.emptyList();
+ }
+ caughtTypes.add(caughtType);
+ thrownTypes.remove(caughtType);
+ }
+ if (onlyWarnOnRootExceptions) {
+ if (!ExceptionUtils.isGenericExceptionClass(caughtType)) {
+ return Collections.emptyList();
+ }
+ }
+ final List<PsiClass> maskedTypes = new ArrayList();
+ for (PsiClassType typeThrown : thrownTypes) {
+ if (!caughtTypes.contains(typeThrown) && caughtType.isAssignableFrom(typeThrown)) {
+ caughtTypes.add(typeThrown);
+ final PsiClass aClass = typeThrown.resolve();
+ if (aClass != null) {
+ maskedTypes.add(aClass);
+ }
+ }
+ }
+ return maskedTypes;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspectionBase.java
new file mode 100644
index 000000000000..5c233495efeb
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspectionBase.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.errorhandling;
+
+import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class UnusedCatchParameterInspectionBase extends BaseInspection {
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreCatchBlocksWithComments = false;
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreTestCases = false;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "unused.catch.parameter.display.name");
+ }
+
+ @Override
+ public JComponent createOptionsPanel() {
+ final MultipleCheckboxOptionsPanel optionsPanel =
+ new MultipleCheckboxOptionsPanel(this);
+ optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
+ "unused.catch.parameter.ignore.catch.option"),
+ "m_ignoreCatchBlocksWithComments");
+ optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
+ "unused.catch.parameter.ignore.empty.option"),
+ "m_ignoreTestCases");
+ return optionsPanel;
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ final boolean namedIgnoreButUsed = ((Boolean)infos[0]).booleanValue();
+ if (namedIgnoreButUsed) {
+ return InspectionGadgetsBundle.message(
+ "used.catch.parameter.named.ignore.problem.descriptor"
+ );
+ }
+ return InspectionGadgetsBundle.message(
+ "unused.catch.parameter.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UnusedCatchParameterVisitor();
+ }
+
+ private class UnusedCatchParameterVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitTryStatement(@NotNull PsiTryStatement statement) {
+ super.visitTryStatement(statement);
+ if (m_ignoreTestCases && TestUtils.isInTestCode(statement)) {
+ return;
+ }
+ final PsiCatchSection[] catchSections = statement.getCatchSections();
+ for (PsiCatchSection catchSection : catchSections) {
+ checkCatchSection(catchSection);
+ }
+ }
+
+ private void checkCatchSection(PsiCatchSection section) {
+ final PsiParameter parameter = section.getParameter();
+ if (parameter == null) {
+ return;
+ }
+ @NonNls final String parameterName = parameter.getName();
+ final PsiCodeBlock block = section.getCatchBlock();
+ if (block == null) {
+ return;
+ }
+ if (m_ignoreCatchBlocksWithComments) {
+ final PsiElement[] children = block.getChildren();
+ for (final PsiElement child : children) {
+ if (child instanceof PsiComment) {
+ return;
+ }
+ }
+ }
+ final CatchParameterUsedVisitor visitor =
+ new CatchParameterUsedVisitor(parameter);
+ block.accept(visitor);
+ final boolean namedIgnore = PsiUtil.isIgnoredName(parameterName);
+ if (visitor.isUsed()) {
+ if (namedIgnore) {
+ registerVariableError(parameter, Boolean.TRUE);
+ }
+ return;
+ }
+ else if (namedIgnore) {
+ return;
+ }
+ registerVariableError(parameter, Boolean.FALSE);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/imports/StaticImportInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/imports/StaticImportInspectionBase.java
new file mode 100644
index 000000000000..0a1182c80183
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/imports/StaticImportInspectionBase.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.imports;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.util.FileTypeUtils;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.containers.OrderedSet;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.StringUtils;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class StaticImportInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"}) public boolean ignoreSingleFieldImports = false;
+ @SuppressWarnings({"PublicField"}) public boolean ignoreSingeMethodImports = false;
+ @SuppressWarnings("PublicField") public boolean ignoreInTestCode = false;
+ @SuppressWarnings("PublicField") public OrderedSet<String> allowedClasses = new OrderedSet<String>();
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("static.import.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "static.import.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new StaticImportFix();
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new StaticImportVisitor();
+ }
+
+ private static class StaticImportFix extends InspectionGadgetsFix {
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("static.import.replace.quickfix");
+ }
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiImportStaticStatement importStatement = (PsiImportStaticStatement)descriptor.getPsiElement();
+ final PsiJavaCodeReferenceElement importReference = importStatement.getImportReference();
+ if (importReference == null) {
+ return;
+ }
+ final JavaResolveResult[] importTargets = importReference.multiResolve(false);
+ if (importTargets.length == 0) {
+ return;
+ }
+ final boolean onDemand = importStatement.isOnDemand();
+ final StaticImportFix.StaticImportReferenceCollector
+ referenceCollector = new StaticImportFix.StaticImportReferenceCollector(importTargets, onDemand);
+ final PsiJavaFile file = (PsiJavaFile)importStatement.getContainingFile();
+ file.accept(referenceCollector);
+ final List<PsiJavaCodeReferenceElement> references = referenceCollector.getReferences();
+ final Map<PsiJavaCodeReferenceElement, PsiMember> referenceTargetMap = new HashMap<PsiJavaCodeReferenceElement, PsiMember>();
+ for (PsiJavaCodeReferenceElement reference : references) {
+ final PsiElement target = reference.resolve();
+ if (target instanceof PsiMember) {
+ final PsiMember member = (PsiMember)target;
+ referenceTargetMap.put(reference, member);
+ }
+ }
+ importStatement.delete();
+ for (Map.Entry<PsiJavaCodeReferenceElement, PsiMember> entry : referenceTargetMap.entrySet()) {
+ removeReference(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private static void removeReference(PsiJavaCodeReferenceElement reference, PsiMember target) {
+ final PsiManager manager = reference.getManager();
+ final Project project = manager.getProject();
+ final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
+ final PsiElementFactory factory = psiFacade.getElementFactory();
+ final PsiClass aClass = target.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ final String qualifiedName = aClass.getQualifiedName();
+ final String text = reference.getText();
+ final String referenceText = qualifiedName + '.' + text;
+ if (reference instanceof PsiReferenceExpression) {
+ final PsiExpression newReference = factory.createExpressionFromText(referenceText, reference);
+ final PsiElement insertedElement = reference.replace(newReference);
+ JavaCodeStyleManager.getInstance(project).shortenClassReferences(insertedElement);
+ }
+ else {
+ final PsiJavaCodeReferenceElement referenceElement =
+ factory.createReferenceElementByFQClassName(referenceText, reference.getResolveScope());
+ final PsiElement insertedElement = reference.replace(referenceElement);
+ JavaCodeStyleManager.getInstance(project).shortenClassReferences(insertedElement);
+ }
+ }
+
+ static class StaticImportReferenceCollector extends JavaRecursiveElementVisitor {
+
+ private final JavaResolveResult[] importTargets;
+ private final boolean onDemand;
+ private final List<PsiJavaCodeReferenceElement> references = new ArrayList<PsiJavaCodeReferenceElement>();
+
+ StaticImportReferenceCollector(@NotNull JavaResolveResult[] importTargets, boolean onDemand) {
+ this.importTargets = importTargets;
+ this.onDemand = onDemand;
+ }
+
+ @Override
+ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
+ super.visitReferenceElement(reference);
+ if (isFullyQualifiedReference(reference)) {
+ return;
+ }
+ PsiElement parent = reference.getParent();
+ if (parent instanceof PsiImportStatementBase) {
+ return;
+ }
+ while (parent instanceof PsiJavaCodeReferenceElement) {
+ parent = parent.getParent();
+ if (parent instanceof PsiImportStatementBase) {
+ return;
+ }
+ }
+ checkStaticImportReference(reference);
+ }
+
+ private void checkStaticImportReference(PsiJavaCodeReferenceElement reference) {
+ if (reference.isQualified()) {
+ return;
+ }
+ final PsiElement target = reference.resolve();
+ if (!(target instanceof PsiMethod) && !(target instanceof PsiClass) && !(target instanceof PsiField)) {
+ return;
+ }
+ final PsiMember member = (PsiMember)target;
+ for (JavaResolveResult importTarget : importTargets) {
+ final PsiElement targetElement = importTarget.getElement();
+ if (targetElement instanceof PsiMethod || targetElement instanceof PsiField) {
+ if (member.equals(targetElement)) {
+ addReference(reference);
+ }
+ }
+ else if (targetElement instanceof PsiClass) {
+ if (onDemand) {
+ final PsiClass containingClass = member.getContainingClass();
+ if (InheritanceUtil.isInheritorOrSelf((PsiClass)targetElement, containingClass, true)) {
+ addReference(reference);
+ }
+ }
+ else {
+ if (targetElement.equals(member)) {
+ addReference(reference);
+ }
+ }
+ }
+ }
+ }
+
+ private void addReference(PsiJavaCodeReferenceElement reference) {
+ references.add(reference);
+ }
+
+ public List<PsiJavaCodeReferenceElement> getReferences() {
+ return references;
+ }
+
+ public static boolean isFullyQualifiedReference(PsiJavaCodeReferenceElement reference) {
+ if (!reference.isQualified()) {
+ return false;
+ }
+ final PsiElement directParent = reference.getParent();
+ if (directParent instanceof PsiMethodCallExpression ||
+ directParent instanceof PsiAssignmentExpression ||
+ directParent instanceof PsiVariable) {
+ return false;
+ }
+ final PsiElement parent =
+ PsiTreeUtil.getParentOfType(reference, PsiImportStatementBase.class, PsiPackageStatement.class, JavaCodeFragment.class);
+ if (parent != null) {
+ return false;
+ }
+ final PsiElement target = reference.resolve();
+ if (!(target instanceof PsiClass)) {
+ return false;
+ }
+ final PsiClass aClass = (PsiClass)target;
+ final String fqName = aClass.getQualifiedName();
+ if (fqName == null) {
+ return false;
+ }
+ final String text =
+ StringUtils.stripAngleBrackets(reference.getText());
+ return text.equals(fqName);
+ }
+ }
+ }
+
+ private class StaticImportVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ final PsiElement parent = aClass.getParent();
+ if (!(parent instanceof PsiJavaFile)) {
+ return;
+ }
+ final PsiJavaFile file = (PsiJavaFile)parent;
+ if (FileTypeUtils.isInServerPageFile(file)) {
+ return;
+ }
+ if (!file.getClasses()[0].equals(aClass)) {
+ return;
+ }
+ final PsiImportList importList = file.getImportList();
+ if (importList == null) {
+ return;
+ }
+ if (ignoreInTestCode && TestUtils.isTest(aClass)) {
+ return;
+ }
+ final PsiImportStaticStatement[] importStatements = importList.getImportStaticStatements();
+ for (PsiImportStaticStatement importStatement : importStatements) {
+ if (shouldReportImportStatement(importStatement)) {
+ registerError(importStatement);
+ }
+ }
+ }
+
+ private boolean shouldReportImportStatement(PsiImportStaticStatement importStatement) {
+ final PsiJavaCodeReferenceElement importReference = importStatement.getImportReference();
+ if (importReference == null) {
+ return false;
+ }
+ PsiClass targetClass = importStatement.resolveTargetClass();
+ boolean checked = false;
+ while (targetClass != null) {
+ final String qualifiedName = targetClass.getQualifiedName();
+ if (allowedClasses.contains(qualifiedName)) {
+ return false;
+ }
+ if (checked) {
+ break;
+ }
+ targetClass = targetClass.getContainingClass();
+ checked = true;
+ }
+ if (importStatement.isOnDemand()) {
+ return true;
+ }
+ if (ignoreSingleFieldImports || ignoreSingeMethodImports) {
+ boolean field = false;
+ boolean method = false;
+ // in the presence of method overloading the plain resolve() method returns null
+ final JavaResolveResult[] results = importReference.multiResolve(false);
+ for (JavaResolveResult result : results) {
+ final PsiElement element = result.getElement();
+ if (element instanceof PsiField) {
+ field = true;
+ } else if (element instanceof PsiMethod) {
+ method = true;
+ }
+ }
+ if (field && !method) {
+ if (ignoreSingleFieldImports) {
+ return false;
+ }
+ }
+ else if (method && !field) {
+ if (ignoreSingeMethodImports) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionBase.java
new file mode 100644
index 000000000000..5a9f275c606a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionBase.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.inheritance;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.CollectionUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ExtendsConcreteCollectionInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "ClassExtendsConcreteCollection";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "extends.concrete.collection.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final PsiClass superClass = (PsiClass)infos[0];
+ final PsiClass aClass = (PsiClass)infos[1];
+ if (aClass instanceof PsiAnonymousClass) {
+ return InspectionGadgetsBundle.message("anonymous.extends.concrete.collection.problem.descriptor", superClass.getQualifiedName());
+ } else {
+ return InspectionGadgetsBundle.message("extends.concrete.collection.problem.descriptor", superClass.getQualifiedName());
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ExtendsConcreteCollectionVisitor();
+ }
+
+ private static class ExtendsConcreteCollectionVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isAnnotationType() || aClass.isEnum()) {
+ return;
+ }
+ final PsiClass superClass = aClass.getSuperClass();
+ if (superClass == null) {
+ return;
+ }
+ if (!CollectionUtils.isCollectionClass(superClass)) {
+ return;
+ }
+ registerClassError(aClass, superClass, aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java
new file mode 100644
index 000000000000..1289bbdbe694
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.inheritance;
+
+import com.intellij.codeInsight.FileModificationService;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.intention.QuickFixFactory;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.Query;
+import com.intellij.util.ui.UIUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ClassUtils;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * User: cdr
+ */
+class StaticInheritanceFix extends InspectionGadgetsFix {
+ private final boolean myReplaceInWholeProject;
+
+ StaticInheritanceFix(boolean replaceInWholeProject) {
+ myReplaceInWholeProject = replaceInWholeProject;
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ String scope =
+ myReplaceInWholeProject ? InspectionGadgetsBundle.message("the.whole.project") : InspectionGadgetsBundle.message("this.class");
+ return InspectionGadgetsBundle.message("static.inheritance.replace.quickfix", scope);
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "Replace inheritance with qualified reference";
+ }
+
+ @Override
+ public void doFix(final Project project, final ProblemDescriptor descriptor) throws IncorrectOperationException {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ dodoFix(project, descriptor);
+ }
+ }, ModalityState.NON_MODAL, project.getDisposed());
+ }
+
+ private void dodoFix(final Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)descriptor.getPsiElement();
+ final PsiClass iface = (PsiClass)referenceElement.resolve();
+ assert iface != null;
+ final PsiField[] allFields = iface.getAllFields();
+
+ final PsiClass implementingClass = ClassUtils.getContainingClass(referenceElement);
+ final PsiManager manager = referenceElement.getManager();
+ assert implementingClass != null;
+ final PsiFile file = implementingClass.getContainingFile();
+
+ ProgressManager.getInstance().run(new Task.Modal(project, "Replacing usages of " + iface.getName(), false) {
+
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ for (final PsiField field : allFields) {
+ final Query<PsiReference> search = ReferencesSearch.search(field, implementingClass.getUseScope(), false);
+ for (PsiReference reference : search) {
+ if (!(reference instanceof PsiReferenceExpression)) {
+ continue;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)reference;
+ if (!myReplaceInWholeProject) {
+ boolean isInheritor =
+ ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ boolean isInheritor = false;
+ PsiClass aClass = PsiTreeUtil.getParentOfType(referenceExpression, PsiClass.class);
+ while (aClass != null) {
+ isInheritor = InheritanceUtil.isInheritorOrSelf(aClass, implementingClass, true);
+ if (isInheritor) break;
+ aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
+ }
+ return isInheritor;
+ }
+ });
+ if (!isInheritor) continue;
+ }
+ final Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ if (!FileModificationService.getInstance().preparePsiElementsForWrite(referenceExpression)) {
+ return;
+ }
+ final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
+ final PsiReferenceExpression qualified =
+ (PsiReferenceExpression)elementFactory
+ .createExpressionFromText("xxx." + referenceExpression.getText(), referenceExpression);
+ final PsiReferenceExpression newReference = (PsiReferenceExpression)referenceExpression.replace(qualified);
+ final PsiReferenceExpression qualifier = (PsiReferenceExpression)newReference.getQualifierExpression();
+ assert qualifier != null : DebugUtil.psiToString(newReference, false);
+ final PsiClass containingClass = field.getContainingClass();
+ qualifier.bindToElement(containingClass);
+ }
+ };
+ invokeWriteAction(runnable, file);
+ }
+ }
+ final Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory().createType(iface);
+ IntentionAction fix = QuickFixFactory.getInstance().createExtendsListFix(implementingClass, classType, false);
+ fix.invoke(project, null, file);
+ }
+ };
+ invokeWriteAction(runnable, file);
+ }
+ });
+ }
+
+ private static void invokeWriteAction(final Runnable runnable, final PsiFile file) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ new WriteCommandAction(file.getProject(), file) {
+ @Override
+ protected void run(Result result) throws Throwable {
+ runnable.run();
+ }
+ }.execute();
+ }
+ });
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java
new file mode 100644
index 000000000000..b17cd7d2139e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceInspection.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.inheritance;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import com.intellij.psi.PsiReferenceList;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class StaticInheritanceInspection extends BaseInspection {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "static.inheritance.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "static.inheritance.problem.descriptor");
+ }
+
+ @NotNull
+ @Override
+ protected InspectionGadgetsFix[] buildFixes(Object... infos) {
+ return new InspectionGadgetsFix[]{new StaticInheritanceFix(false), new StaticInheritanceFix(true)};
+ }
+
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new StaticInheritanceVisitor();
+ }
+
+ private static class StaticInheritanceVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down
+ final PsiReferenceList implementsList = aClass.getImplementsList();
+ if (implementsList == null) {
+ return;
+ }
+ final PsiJavaCodeReferenceElement[] references =
+ implementsList.getReferenceElements();
+ for (final PsiJavaCodeReferenceElement reference : references) {
+ final PsiClass iface = (PsiClass)reference.resolve();
+ if (iface != null) {
+ if (interfaceContainsOnlyConstants(iface, new HashSet<PsiClass>())) {
+ registerError(reference);
+ }
+ }
+ }
+ }
+
+ private static boolean interfaceContainsOnlyConstants(
+ PsiClass iface, Set<PsiClass> visitedIntefaces) {
+ if (!visitedIntefaces.add(iface)) {
+ return true;
+ }
+ if (iface.getAllFields().length == 0) {
+ // ignore it, it's either a true interface or just a marker
+ return false;
+ }
+ if (iface.getMethods().length != 0) {
+ return false;
+ }
+ final PsiClass[] parentInterfaces = iface.getInterfaces();
+ for (final PsiClass parentInterface : parentInterfaces) {
+ if (!interfaceContainsOnlyConstants(parentInterface,
+ visitedIntefaces)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspectionBase.java
new file mode 100644
index 000000000000..3b72bd5f87f1
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspectionBase.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.AddToIgnoreIfAnnotatedByListQuickFix;
+import com.siyeh.ig.psiutils.ClassUtils;
+import com.siyeh.ig.psiutils.UninitializedReadCollector;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InstanceVariableUninitializedUseInspectionBase extends BaseInspection {
+ protected final List<String> annotationNames = new ArrayList();
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignorePrimitives = false;
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls
+ public String annotationNamesString = "";
+
+ public InstanceVariableUninitializedUseInspectionBase() {
+ parseString(annotationNamesString, annotationNames);
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "InstanceVariableUsedBeforeInitialized";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("instance.variable.used.before.initialized.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("instance.variable.used.before.initialized.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(annotationNamesString, annotationNames);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ annotationNamesString = formatString(annotationNames);
+ super.writeSettings(element);
+ }
+
+ @NotNull
+ @Override
+ protected InspectionGadgetsFix[] buildFixes(Object... infos) {
+ final PsiField field = (PsiField)infos[0];
+ return AddToIgnoreIfAnnotatedByListQuickFix.build(field, annotationNames);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new InstanceVariableInitializationVisitor();
+ }
+
+ private class InstanceVariableInitializationVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ if (field.hasModifierProperty(PsiModifier.STATIC) || field.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ if (field.getInitializer() != null) {
+ return;
+ }
+ final PsiAnnotation annotation = AnnotationUtil.findAnnotation(field, annotationNames);
+ if (annotation != null) {
+ return;
+ }
+ if (m_ignorePrimitives) {
+ final PsiType fieldType = field.getType();
+ if (ClassUtils.isPrimitive(fieldType)) {
+ return;
+ }
+ }
+ final PsiClass aClass = field.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ for (ImplicitUsageProvider provider :
+ Extensions.getExtensions(ImplicitUsageProvider.EP_NAME)) {
+ if (provider.isImplicitWrite(field)) {
+ return;
+ }
+ }
+ final UninitializedReadCollector uninitializedReadsCollector = new UninitializedReadCollector();
+ if (!isInitializedInInitializer(field, uninitializedReadsCollector)) {
+ final PsiMethod[] constructors = aClass.getConstructors();
+ for (final PsiMethod constructor : constructors) {
+ final PsiCodeBlock body = constructor.getBody();
+ uninitializedReadsCollector.blockAssignsVariable(body, field);
+ }
+ }
+ final PsiExpression[] badReads = uninitializedReadsCollector.getUninitializedReads();
+ for (PsiExpression expression : badReads) {
+ registerError(expression, field);
+ }
+ }
+
+ private boolean isInitializedInInitializer(@NotNull PsiField field, UninitializedReadCollector uninitializedReadsCollector) {
+ final PsiClass aClass = field.getContainingClass();
+ if (aClass == null) {
+ return false;
+ }
+ final PsiClassInitializer[] initializers = aClass.getInitializers();
+ for (final PsiClassInitializer initializer : initializers) {
+ if (!initializer.hasModifierProperty(PsiModifier.STATIC)) {
+ final PsiCodeBlock body = initializer.getBody();
+ if (uninitializedReadsCollector.blockAssignsVariable(body, field)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspectionBase.java
new file mode 100644
index 000000000000..e36fe008ab21
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspectionBase.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.MethodCallUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class OverridableMethodCallDuringObjectConstructionInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("overridable.method.call.in.constructor.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("overridable.method.call.in.constructor.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new OverridableMethodCallInConstructorVisitor();
+ }
+
+ private static class OverridableMethodCallInConstructorVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ if (!MethodCallUtils.isCallDuringObjectConstruction(expression)) {
+ return;
+ }
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (qualifier != null) {
+ if (!(qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression)) {
+ return;
+ }
+ }
+ final PsiClass containingClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
+ if (containingClass == null || containingClass.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ final PsiMethod calledMethod = expression.resolveMethod();
+ if (calledMethod == null || !PsiUtil.canBeOverriden(calledMethod)) {
+ return;
+ }
+ final PsiClass calledMethodClass = calledMethod.getContainingClass();
+ if (calledMethodClass == null || !calledMethodClass.equals(containingClass)) {
+ return;
+ }
+ registerMethodCallError(expression, expression);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverriddenMethodCallDuringObjectConstructionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverriddenMethodCallDuringObjectConstructionInspection.java
new file mode 100644
index 000000000000..9042da9d041c
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/OverriddenMethodCallDuringObjectConstructionInspection.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.MethodCallUtils;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class OverriddenMethodCallDuringObjectConstructionInspection extends BaseInspection {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("overridden.method.call.in.constructor.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("overridden.method.call.in.constructor.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new OverriddenMethodCallInConstructorVisitor();
+ }
+
+ private static class OverriddenMethodCallInConstructorVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ if (!MethodCallUtils.isCallDuringObjectConstruction(expression)) {
+ return;
+ }
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (qualifier != null) {
+ if (!(qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression)) {
+ return;
+ }
+ }
+ final PsiClass containingClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
+ if (containingClass == null || containingClass.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ final PsiMethod calledMethod = expression.resolveMethod();
+ if (calledMethod == null || !PsiUtil.canBeOverriden(calledMethod)) {
+ return;
+ }
+ final PsiClass calledMethodClass = calledMethod.getContainingClass();
+ if (!InheritanceUtil.isInheritorOrSelf(containingClass, calledMethodClass, true)) {
+ return;
+ }
+ if (!MethodUtils.isOverriddenInHierarchy(calledMethod, containingClass)) {
+ return;
+ }
+ registerMethodCallError(expression);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/internationalization/MagicCharacterInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/internationalization/MagicCharacterInspectionBase.java
new file mode 100644
index 000000000000..bbdc674c3b08
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/internationalization/MagicCharacterInspectionBase.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.internationalization;
+
+import com.intellij.psi.PsiLiteralExpression;
+import com.intellij.psi.PsiType;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class MagicCharacterInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("magic.character.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "magic.character.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new CharacterLiteralsShouldBeExplicitlyDeclaredVisitor();
+ }
+
+ private static class CharacterLiteralsShouldBeExplicitlyDeclaredVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitLiteralExpression(
+ @NotNull PsiLiteralExpression expression) {
+ super.visitLiteralExpression(expression);
+ final PsiType type = expression.getType();
+ if (type == null) {
+ return;
+ }
+ if (!type.equals(PsiType.CHAR)) {
+ return;
+ }
+ final String text = expression.getText();
+ if (text == null) {
+ return;
+ }
+ if (text.equals(" ")) {
+ return;
+ }
+ if (ExpressionUtils.isDeclaredConstant(expression)) {
+ return;
+ }
+ if (NonNlsUtils.isNonNlsAnnotatedUse(expression)) {
+ return;
+ }
+ registerError(expression);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java
new file mode 100644
index 000000000000..4ea6a4c7290f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.j2me;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.performance.InnerClassReferenceVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class AnonymousInnerClassMayBeStaticInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "anonymous.inner.may.be.named.static.inner.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "anonymous.inner.may.be.named.static.inner.class.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new AnonymousInnerClassMayBeStaticVisitor();
+ }
+
+ private static class AnonymousInnerClassMayBeStaticVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (!(aClass instanceof PsiAnonymousClass)) {
+ return;
+ }
+ if (aClass instanceof PsiEnumConstantInitializer) {
+ return;
+ }
+ final PsiMember containingMember =
+ PsiTreeUtil.getParentOfType(aClass, PsiMember.class);
+ if (containingMember == null ||
+ containingMember.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final PsiAnonymousClass anAnonymousClass =
+ (PsiAnonymousClass)aClass;
+ final InnerClassReferenceVisitor visitor =
+ new InnerClassReferenceVisitor(anAnonymousClass);
+ anAnonymousClass.accept(visitor);
+ if (!visitor.canInnerClassBeStatic()) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java
new file mode 100644
index 000000000000..d4714577f02f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MethodCallInLoopConditionInspectionBase.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.j2me;
+
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class MethodCallInLoopConditionInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("method.call.in.loop.condition.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("method.call.in.loop.condition.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MethodCallInLoopConditionVisitor();
+ }
+
+ private static class MethodCallInLoopConditionVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitForStatement(@NotNull PsiForStatement statement) {
+ super.visitForStatement(statement);
+ final PsiExpression condition = statement.getCondition();
+ if (condition == null) {
+ return;
+ }
+ checkForMethodCalls(condition);
+ }
+
+ @Override
+ public void visitWhileStatement(@NotNull PsiWhileStatement statement) {
+ super.visitWhileStatement(statement);
+ final PsiExpression condition = statement.getCondition();
+ if (condition == null) {
+ return;
+ }
+ checkForMethodCalls(condition);
+ }
+
+ @Override
+ public void visitDoWhileStatement(@NotNull PsiDoWhileStatement statement) {
+ super.visitDoWhileStatement(statement);
+ final PsiExpression condition = statement.getCondition();
+ if (condition == null) {
+ return;
+ }
+ checkForMethodCalls(condition);
+ }
+
+ private void checkForMethodCalls(PsiExpression condition) {
+ final PsiElementVisitor visitor = new JavaRecursiveElementVisitor() {
+
+ @Override
+ public void visitMethodCallExpression(
+ @NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ registerMethodCallError(expression);
+ }
+ };
+ condition.accept(visitor);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java
index 92254308f431..1305663d7710 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java
@@ -19,16 +19,18 @@ import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.CommonProblemDescriptor;
import com.intellij.codeInspection.GlobalInspectionContext;
import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.reference.RefClass;
import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.codeInspection.reference.RefPackage;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.JavaPsiFacade;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiPackage;
+import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseGlobalInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.BaseSharedLocalInspection;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -60,7 +62,7 @@ public class MissingPackageInfoInspection extends BaseGlobalInspection {
final String packageName = refPackage.getQualifiedName();
final Project project = globalContext.getProject();
final PsiPackage aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName);
- if (aPackage == null) {
+ if (hasPackageInfoFile(aPackage)) {
return null;
}
final List<RefEntity> children = refPackage.getChildren();
@@ -74,21 +76,77 @@ public class MissingPackageInfoInspection extends BaseGlobalInspection {
if (!hasClasses) {
return null;
}
+ if (PsiUtil.isLanguageLevel5OrHigher(aPackage)) {
+ return new CommonProblemDescriptor[] {
+ manager.createProblemDescriptor(InspectionGadgetsBundle.message("missing.package.info.problem.descriptor", packageName))};
+ }
+ else {
+ return new CommonProblemDescriptor[] {
+ manager.createProblemDescriptor(InspectionGadgetsBundle.message("missing.package.html.problem.descriptor", packageName))};
+ }
+ }
+
+ @Contract("null -> true")
+ static boolean hasPackageInfoFile(PsiPackage aPackage) {
+ if (aPackage == null) {
+ return true;
+ }
final PsiDirectory[] directories = aPackage.getDirectories();
for (PsiDirectory directory : directories) {
final boolean packageInfoFound = directory.findFile(PsiPackage.PACKAGE_INFO_FILE) != null;
final boolean packageDotHtmlFound = directory.findFile("package.html") != null;
if (packageInfoFound || packageDotHtmlFound) {
- return null;
+ return true;
}
}
- if (PsiUtil.isLanguageLevel5OrHigher(aPackage)) {
- return new CommonProblemDescriptor[] {
- manager.createProblemDescriptor(InspectionGadgetsBundle.message("missing.package.info.problem.descriptor", packageName))};
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public LocalInspectionTool getSharedLocalInspectionTool() {
+ return new LocalMissingPackageInfoInspection(this);
+ }
+
+ private static class LocalMissingPackageInfoInspection extends BaseSharedLocalInspection<MissingPackageInfoInspection> {
+
+ public LocalMissingPackageInfoInspection(MissingPackageInfoInspection settingsDelegate) {
+ super(settingsDelegate);
}
- else {
- return new CommonProblemDescriptor[] {
- manager.createProblemDescriptor(InspectionGadgetsBundle.message("missing.package.html.problem.descriptor", packageName))};
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final PsiPackageStatement packageStatement = (PsiPackageStatement)infos[0];
+ if (PsiUtil.isLanguageLevel5OrHigher(packageStatement)) {
+ return InspectionGadgetsBundle.message("missing.package.info.problem.descriptor", packageStatement.getPackageName());
+ }
+ else {
+ return InspectionGadgetsBundle.message("missing.package.html.problem.descriptor", packageStatement.getPackageName());
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BaseInspectionVisitor() {
+ @Override
+ public void visitJavaFile(PsiJavaFile file) {
+ final PsiPackageStatement packageStatement = file.getPackageStatement();
+ if (packageStatement == null) {
+ return;
+ }
+ final PsiJavaCodeReferenceElement packageReference = packageStatement.getPackageReference();
+ final PsiElement target = packageReference.resolve();
+ if (!(target instanceof PsiPackage)) {
+ return;
+ }
+ final PsiPackage aPackage = (PsiPackage)target;
+ if (hasPackageInfoFile(aPackage)) {
+ return;
+ }
+ registerError(packageReference, packageStatement);
+ }
+ };
}
}
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspectionBase.java
new file mode 100644
index 000000000000..019893e18461
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspectionBase.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.javadoc;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.xml.XmlFile;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class PackageDotHtmlMayBePackageInfoInspectionBase extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("package.dot.html.may.be.package.info.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ if (((Boolean)infos[1]).booleanValue()) {
+ return InspectionGadgetsBundle.message("package.dot.html.may.be.package.info.exists.problem.descriptor");
+ }
+ return InspectionGadgetsBundle.message("package.dot.html.may.be.package.info.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new PackageDotHtmlMayBePackageInfoVisitor();
+ }
+
+ private static class PackageDotHtmlMayBePackageInfoVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitFile(PsiFile file) {
+ super.visitFile(file);
+ if (!(file instanceof XmlFile)) {
+ return;
+ }
+ @NonNls final String fileName = file.getName();
+ if (!"package.html".equals(fileName)) {
+ return;
+ }
+ final PsiDirectory directory = file.getContainingDirectory();
+ if (directory == null) {
+ return;
+ }
+ final String aPackage = getPackage(directory);
+ if (aPackage == null) {
+ return;
+ }
+ final boolean exists = directory.findFile("package-info.java") != null;
+ registerError(file, aPackage, Boolean.valueOf(exists));
+ }
+
+ public static String getPackage(@NotNull PsiDirectory directory) {
+ final VirtualFile virtualFile = directory.getVirtualFile();
+ final Project project = directory.getProject();
+ final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project);
+ final ProjectFileIndex fileIndex = projectRootManager.getFileIndex();
+ return fileIndex.getPackageNameByDirectory(virtualFile);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AssertAsNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AssertAsNameInspectionBase.java
new file mode 100644
index 000000000000..f4c8296789da
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/AssertAsNameInspectionBase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.jdk;
+
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class AssertAsNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "AssertAsIdentifier";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "use.assert.as.identifier.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "use.assert.as.identifier.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new AssertAsNameVisitor();
+ }
+
+ private static class AssertAsNameVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitVariable(@NotNull PsiVariable variable) {
+ super.visitVariable(variable);
+ final String variableName = variable.getName();
+ if (!PsiKeyword.ASSERT.equals(variableName)) {
+ return;
+ }
+ registerVariableError(variable);
+ }
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ final String name = method.getName();
+ if (!PsiKeyword.ASSERT.equals(name)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //note: no call to super, to avoid drill-down
+ final String name = aClass.getName();
+ if (!PsiKeyword.ASSERT.equals(name)) {
+ return;
+ }
+ final PsiTypeParameterList params = aClass.getTypeParameterList();
+ if (params != null) {
+ params.accept(this);
+ }
+ registerClassError(aClass);
+ }
+
+ @Override
+ public void visitTypeParameter(PsiTypeParameter parameter) {
+ super.visitTypeParameter(parameter);
+ final String name = parameter.getName();
+ if (!PsiKeyword.ASSERT.equals(name)) {
+ return;
+ }
+ registerTypeParameterError(parameter);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/EnumAsNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/EnumAsNameInspectionBase.java
new file mode 100644
index 000000000000..e24a29d6cb3a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/EnumAsNameInspectionBase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.jdk;
+
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class EnumAsNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "EnumAsIdentifier";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "use.enum.as.identifier.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "use.enum.as.identifier.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new EnumAsNameVisitor();
+ }
+
+ private static class EnumAsNameVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitVariable(@NotNull PsiVariable variable) {
+ super.visitVariable(variable);
+ final String variableName = variable.getName();
+ if (!PsiKeyword.ENUM.equals(variableName)) {
+ return;
+ }
+ registerVariableError(variable);
+ }
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ final String name = method.getName();
+ if (!PsiKeyword.ENUM.equals(name)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //note: no call to super, to avoid drill-down
+ final String name = aClass.getName();
+ if (!PsiKeyword.ENUM.equals(name)) {
+ return;
+ }
+ final PsiTypeParameterList params = aClass.getTypeParameterList();
+ if (params != null) {
+ params.accept(this);
+ }
+ registerClassError(aClass);
+ }
+
+ @Override
+ public void visitTypeParameter(PsiTypeParameter parameter) {
+ super.visitTypeParameter(parameter);
+ final String name = parameter.getName();
+ if (!PsiKeyword.ENUM.equals(name)) {
+ return;
+ }
+ registerTypeParameterError(parameter);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java
new file mode 100644
index 000000000000..69444ef1431f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiFormatUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "BeforeOrAfterWithIncorrectSignature";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "before.class.or.after.class.is.public.static.void.no.arg.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "before.class.or.after.class.is.public.static.void.no.arg.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BeforeClassOrAfterClassIsPublicStaticVoidNoArgVisitor();
+ }
+
+ private static class BeforeClassOrAfterClassIsPublicStaticVoidNoArgVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //note: no call to super;
+ if (!TestUtils.isJUnit4BeforeClassOrAfterClassMethod(method)) {
+ return;
+ }
+ final PsiType returnType = method.getReturnType();
+ if (returnType == null) {
+ return;
+ }
+ final PsiClass targetClass = method.getContainingClass();
+ if (targetClass == null) {
+ return;
+ }
+
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() != 0 ||
+ !returnType.equals(PsiType.VOID) ||
+ !method.hasModifierProperty(PsiModifier.PUBLIC) ||
+ !method.hasModifierProperty(PsiModifier.STATIC)) {
+ registerMethodError(method, "Change signature of \'" +
+ PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
+ PsiFormatUtil.SHOW_NAME |
+ PsiFormatUtil.SHOW_MODIFIERS |
+ PsiFormatUtil.SHOW_PARAMETERS |
+ PsiFormatUtil.SHOW_TYPE,
+ PsiFormatUtil.SHOW_TYPE) +
+ "\' to \'public static void " +
+ method.getName() +
+ "()\'");
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java
new file mode 100644
index 000000000000..c527c7ee951c
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+public class JUnit4AnnotatedMethodInJUnit3TestCaseInspectionBase extends BaseInspection {
+ protected static final String IGNORE = "org.junit.Ignore";
+
+ @Override
+ @Nls
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("junit4.test.method.in.class.extending.junit3.testcase.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ if (AnnotationUtil.isAnnotated((PsiMethod)infos[1], IGNORE, false)) {
+ return InspectionGadgetsBundle.message("ignore.test.method.in.class.extending.junit3.testcase.problem.descriptor");
+ }
+ return InspectionGadgetsBundle.message("junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new Junit4AnnotatedMethodInJunit3TestCaseVisitor();
+ }
+
+ private static class Junit4AnnotatedMethodInJunit3TestCaseVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ super.visitMethod(method);
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ if (!TestUtils.isJUnitTestClass(containingClass)) {
+ return;
+ }
+ if (AnnotationUtil.isAnnotated(method, IGNORE, false) && method.getName().startsWith("test")) {
+ registerMethodError(method, containingClass, method);
+ } else if (TestUtils.isJUnit4TestMethod(method)) {
+ registerMethodError(method, containingClass, method);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..fce2f99b4b10
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitAbstractTestClassNamingConventionInspectionBase.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiTypeParameter;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.naming.ConventionInspection;
+import org.jetbrains.annotations.NotNull;
+
+public class JUnitAbstractTestClassNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 12;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "junit.abstract.test.class.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String className = (String)infos[0];
+ if (className.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "junit.abstract.test.class.naming.convention.problem.descriptor.short");
+ }
+ else if (className.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "junit.abstract.test.class.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "junit.abstract.test.class.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*TestCase";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitElement(PsiElement element) {
+ if (!(element instanceof PsiClass)) {
+ super.visitElement(element);
+ return;
+ }
+
+ PsiClass aClass = (PsiClass)element;
+ if (aClass.isInterface() || aClass.isEnum() ||
+ aClass.isAnnotationType()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ if (!InheritanceUtil.isInheritor(aClass,
+ "junit.framework.TestCase")) {
+ return;
+ }
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerClassError(aClass, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..cbbd14eab21b
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnitTestClassNamingConventionInspectionBase.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.naming.ConventionInspection;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class JUnitTestClassNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 8;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "junit.test.class.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String className = (String)infos[0];
+ if (className.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "junit.test.class.naming.convention.problem.descriptor.short");
+ }
+ else if (className.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "junit.test.class.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "junit.test.class.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*Test";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+ @Override
+ public void visitElement(PsiElement element) {
+ if (!(element instanceof PsiClass)) {
+ super.visitElement(element);
+ return;
+ }
+
+ PsiClass aClass = (PsiClass)element;
+ if (aClass.isInterface() || aClass.isEnum() ||
+ aClass.isAnnotationType()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ if (!InheritanceUtil.isInheritor(aClass,
+ "junit.framework.TestCase")) {
+ if (!hasJUnit4TestMethods(aClass)) {
+ return;
+ }
+ }
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerClassError(aClass, name);
+ }
+
+ private boolean hasJUnit4TestMethods(@NotNull PsiClass aClass) {
+ //use this if this method turns out to have bad performance:
+ //if (!TestUtils.isTest(aClass)) {
+ // return false;
+ //}
+ final PsiMethod[] methods = aClass.getMethods();
+ for (PsiMethod method : methods) {
+ if (TestUtils.isJUnit4TestMethod(method)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java
new file mode 100644
index 000000000000..af3f874fca3b
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledSetUpInspectionBase.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class MisspelledSetUpInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "misspelled.set.up.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "misspelled.set.up.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MisspelledSetUpVisitor();
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ private static class MisspelledSetUpVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //note: no call to super
+ final PsiClass aClass = method.getContainingClass();
+ @NonNls final String methodName = method.getName();
+ if (!"setup".equals(methodName)) {
+ return;
+ }
+ if (aClass == null) {
+ return;
+ }
+ if (!InheritanceUtil.isInheritor(aClass,
+ "junit.framework.TestCase")) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java
new file mode 100644
index 000000000000..d6858bff4ec4
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisspelledTearDownInspectionBase.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class MisspelledTearDownInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "misspelled.tear.down.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "misspelled.tear.down.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MisspelledSetUpVisitor();
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ private static class MisspelledSetUpVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ // note: no call to super
+ @NonNls final String methodName = method.getName();
+ if (!"teardown".equals(methodName)) {
+ return;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ if (!InheritanceUtil.isInheritor(aClass,
+ "junit.framework.TestCase")) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java
new file mode 100644
index 000000000000..b13dbc94ec4d
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/ParameterizedParametersStaticCollectionInspectionBase.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ParameterizedParametersStaticCollectionInspectionBase extends BaseInspection {
+ protected static final String PARAMETERS_FQN = "org.junit.runners.Parameterized.Parameters";
+ private static final String PARAMETERIZED_FQN = "org.junit.runners.Parameterized";
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return infos.length > 0
+ ? (String)infos[1]
+ : "Class #ref annotated @RunWith(Parameterized.class) lacks data provider";
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BaseInspectionVisitor() {
+ @Override
+ public void visitClass(PsiClass aClass) {
+ final PsiAnnotation annotation = AnnotationUtil.findAnnotation(aClass, "org.junit.runner.RunWith");
+ if (annotation != null) {
+ for (PsiNameValuePair pair : annotation.getParameterList().getAttributes()) {
+ final PsiAnnotationMemberValue value = pair.getValue();
+ if (value instanceof PsiClassObjectAccessExpression) {
+ final PsiTypeElement typeElement = ((PsiClassObjectAccessExpression)value).getOperand();
+ if (typeElement.getType().getCanonicalText().equals(PARAMETERIZED_FQN)) {
+ List<MethodCandidate> candidates = new ArrayList<MethodCandidate>();
+ for (PsiMethod method : aClass.getMethods()) {
+ PsiType returnType = method.getReturnType();
+ final PsiClass returnTypeClass = PsiUtil.resolveClassInType(returnType);
+ final Project project = aClass.getProject();
+ final PsiClass collectionsClass =
+ JavaPsiFacade.getInstance(project).findClass(Collection.class.getName(), GlobalSearchScope.allScope(project));
+ if (AnnotationUtil.isAnnotated(method, PARAMETERS_FQN, false)) {
+ final PsiModifierList modifierList = method.getModifierList();
+ boolean hasToFixSignature = false;
+ String message = "Make method \'" + method.getName() + "\' ";
+ String errorString = "Method \'#ref()\' should be ";
+ if (!modifierList.hasModifierProperty(PsiModifier.PUBLIC)) {
+ message += PsiModifier.PUBLIC + " ";
+ errorString += PsiModifier.PUBLIC + " ";
+ hasToFixSignature = true;
+ }
+ if (!modifierList.hasModifierProperty(PsiModifier.STATIC)) {
+ message += PsiModifier.STATIC;
+ errorString += PsiModifier.STATIC;
+ hasToFixSignature = true;
+ }
+ if (collectionsClass != null &&
+ (returnTypeClass == null || !InheritanceUtil.isInheritorOrSelf(returnTypeClass, collectionsClass, true))) {
+ message += (hasToFixSignature ? " and" : "") + " return Collection";
+ errorString += (hasToFixSignature ? " and" : "") + " return Collection";
+ returnType = JavaPsiFacade.getElementFactory(project).createType(collectionsClass);
+ hasToFixSignature = true;
+ }
+ if (hasToFixSignature) {
+ candidates.add(new MethodCandidate(method, message, errorString, returnType));
+ continue;
+ }
+ return;
+ }
+ }
+ if (candidates.isEmpty()) {
+ registerClassError(aClass);
+ }
+ else {
+ for (MethodCandidate candidate : candidates) {
+ registerMethodError(candidate.myMethod, candidate.myProblem, candidate.myErrorString, candidate.myReturnType);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+
+ @Override
+ @Nls
+ @NotNull
+ public String getDisplayName() {
+ return "@RunWith(Parameterized.class) without data provider";
+ }
+
+ private static class MethodCandidate {
+ PsiMethod myMethod;
+ String myProblem;
+ private final String myErrorString;
+ PsiType myReturnType;
+
+ public MethodCandidate(PsiMethod method, String problem, String errorString, PsiType returnType) {
+ myMethod = method;
+ myProblem = problem;
+ myErrorString = errorString;
+ myReturnType = returnType;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java
new file mode 100644
index 000000000000..32f412b4184e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestCaseInProductCodeInspectionBase.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class TestCaseInProductCodeInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "test.case.in.product.code.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "JUnitTestCaseInProductSource";
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "test.case.in.product.code.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new TestCaseInProductCodeVisitor();
+ }
+
+ private static class TestCaseInProductCodeVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (TestUtils.isTest(aClass)) {
+ return;
+ }
+ if (!InheritanceUtil.isInheritor(aClass,
+ "junit.framework.TestCase")) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java
new file mode 100644
index 000000000000..59710abc953b
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspectionBase.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TestUtils;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class TestMethodWithoutAssertionInspectionBase extends BaseInspection {
+ protected final List<String> methodNamePatterns = new ArrayList<String>();
+ protected final List<String> classNames = new ArrayList<String>();
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls public String assertionMethods =
+ "org.junit.Assert,assert.*|fail.*," +
+ "junit.framework.Assert,assert.*|fail.*," +
+ "org.mockito.Mockito,verify.*," +
+ "org.junit.rules.ExpectedException,expect.*," +
+ "org.hamcrest.MatcherAssert,assertThat";
+ @SuppressWarnings({"PublicField"})
+ public boolean assertKeywordIsAssertion = false;
+ private Map<String, Pattern> patternCache = null;
+
+ public TestMethodWithoutAssertionInspectionBase() {
+ parseString(assertionMethods, classNames, methodNamePatterns);
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "JUnitTestMethodWithNoAssertions";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("test.method.without.assertion.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("test.method.without.assertion.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(assertionMethods, classNames, methodNamePatterns);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ assertionMethods = formatString(classNames, methodNamePatterns);
+ super.writeSettings(element);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new TestMethodWithoutAssertionVisitor();
+ }
+
+ private boolean methodNamesMatch(String methodName, String methodNamePattern) {
+ Pattern pattern;
+ if (patternCache != null) {
+ pattern = patternCache.get(methodNamePattern);
+ }
+ else {
+ patternCache = new HashMap<String, Pattern>(methodNamePatterns.size());
+ pattern = null;
+ }
+ if (pattern == null) {
+ try {
+ pattern = Pattern.compile(methodNamePattern);
+ patternCache.put(methodNamePattern, pattern);
+ }
+ catch (PatternSyntaxException ignore) {
+ return false;
+ }
+ catch (NullPointerException ignore) {
+ return false;
+ }
+ }
+ if (pattern == null) {
+ return false;
+ }
+ final Matcher matcher = pattern.matcher(methodName);
+ return matcher.matches();
+ }
+
+ private class TestMethodWithoutAssertionVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ if (!TestUtils.isJUnitTestMethod(method)) {
+ return;
+ }
+ if (hasExpectedExceptionAnnotation(method)) {
+ return;
+ }
+ if (containsAssertion(method)) {
+ return;
+ }
+ if (lastStatementIsCallToMethodWithAssertion(method)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+
+ private boolean lastStatementIsCallToMethodWithAssertion(PsiMethod method) {
+ final PsiCodeBlock body = method.getBody();
+ if (body == null) {
+ return false;
+ }
+ final PsiStatement[] statements = body.getStatements();
+ if (statements.length <= 0) {
+ return false;
+ }
+ final PsiStatement lastStatement = statements[0];
+ if (!(lastStatement instanceof PsiExpressionStatement)) {
+ return false;
+ }
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)lastStatement;
+ final PsiExpression expression = expressionStatement.getExpression();
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ if (qualifierExpression != null && !(qualifierExpression instanceof PsiThisExpression)) {
+ return false;
+ }
+ final PsiMethod targetMethod = methodCallExpression.resolveMethod();
+ return containsAssertion(targetMethod);
+ }
+
+ private boolean containsAssertion(PsiElement element) {
+ if (element == null) {
+ return false;
+ }
+ final ContainsAssertionVisitor
+ visitor = new ContainsAssertionVisitor();
+ element.accept(visitor);
+ return visitor.containsAssertion();
+ }
+
+ private boolean hasExpectedExceptionAnnotation(PsiMethod method) {
+ final PsiModifierList modifierList = method.getModifierList();
+ final PsiAnnotation testAnnotation = modifierList.findAnnotation("org.junit.Test");
+ if (testAnnotation == null) {
+ return false;
+ }
+ final PsiAnnotationParameterList parameterList = testAnnotation.getParameterList();
+ final PsiNameValuePair[] nameValuePairs = parameterList.getAttributes();
+ for (PsiNameValuePair nameValuePair : nameValuePairs) {
+ @NonNls final String parameterName = nameValuePair.getName();
+ if ("expected".equals(parameterName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private class ContainsAssertionVisitor extends JavaRecursiveElementVisitor {
+
+ private boolean containsAssertion = false;
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (!containsAssertion) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) {
+ if (containsAssertion) {
+ return;
+ }
+ super.visitMethodCallExpression(call);
+ final PsiReferenceExpression methodExpression = call.getMethodExpression();
+ @NonNls final String methodName = methodExpression.getReferenceName();
+ if (methodName == null) {
+ return;
+ }
+ final int methodNamesSize = methodNamePatterns.size();
+ for (int i = 0; i < methodNamesSize; i++) {
+ final String pattern = methodNamePatterns.get(i);
+ if (!methodNamesMatch(methodName, pattern)) {
+ continue;
+ }
+ final PsiMethod method = call.resolveMethod();
+ if (method == null || method.isConstructor()) {
+ continue;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (!InheritanceUtil.isInheritor(aClass, classNames.get(i))) {
+ continue;
+ }
+ containsAssertion = true;
+ break;
+ }
+ }
+
+ @Override
+ public void visitAssertStatement(PsiAssertStatement statement) {
+ if (containsAssertion) {
+ return;
+ }
+ super.visitAssertStatement(statement);
+ if (!assertKeywordIsAssertion) {
+ return;
+ }
+ containsAssertion = true;
+ }
+
+ public boolean containsAssertion() {
+ return containsAssertion;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java
new file mode 100644
index 000000000000..59b168af1434
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/UseOfObsoleteAssertInspection.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.junit;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class UseOfObsoleteAssertInspection extends BaseInspection {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("usage.of.obsolete.assert.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("use.of.obsolete.assert.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new ReplaceObsoleteAssertsFix();
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UseOfObsoleteAssertVisitor();
+ }
+
+ private static class UseOfObsoleteAssertVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ final Project project = expression.getProject();
+ final Module module = ModuleUtilCore.findModuleForPsiElement(expression);
+ if (module == null) {
+ return;
+ }
+ final PsiClass newAssertClass = JavaPsiFacade.getInstance(project)
+ .findClass("org.junit.Assert", GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module));
+ if (newAssertClass == null) {
+ return;
+ }
+ final PsiMethod psiMethod = expression.resolveMethod();
+ if (psiMethod == null || !psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final PsiClass containingClass = psiMethod.getContainingClass();
+ if (containingClass != null && Comparing.strEqual(containingClass.getQualifiedName(), "junit.framework.Assert")) {
+ registerMethodCallError(expression);
+ }
+ }
+ }
+
+ private static class ReplaceObsoleteAssertsFix extends InspectionGadgetsFix {
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiElement psiElement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class);
+ if (!(psiElement instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ final PsiClass newAssertClass =
+ JavaPsiFacade.getInstance(project).findClass("org.junit.Assert", GlobalSearchScope.allScope(project));
+ final PsiClass oldAssertClass =
+ JavaPsiFacade.getInstance(project).findClass("junit.framework.Assert", GlobalSearchScope.allScope(project));
+
+ if (newAssertClass == null) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)psiElement;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ final PsiElement usedImport = qualifierExpression instanceof PsiReferenceExpression ?
+ ((PsiReferenceExpression)qualifierExpression).advancedResolve(true).getCurrentFileResolveScope() :
+ methodExpression.advancedResolve(true).getCurrentFileResolveScope();
+ final PsiMethod psiMethod = methodCallExpression.resolveMethod();
+
+ final boolean isImportUnused = isImportBecomeUnused(methodCallExpression, usedImport, psiMethod);
+
+ PsiImportStaticStatement staticStatement = null;
+ if (qualifierExpression == null) {
+ staticStatement = staticallyImported(oldAssertClass, methodExpression);
+ }
+
+ final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project);
+ if (staticStatement == null) {
+ methodExpression.setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass));
+
+ if (isImportUnused && usedImport instanceof PsiImportStatementBase) {
+ usedImport.delete();
+ }
+
+ styleManager.shortenClassReferences(methodExpression);
+ }
+ else {
+ if (isImportUnused) {
+ final PsiJavaCodeReferenceElement importReference = staticStatement.getImportReference();
+ if (importReference != null) {
+ if (staticStatement.isOnDemand()) {
+ importReference.bindToElement(newAssertClass);
+ }
+ else {
+ final PsiElement importQExpression = importReference.getQualifier();
+ if (importQExpression instanceof PsiReferenceExpression) {
+ ((PsiReferenceExpression)importQExpression).bindToElement(newAssertClass);
+ }
+ }
+ }
+ }
+ else {
+ methodExpression
+ .setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass));
+ styleManager.shortenClassReferences(methodExpression);
+ }
+ }
+ /*
+ //refs can be optimized now but should we really?
+ if (isImportUnused) {
+ for (PsiReference reference : ReferencesSearch.search(newAssertClass, new LocalSearchScope(methodCallExpression.getContainingFile()))) {
+ final PsiElement element = reference.getElement();
+ styleManager.shortenClassReferences(element);
+ }
+ }*/
+ }
+
+ private static boolean isImportBecomeUnused(final PsiMethodCallExpression methodCallExpression,
+ final PsiElement usedImport,
+ final PsiMethod psiMethod) {
+ final boolean[] proceed = new boolean[]{true};
+ methodCallExpression.getContainingFile().accept(new JavaRecursiveElementWalkingVisitor() {
+ @Override
+ public void visitElement(PsiElement element) {
+ if (proceed[0]) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ if (expression == methodCallExpression) {
+ return;
+ }
+ final PsiMethod resolved = expression.resolveMethod();
+ if (resolved == psiMethod) {
+ proceed[0] = false;
+ }
+ else {
+ final PsiElement resolveScope =
+ expression.getMethodExpression().advancedResolve(false).getCurrentFileResolveScope();
+ if (resolveScope == usedImport) {
+ proceed[0] = false;
+ }
+ }
+ }
+ });
+ return proceed[0];
+ }
+
+ @Nullable
+ private static PsiImportStaticStatement staticallyImported(PsiClass oldAssertClass, PsiReferenceExpression methodExpression) {
+ final String referenceName = methodExpression.getReferenceName();
+ final PsiFile containingFile = methodExpression.getContainingFile();
+ if (!(containingFile instanceof PsiJavaFile)) {
+ return null;
+ }
+ final PsiImportList importList = ((PsiJavaFile)containingFile).getImportList();
+ if (importList == null) {
+ return null;
+ }
+ final PsiImportStaticStatement[] statements = importList.getImportStaticStatements();
+ for (PsiImportStaticStatement statement : statements) {
+ if (oldAssertClass != statement.resolveTargetClass()) {
+ continue;
+ }
+ final String importRefName = statement.getReferenceName();
+ final PsiJavaCodeReferenceElement importReference = statement.getImportReference();
+ if (importReference == null) {
+ continue;
+ }
+ if (Comparing.strEqual(importRefName, referenceName)) {
+ final PsiElement qualifier = importReference.getQualifier();
+ if (qualifier instanceof PsiJavaCodeReferenceElement) {
+ return statement;
+ }
+ }
+ else if (importRefName == null) {
+ return statement;
+ }
+ }
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return InspectionGadgetsBundle.message("use.of.obsolete.assert.quickfix");
+ }
+
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspectionBase.java
new file mode 100644
index 000000000000..6478d2a97a9a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspectionBase.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassWithMultipleLoggersInspectionBase extends BaseInspection {
+ protected final List<String> loggerNames = new ArrayList();
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls
+ public String loggerNamesString = "java.util.logging.Logger" + ',' +
+ "org.slf4j.Logger" + ',' +
+ "org.apache.commons.logging.Log" + ',' +
+ "org.apache.log4j.Logger";
+
+ public ClassWithMultipleLoggersInspectionBase() {
+ parseString(loggerNamesString, loggerNames);
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("multiple.loggers.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "multiple.loggers.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(loggerNamesString, loggerNames);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ loggerNamesString = formatString(loggerNames);
+ super.writeSettings(element);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassWithMultipleLoggersVisitor();
+ }
+
+ private class ClassWithMultipleLoggersVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //no recursion to avoid drilldown
+ if (aClass.isInterface() || aClass.isEnum() ||
+ aClass.isAnnotationType()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ if (aClass.getContainingClass() != null) {
+ return;
+ }
+ int numLoggers = 0;
+ final PsiField[] fields = aClass.getFields();
+ for (PsiField field : fields) {
+ if (isLogger(field)) {
+ numLoggers++;
+ }
+ }
+ if (numLoggers <= 1) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+
+ private boolean isLogger(PsiVariable variable) {
+ final PsiType type = variable.getType();
+ final String text = type.getCanonicalText();
+ return loggerNames.contains(text);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithoutLoggerInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithoutLoggerInspectionBase.java
new file mode 100644
index 000000000000..b1dad3eaadac
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/ClassWithoutLoggerInspectionBase.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassWithoutLoggerInspectionBase extends BaseInspection {
+ protected final List<String> loggerNames = new ArrayList();
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls
+ public String loggerNamesString = "java.util.logging.Logger" + ',' +
+ "org.slf4j.Logger" + ',' +
+ "org.apache.commons.logging.Log" + ',' +
+ "org.apache.log4j.Logger";
+ /**
+ * @noinspection PublicField
+ */
+ public boolean ignoreSuperLoggers = false;
+
+ public ClassWithoutLoggerInspectionBase() {
+ parseString(loggerNamesString, loggerNames);
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("no.logger.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("no.logger.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(loggerNamesString, loggerNames);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ loggerNamesString = formatString(loggerNames);
+ super.writeSettings(element);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassWithoutLoggerVisitor();
+ }
+
+ private class ClassWithoutLoggerVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //no recursion to avoid drilldown
+ if (aClass.isInterface() || aClass.isEnum() ||
+ aClass.isAnnotationType()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter ||
+ aClass instanceof PsiAnonymousClass) {
+ return;
+ }
+ if (aClass.getContainingClass() != null) {
+ return;
+ }
+ final PsiField[] fields;
+ if (ignoreSuperLoggers) {
+ fields = aClass.getAllFields();
+ }
+ else {
+ fields = aClass.getFields();
+ }
+ for (PsiField field : fields) {
+ if (isLogger(field)) {
+ if (PsiUtil.isAccessible(field, aClass, aClass)) {
+ return;
+ }
+ }
+ }
+ registerClassError(aClass);
+ }
+
+ private boolean isLogger(PsiVariable variable) {
+ final PsiType type = variable.getType();
+ final String text = type.getCanonicalText();
+ return loggerNames.contains(text);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java
new file mode 100644
index 000000000000..0413d835f139
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.TypeUtils;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LogStatementGuardedByLogConditionInspectionBase extends BaseInspection {
+ final List<String> logMethodNameList = new ArrayList();
+ final List<String> logConditionMethodNameList = new ArrayList();
+ @SuppressWarnings({"PublicField"})
+ public String loggerClassName = "java.util.logging.Logger";
+ @NonNls
+ @SuppressWarnings({"PublicField"})
+ public String loggerMethodAndconditionMethodNames =
+ "fine,isLoggable(java.util.logging.Level.FINE)," +
+ "finer,isLoggable(java.util.logging.Level.FINER)," +
+ "finest,isLoggable(java.util.logging.Level.FINEST)";
+ @SuppressWarnings("PublicField")
+ public boolean flagAllUnguarded = false;
+
+ public LogStatementGuardedByLogConditionInspectionBase() {
+ parseString(loggerMethodAndconditionMethodNames, logMethodNameList, logConditionMethodNameList);
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("log.statement.guarded.by.log.condition.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("log.statement.guarded.by.log.condition.problem.descriptor");
+ }
+
+ @Override
+ @Nullable
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new LogStatementGuardedByLogConditionFix();
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new LogStatementGuardedByLogConditionVisitor();
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(loggerMethodAndconditionMethodNames, logMethodNameList, logConditionMethodNameList);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ loggerMethodAndconditionMethodNames = formatString(logMethodNameList, logConditionMethodNameList);
+ super.writeSettings(element);
+ }
+
+ private class LogStatementGuardedByLogConditionFix extends InspectionGadgetsFix {
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("log.statement.guarded.by.log.condition.quickfix");
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element.getParent().getParent();
+ final PsiStatement statement = PsiTreeUtil.getParentOfType(methodCallExpression, PsiStatement.class);
+ if (statement == null) {
+ return;
+ }
+ final List<PsiStatement> logStatements = new ArrayList();
+ logStatements.add(statement);
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (referenceName == null) {
+ return;
+ }
+ PsiStatement previousStatement = PsiTreeUtil.getPrevSiblingOfType(statement, PsiStatement.class);
+ while (previousStatement != null && isSameLogMethodCall(previousStatement, referenceName)) {
+ logStatements.add(0, previousStatement);
+ previousStatement = PsiTreeUtil.getPrevSiblingOfType(previousStatement, PsiStatement.class);
+ }
+ PsiStatement nextStatement = PsiTreeUtil.getNextSiblingOfType(statement, PsiStatement.class);
+ while (nextStatement != null && isSameLogMethodCall(nextStatement, referenceName)) {
+ logStatements.add(nextStatement);
+ nextStatement = PsiTreeUtil.getNextSiblingOfType(nextStatement, PsiStatement.class);
+ }
+ final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return;
+ }
+ final int index = logMethodNameList.indexOf(referenceName);
+ final String conditionMethodText = logConditionMethodNameList.get(index);
+ @NonNls final String ifStatementText = "if (" + qualifier.getText() + '.' + conditionMethodText + ") {}";
+ final PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(ifStatementText, statement);
+ final PsiBlockStatement blockStatement = (PsiBlockStatement)ifStatement.getThenBranch();
+ if (blockStatement == null) {
+ return;
+ }
+ final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
+ for (PsiStatement logStatement : logStatements) {
+ codeBlock.add(logStatement);
+ }
+ final PsiStatement firstStatement = logStatements.get(0);
+ final PsiElement parent = firstStatement.getParent();
+ final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
+ if (parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getElseBranch() != null) {
+ final PsiBlockStatement newBlockStatement = (PsiBlockStatement)factory.createStatementFromText("{}", statement);
+ newBlockStatement.getCodeBlock().add(ifStatement);
+ final PsiElement result = firstStatement.replace(newBlockStatement);
+ codeStyleManager.shortenClassReferences(result);
+ return;
+ }
+ final PsiElement result = parent.addBefore(ifStatement, firstStatement);
+ codeStyleManager.shortenClassReferences(result);
+ for (PsiStatement logStatement : logStatements) {
+ logStatement.delete();
+ }
+ }
+
+ private boolean isSameLogMethodCall(PsiStatement statement, @NotNull String methodName) {
+ if (statement == null) {
+ return false;
+ }
+ if (!(statement instanceof PsiExpressionStatement)) {
+ return false;
+ }
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statement;
+ final PsiExpression expression = expressionStatement.getExpression();
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (!methodName.equals(referenceName)) {
+ return false;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ return qualifier != null && TypeUtils.expressionHasTypeOrSubtype(qualifier, loggerClassName);
+ }
+ }
+
+ private class LogStatementGuardedByLogConditionVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (!logMethodNameList.contains(referenceName)) {
+ return;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return;
+ }
+ if (!TypeUtils.expressionHasTypeOrSubtype(qualifier, loggerClassName)) {
+ return;
+ }
+ if (isSurroundedByLogGuard(expression, referenceName)) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length == 0) {
+ return;
+ }
+ if (!flagAllUnguarded) {
+ boolean constant = true;
+ for (PsiExpression argument : arguments) {
+ if (!PsiUtil.isConstantExpression(argument)) {
+ constant = false;
+ break;
+ }
+ }
+ if (constant) {
+ return;
+ }
+ }
+ registerMethodCallError(expression);
+ }
+
+ private boolean isSurroundedByLogGuard(PsiElement element, String logMethodName) {
+ while (true) {
+ final PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(element, PsiIfStatement.class);
+ if (ifStatement == null) {
+ return false;
+ }
+ final PsiExpression condition = ifStatement.getCondition();
+ if (isLogGuardCheck(condition, logMethodName)) {
+ return true;
+ }
+ element = ifStatement;
+ }
+ }
+
+ private boolean isLogGuardCheck(@Nullable PsiExpression expression, String logMethodName) {
+ if (expression instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return false;
+ }
+ if (!TypeUtils.expressionHasTypeOrSubtype(qualifier, loggerClassName)) {
+ return false;
+ }
+ final String referenceName = methodExpression.getReferenceName();
+ if (referenceName == null) {
+ return false;
+ }
+ final int index = logMethodNameList.indexOf(logMethodName);
+ final String conditionName = logConditionMethodNameList.get(index);
+ return conditionName.startsWith(referenceName);
+ }
+ else if (expression instanceof PsiPolyadicExpression) {
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ for (PsiExpression operand : operands) {
+ if (isLogGuardCheck(operand, logMethodName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggerInitializedWithForeignClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggerInitializedWithForeignClassInspectionBase.java
new file mode 100644
index 000000000000..5a70933d865b
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggerInitializedWithForeignClassInspectionBase.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LoggerInitializedWithForeignClassInspectionBase extends BaseInspection {
+ @NonNls private static final String DEFAULT_LOGGER_CLASS_NAMES =
+ "org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger";
+ @NonNls private static final String DEFAULT_FACTORY_METHOD_NAMES = "getLogger,getLogger,getLog,getLogger";
+ protected final List<String> loggerFactoryClassNames = new ArrayList();
+ protected final List<String> loggerFactoryMethodNames = new ArrayList();
+ @SuppressWarnings({"PublicField"})
+ public String loggerClassName = DEFAULT_LOGGER_CLASS_NAMES;
+ @SuppressWarnings({"PublicField"})
+ public String loggerFactoryMethodName = DEFAULT_FACTORY_METHOD_NAMES;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("logger.initialized.with.foreign.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("logger.initialized.with.foreign.class.problem.descriptor");
+ }
+
+ @Override
+ @Nullable
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new LoggerInitializedWithForeignClassFix((String)infos[0]);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new LoggerInitializedWithForeignClassVisitor();
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(loggerClassName, loggerFactoryClassNames);
+ parseString(loggerFactoryMethodName, loggerFactoryMethodNames);
+ if (loggerFactoryClassNames.size() != loggerFactoryMethodNames.size()) {
+ parseString(DEFAULT_LOGGER_CLASS_NAMES, loggerFactoryClassNames);
+ parseString(DEFAULT_FACTORY_METHOD_NAMES, loggerFactoryMethodNames);
+ }
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ loggerClassName = formatString(loggerFactoryClassNames);
+ loggerFactoryMethodName = formatString(loggerFactoryMethodNames);
+ super.writeSettings(element);
+ }
+
+ private static class LoggerInitializedWithForeignClassFix extends InspectionGadgetsFix {
+
+ private final String newClassName;
+
+ private LoggerInitializedWithForeignClassFix(String newClassName) {
+ this.newClassName = newClassName;
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("logger.initialized.with.foreign.class.quickfix", newClassName);
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "Replace foreign class";
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ if (!(element instanceof PsiClassObjectAccessExpression)) {
+ return;
+ }
+ final PsiClassObjectAccessExpression classObjectAccessExpression = (PsiClassObjectAccessExpression)element;
+ replaceExpression(classObjectAccessExpression, newClassName + ".class");
+ }
+ }
+
+ private class LoggerInitializedWithForeignClassVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
+ super.visitClassObjectAccessExpression(expression);
+ PsiElement parent = expression.getParent();
+ if (parent instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)parent;
+ if (!expression.equals(referenceExpression.getQualifierExpression())) {
+ return;
+ }
+ @NonNls final String name = referenceExpression.getReferenceName();
+ if (!"getName".equals(name)) {
+ return;
+ }
+ final PsiElement grandParent = referenceExpression.getParent();
+ if (!(grandParent instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent;
+ final PsiExpressionList list = methodCallExpression.getArgumentList();
+ if (list.getExpressions().length != 0) {
+ return;
+ }
+ parent = methodCallExpression.getParent();
+ }
+ if (!(parent instanceof PsiExpressionList)) {
+ return;
+ }
+ final PsiElement grandParent = parent.getParent();
+ if (!(grandParent instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent;
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ final PsiExpression[] expressions = argumentList.getExpressions();
+ if (expressions.length != 1) {
+ return;
+ }
+ final PsiClass containingClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
+ if (containingClass == null) {
+ return;
+ }
+ final String containingClassName = containingClass.getName();
+ if (containingClassName == null) {
+ return;
+ }
+ final PsiMethod method = methodCallExpression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ final String className = aClass.getQualifiedName();
+ final int index = loggerFactoryClassNames.indexOf(className);
+ if (index < 0) {
+ return;
+ }
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ final String loggerFactoryMethodName = loggerFactoryMethodNames.get(index);
+ if (!loggerFactoryMethodName.equals(referenceName)) {
+ return;
+ }
+ final PsiTypeElement operand = expression.getOperand();
+ final PsiType type = operand.getType();
+ if (!(type instanceof PsiClassType)) {
+ return;
+ }
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiClass initializerClass = classType.resolve();
+ if (initializerClass == null) {
+ return;
+ }
+ if (containingClass.equals(initializerClass)) {
+ return;
+ }
+ registerError(expression, containingClassName);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggingConditionDisagreesWithLogStatementInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggingConditionDisagreesWithLogStatementInspection.java
new file mode 100644
index 000000000000..10d7a75a2b61
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LoggingConditionDisagreesWithLogStatementInspection.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2008-2012 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+public class LoggingConditionDisagreesWithLogStatementInspection extends BaseInspection {
+
+ private static final Set<String> loggingLevels = new HashSet(Arrays.asList(
+ "debug", "error", "fatal", "info", "trace", "warn", "severe", "warning", "info", "config", "fine", "finer", "finest"));
+
+ private static final Map<String, LoggingProblemChecker> problemCheckers = new HashMap();
+
+ static {
+ register(new Log4jProblemChecker());
+ register(new CommonsLoggingProblemChecker());
+ register(new JavaUtilLoggingProblemChecker());
+ register(new Slf4jProblemChecker());
+ }
+
+ private static void register(LoggingProblemChecker problemChecker) {
+ for (String name : problemChecker.getClassNames()) {
+ problemCheckers.put(name, problemChecker);
+ }
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("logging.condition.disagrees.with.log.statement.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("logging.condition.disagrees.with.log.statement.problem.descriptor", infos[0]);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new LoggingConditionDisagreesWithLogStatementVisitor();
+ }
+
+ private static class LoggingConditionDisagreesWithLogStatementVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (referenceName == null) {
+ return;
+ }
+ final String loggingLevel;
+ if (!loggingLevels.contains(referenceName)) {
+ if (!"log".equals(referenceName)) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length < 2) {
+ return;
+ }
+ final PsiExpression argument = arguments[0];
+ loggingLevel = JavaUtilLoggingProblemChecker.getLoggingLevelFromArgument(argument);
+ if (loggingLevel == null) {
+ return;
+ }
+ }
+ else {
+ loggingLevel = referenceName;
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final PsiElement parent = expression.getParent();
+ if (!(parent instanceof PsiExpressionStatement)) {
+ return;
+ }
+ final PsiElement grandParent = parent.getParent();
+ final PsiIfStatement ifStatement;
+ if (grandParent instanceof PsiCodeBlock) {
+ final PsiElement greatGrandParent = grandParent.getParent();
+ if (!(greatGrandParent instanceof PsiBlockStatement)) {
+ return;
+ }
+ final PsiElement greatGreatGrandParent = greatGrandParent.getParent();
+ if (!(greatGreatGrandParent instanceof PsiIfStatement)) {
+ return;
+ }
+ ifStatement = (PsiIfStatement)greatGreatGrandParent;
+ }
+ else if (grandParent instanceof PsiIfStatement) {
+ ifStatement = (PsiIfStatement)grandParent;
+ }
+ else {
+ return;
+ }
+ PsiExpression condition = ifStatement.getCondition();
+ if (condition instanceof PsiMethodCallExpression) {
+ final PsiStatement thenBranch = ifStatement.getThenBranch();
+ if (!PsiTreeUtil.isAncestor(thenBranch, expression, false)) {
+ return;
+ }
+ }
+ else if (condition instanceof PsiPrefixExpression) {
+ final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)condition;
+ if (!JavaTokenType.EXCL.equals(prefixExpression.getOperationTokenType())) {
+ return;
+ }
+ final PsiStatement elseBranch = ifStatement.getElseBranch();
+ if (!PsiTreeUtil.isAncestor(elseBranch, expression, false)) {
+ return;
+ }
+ condition = prefixExpression.getOperand();
+ if (!(condition instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ }
+ else {
+ return;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (target == null) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)condition;
+ final PsiReferenceExpression conditionMethodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression conditionQualifier = conditionMethodExpression.getQualifierExpression();
+ if (!(conditionQualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression conditionReferenceExpression = (PsiReferenceExpression)conditionQualifier;
+ final PsiElement conditionTarget = conditionReferenceExpression.resolve();
+ if (!target.equals(conditionTarget)) {
+ return;
+ }
+ final String qualifiedName = containingClass.getQualifiedName();
+ final LoggingProblemChecker problemChecker = problemCheckers.get(qualifiedName);
+ if (problemChecker == null || !problemChecker.hasLoggingProblem(loggingLevel, methodCallExpression)) {
+ return;
+ }
+ registerMethodCallError(methodCallExpression, loggingLevel);
+ }
+ }
+
+ interface LoggingProblemChecker {
+
+ String[] getClassNames();
+
+ boolean hasLoggingProblem(String priority, PsiMethodCallExpression methodCallExpression);
+ }
+
+ private static class JavaUtilLoggingProblemChecker implements LoggingProblemChecker {
+
+ @Override
+ public String[] getClassNames() {
+ return new String[]{"java.util.logging.Logger"};
+ }
+
+ @Override
+ public boolean hasLoggingProblem(String priority, PsiMethodCallExpression methodCallExpression) {
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!"isLoggable".equals(methodName)) {
+ return false;
+ }
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 1) {
+ return false;
+ }
+ final PsiExpression argument = arguments[0];
+ final String loggingLevel = getLoggingLevelFromArgument(argument);
+ if (loggingLevel == null) {
+ return false;
+ }
+ return !loggingLevel.equals(priority);
+ }
+
+ @Nullable
+ public static String getLoggingLevelFromArgument(PsiExpression argument) {
+ if (!(argument instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ final PsiReferenceExpression argumentReference = (PsiReferenceExpression)argument;
+ final PsiType type = argument.getType();
+ if (!(type instanceof PsiClassType)) {
+ return null;
+ }
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiClass aClass = classType.resolve();
+ if (aClass == null) {
+ return null;
+ }
+ final String qName = aClass.getQualifiedName();
+ if (!"java.util.logging.Level".equals(qName)) {
+ return null;
+ }
+ final PsiElement argumentTarget = argumentReference.resolve();
+ if (!(argumentTarget instanceof PsiField)) {
+ return null;
+ }
+ final PsiField field = (PsiField)argumentTarget;
+ return field.getName().toLowerCase();
+ }
+ }
+
+ private static class CommonsLoggingProblemChecker implements LoggingProblemChecker {
+
+ @Override
+ public String[] getClassNames() {
+ return new String[]{"org.apache.commons.logging.Log"};
+ }
+
+ @Override
+ public boolean hasLoggingProblem(String priority, PsiMethodCallExpression methodCallExpression) {
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if ("isTraceEnabled".equals(methodName)) {
+ return !priority.equals("trace");
+ }
+ else if ("isDebugEnabled".equals(methodName)) {
+ return !priority.equals("debug");
+ }
+ else if ("isInfoEnabled".equals(methodName)) {
+ return !priority.equals("info");
+ }
+ else if ("isWarnEnabled".equals(methodName)) {
+ return !priority.equals("warn");
+ }
+ else if ("isErrorEnabled".equals(methodName)) {
+ return !priority.equals("error");
+ }
+ else if ("isFatalEnabled".equals(methodName)) {
+ return !priority.equals("fatal");
+ }
+ return false;
+ }
+ }
+
+ private static class Slf4jProblemChecker implements LoggingProblemChecker {
+ @Override
+ public String[] getClassNames() {
+ return new String[]{"org.slf4j.Logger"};
+ }
+
+ @Override
+ public boolean hasLoggingProblem(String priority, PsiMethodCallExpression methodCallExpression) {
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if ("isTraceEnabled".equals(methodName)) {
+ return !"trace".equals(priority);
+ }
+ else if ("isDebugEnabled".equals(methodName)) {
+ return !"debug".equals(priority);
+ }
+ else if ("isInfoEnabled".equals(methodName)) {
+ return !"info".equals(priority);
+ }
+ else if ("isWarnEnabled".equals(methodName)) {
+ return !"warn".equals(priority);
+ }
+ else if ("isErrorEnabled".equals(methodName)) {
+ return !"error".equals(priority);
+ }
+ return false;
+ }
+ }
+
+ private static class Log4jProblemChecker implements LoggingProblemChecker {
+
+ @Override
+ public String[] getClassNames() {
+ return new String[]{"org.apache.log4j.Logger", "org.apache.log4j.Category"};
+ }
+
+ @Override
+ public boolean hasLoggingProblem(String priority, PsiMethodCallExpression methodCallExpression) {
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ String enabledFor = null;
+ if ("isDebugEnabled".equals(methodName)) {
+ enabledFor = "debug";
+ }
+ else if ("isInfoEnabled".equals(methodName)) {
+ enabledFor = "info";
+ }
+ else if ("isTraceEnabled".equals(methodName)) {
+ enabledFor = "trace";
+ }
+ else if ("isEnabledFor".equals(methodName)) {
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ for (PsiExpression argument : arguments) {
+ if (!(argument instanceof PsiReferenceExpression)) {
+ continue;
+ }
+ final PsiReferenceExpression argumentReference = (PsiReferenceExpression)argument;
+ final PsiType type = argument.getType();
+ if (!(type instanceof PsiClassType)) {
+ continue;
+ }
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiClass aClass = classType.resolve();
+ if (!InheritanceUtil.isInheritor(aClass, "org.apache.log4j.Priority")) {
+ continue;
+ }
+ final PsiElement argumentTarget = argumentReference.resolve();
+ if (!(argumentTarget instanceof PsiField)) {
+ continue;
+ }
+ final PsiField field = (PsiField)argumentTarget;
+ enabledFor = field.getName().toLowerCase();
+ }
+ if (enabledFor == null) {
+ return false;
+ }
+ }
+ return !priority.equals(enabledFor);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspectionBase.java
new file mode 100644
index 000000000000..78d1aa9c858a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspectionBase.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.MakeFieldStaticFinalFix;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NonStaticFinalLoggerInspectionBase extends BaseInspection {
+ protected final List<String> loggerClassNames = new ArrayList();
+ @SuppressWarnings("PublicField")
+ public String loggerClassName = "java.util.logging.Logger" + ',' +
+ "org.slf4j.Logger" + ',' +
+ "org.apache.commons.logging.Log" + ',' +
+ "org.apache.log4j.Logger";
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "NonConstantLogger";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("non.constant.logger.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("non.constant.logger.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ final PsiField field = (PsiField)infos[0];
+ return MakeFieldStaticFinalFix.buildFixUnconditional(field);
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(loggerClassName, loggerClassNames);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ loggerClassName = formatString(loggerClassNames);
+ super.writeSettings(element);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NonStaticFinalLoggerVisitor();
+ }
+
+ private class NonStaticFinalLoggerVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ if (aClass.getContainingClass() != null) {
+ return;
+ }
+ final PsiField[] fields = aClass.getFields();
+ for (final PsiField field : fields) {
+ if (!isLogger(field)) {
+ continue;
+ }
+ if (field.hasModifierProperty(PsiModifier.STATIC) && field.hasModifierProperty(PsiModifier.FINAL)) {
+ continue;
+ }
+ registerFieldError(field, field);
+ }
+ }
+
+ private boolean isLogger(PsiVariable variable) {
+ final PsiType type = variable.getType();
+ final String text = type.getCanonicalText();
+ return loggerClassNames.contains(text);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java
new file mode 100644
index 000000000000..0a6ef31fcc7e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.util.containers.ContainerUtilRt;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+public class PlaceholderCountMatchesArgumentCountInspection extends BaseInspection {
+
+ @NonNls
+ private static final Set<String> loggingMethodNames = ContainerUtilRt.newHashSet("trace", "debug", "info", "warn", "error");
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("placeholder.count.matches.argument.count.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final int argumentCount = ((Integer)infos[0]).intValue();
+ final int placeholderCount = ((Integer)infos[1]).intValue();
+ if (argumentCount > placeholderCount) {
+ return InspectionGadgetsBundle.message("placeholder.count.matches.argument.count.more.problem.descriptor",
+ argumentCount, placeholderCount);
+ }
+ else {
+ return InspectionGadgetsBundle.message("placeholder.count.matches.argument.count.fewer.problem.descriptor",
+ argumentCount, placeholderCount);
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new PlaceholderCountMatchesArgumentCountVisitor();
+ }
+
+ private static class PlaceholderCountMatchesArgumentCountVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String name = methodExpression.getReferenceName();
+ if (!loggingMethodNames.contains(name)) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length == 0) {
+ return;
+ }
+ final PsiExpression firstArgument = arguments[0];
+ final int placeholderCount;
+ final int argumentCount;
+ if (InheritanceUtil.isInheritor(firstArgument.getType(), "org.slf4j.Marker")) {
+ if (arguments.length < 2) {
+ return;
+ }
+ final PsiExpression secondArgument = arguments[1];
+ if (!ExpressionUtils.hasStringType(secondArgument)) {
+ return;
+ }
+ final String value = (String)ExpressionUtils.computeConstantExpression(secondArgument);
+ if (value == null) {
+ return;
+ }
+ placeholderCount = countPlaceholders(value);
+ argumentCount = hasThrowableType(arguments[arguments.length - 1]) ? arguments.length - 3 : arguments.length - 2;
+ }
+ else if (ExpressionUtils.hasStringType(firstArgument)) {
+ final String value = (String)ExpressionUtils.computeConstantExpression(firstArgument);
+ if (value == null) {
+ return;
+ }
+ placeholderCount = countPlaceholders(value);
+ argumentCount = hasThrowableType(arguments[arguments.length - 1]) ? arguments.length - 2 : arguments.length - 1;
+ } else {
+ return;
+ }
+ if (placeholderCount == argumentCount) {
+ return;
+ }
+ registerMethodCallError(expression, argumentCount, placeholderCount);
+ }
+
+ private static boolean hasThrowableType(PsiExpression lastArgument) {
+ return InheritanceUtil.isInheritor(lastArgument.getType(), "java.lang.Throwable");
+ }
+
+ public static int countPlaceholders(String value) {
+ int count = 0;
+ int index = value.indexOf("{}");
+ while (index >= 0) {
+ if (index <= 0 || value.charAt(index - 1) != '\\') {
+ count++;
+ }
+ index = value.indexOf("{}", index + 1);
+ }
+ return count;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PublicMethodWithoutLoggingInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PublicMethodWithoutLoggingInspectionBase.java
new file mode 100644
index 000000000000..0752e8678aa4
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PublicMethodWithoutLoggingInspectionBase.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PropertyUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PublicMethodWithoutLoggingInspectionBase extends BaseInspection {
+ protected final List<String> loggerClassNames = new ArrayList<String>();
+ @SuppressWarnings("PublicField")
+ public String loggerClassName = "java.util.logging.Logger" + ',' +
+ "org.slf4j.Logger" + ',' +
+ "org.apache.commons.logging.Log" + ',' +
+ "org.apache.log4j.Logger";
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "public.method.without.logging.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("public.method.without.logging.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(loggerClassName, loggerClassNames);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ loggerClassName = formatString(loggerClassNames);
+ super.writeSettings(element);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new PublicMethodWithoutLoggingVisitor();
+ }
+
+ private class PublicMethodWithoutLoggingVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ //no drilldown
+ if (method.getNameIdentifier() == null) {
+ return;
+ }
+ if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
+ return;
+ }
+ final PsiCodeBlock body = method.getBody();
+ if (body == null) {
+ return;
+ }
+ if (method.isConstructor()) {
+ return;
+ }
+ if (PropertyUtil.isSimpleGetter(method) || PropertyUtil.isSimpleSetter(method)) {
+ return;
+ }
+ if (containsLoggingCall(body)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+
+ private boolean containsLoggingCall(PsiCodeBlock block) {
+ ContainsLoggingCallVisitor visitor = new ContainsLoggingCallVisitor();
+ block.accept(visitor);
+ return visitor.containsLoggingCall();
+ }
+ }
+
+ private class ContainsLoggingCallVisitor extends JavaRecursiveElementVisitor {
+
+ private boolean containsLoggingCall = false;
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (containsLoggingCall) {
+ return;
+ }
+ super.visitElement(element);
+ }
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ if (containsLoggingCall) {
+ return;
+ }
+ super.visitMethodCallExpression(expression);
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final String containingClassName = containingClass.getQualifiedName();
+ if (containingClassName == null) {
+ return;
+ }
+ if (loggerClassNames.contains(containingClassName)) {
+ containsLoggingCall = true;
+ }
+ }
+
+ public boolean containsLoggingCall() {
+ return containsLoggingCall;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/StringConcatenationArgumentToLogCallInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/StringConcatenationArgumentToLogCallInspection.java
new file mode 100644
index 000000000000..40925af80232
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/StringConcatenationArgumentToLogCallInspection.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.logging;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import com.siyeh.ig.psiutils.TypeUtils;
+import gnu.trove.THashSet;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class StringConcatenationArgumentToLogCallInspection extends BaseInspection {
+
+ @NonNls
+ private static final Set<String> logNames = new THashSet<String>();
+ static {
+ logNames.add("trace");
+ logNames.add("debug");
+ logNames.add("info");
+ logNames.add("warn");
+ logNames.add("error");
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("string.concatenation.argument.to.log.call.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("string.concatenation.argument.to.log.call.problem.descriptor");
+ }
+
+ @Nullable
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ if (!StringConcatenationArgumentToLogCallFix.isAvailable((PsiExpression)infos[0])) {
+ return null;
+ }
+ return new StringConcatenationArgumentToLogCallFix();
+ }
+
+ private static class StringConcatenationArgumentToLogCallFix extends InspectionGadgetsFix {
+
+ public StringConcatenationArgumentToLogCallFix() {}
+
+ @NotNull
+ @Override
+ public String getName() {
+ return InspectionGadgetsBundle.message("string.concatenation.argument.to.log.call.quickfix");
+ }
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiElement grandParent = element.getParent().getParent();
+ if (!(grandParent instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent;
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length == 0) {
+ return;
+ }
+ @NonNls final StringBuilder newMethodCall = new StringBuilder(methodCallExpression.getMethodExpression().getText());
+ newMethodCall.append('(');
+ PsiExpression argument = arguments[0];
+ int usedArguments;
+ if (!(argument instanceof PsiPolyadicExpression)) {
+ if (!TypeUtils.expressionHasTypeOrSubtype(argument, "org.slf4j.Marker") || arguments.length < 2) {
+ return;
+ }
+ newMethodCall.append(argument.getText()).append(',');
+ argument = arguments[1];
+ usedArguments = 2;
+ if (!(argument instanceof PsiPolyadicExpression)) {
+ return;
+ }
+ }
+ else {
+ usedArguments = 1;
+ }
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)argument;
+ final PsiMethod method = methodCallExpression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final String methodName = method.getName();
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final PsiMethod[] methods = containingClass.findMethodsByName(methodName, false);
+ boolean varArgs = false;
+ for (PsiMethod otherMethod : methods) {
+ if (otherMethod.isVarArgs()) {
+ varArgs = true;
+ break;
+ }
+ }
+ final List<PsiExpression> newArguments = new ArrayList();
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ boolean addPlus = false;
+ boolean inStringLiteral = false;
+ for (PsiExpression operand : operands) {
+ if (ExpressionUtils.isEvaluatedAtCompileTime(operand)) {
+ if (ExpressionUtils.hasStringType(operand) && operand instanceof PsiLiteralExpression) {
+ final String text = operand.getText();
+ final int count = StringUtil.getOccurrenceCount(text, "{}");
+ for (int i = 0; i < count && usedArguments + i < arguments.length; i++) {
+ newArguments.add(ParenthesesUtils.stripParentheses((PsiExpression)arguments[i + usedArguments].copy()));
+ }
+ usedArguments += count;
+ if (!inStringLiteral) {
+ if (addPlus) {
+ newMethodCall.append('+');
+ }
+ newMethodCall.append('"');
+ inStringLiteral = true;
+ }
+ newMethodCall.append(text.substring(1, text.length() - 1));
+ }
+ else {
+ if (inStringLiteral) {
+ newMethodCall.append('"');
+ inStringLiteral = false;
+ }
+ if (addPlus) {
+ newMethodCall.append('+');
+ }
+ newMethodCall.append(operand.getText());
+ }
+ }
+ else {
+ newArguments.add(ParenthesesUtils.stripParentheses((PsiExpression)operand.copy()));
+ if (!inStringLiteral) {
+ if (addPlus) {
+ newMethodCall.append('+');
+ }
+ newMethodCall.append('"');
+ inStringLiteral = true;
+ }
+ newMethodCall.append("{}");
+ }
+ addPlus = true;
+ }
+ while (usedArguments < arguments.length) {
+ newArguments.add(arguments[usedArguments++]);
+ }
+ if (inStringLiteral) {
+ newMethodCall.append('"');
+ }
+ if (!varArgs && newArguments.size() > 2) {
+ newMethodCall.append(", new Object[]{");
+ boolean comma = false;
+ for (PsiExpression newArgument : newArguments) {
+ if (comma) {
+ newMethodCall.append(',');
+ }
+ else {
+ comma =true;
+ }
+ if (newArgument != null) {
+ newMethodCall.append(newArgument.getText());
+ }
+ }
+ newMethodCall.append('}');
+ }
+ else {
+ for (PsiExpression newArgument : newArguments) {
+ newMethodCall.append(',');
+ if (newArgument != null) {
+ newMethodCall.append(newArgument.getText());
+ }
+ }
+ }
+ newMethodCall.append(')');
+ replaceExpression(methodCallExpression, newMethodCall.toString());
+ }
+
+ public static boolean isAvailable(PsiExpression expression) {
+ if (!(expression instanceof PsiPolyadicExpression)) {
+ return false;
+ }
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ for (PsiExpression operand : operands) {
+ if (!ExpressionUtils.isEvaluatedAtCompileTime(operand)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new StringConcatenationArgumentToLogCallVisitor();
+ }
+
+ private static class StringConcatenationArgumentToLogCallVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (!logNames.contains(referenceName)) {
+ return;
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null || !"org.slf4j.Logger".equals(containingClass.getQualifiedName())) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length == 0) {
+ return;
+ }
+ PsiExpression argument = arguments[0];
+ if (!ExpressionUtils.hasStringType(argument)) {
+ if (arguments.length < 2) {
+ return;
+ }
+ argument = arguments[1];
+ if (!ExpressionUtils.hasStringType(argument)) {
+ return;
+ }
+ }
+ if (!containsNonConstantConcatenation(argument)) {
+ return;
+ }
+ registerMethodCallError(expression, argument);
+ }
+
+ private static boolean containsNonConstantConcatenation(@Nullable PsiExpression expression) {
+ if (expression instanceof PsiParenthesizedExpression) {
+ final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
+ return containsNonConstantConcatenation(parenthesizedExpression.getExpression());
+ }
+ else if (expression instanceof PsiPolyadicExpression) {
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
+ if (!ExpressionUtils.hasStringType(polyadicExpression)) {
+ return false;
+ }
+ if (!JavaTokenType.PLUS.equals(polyadicExpression.getOperationTokenType())) {
+ return false;
+ }
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ for (PsiExpression operand : operands) {
+ if (!ExpressionUtils.isEvaluatedAtCompileTime(operand)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoCommentInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoCommentInspection.java
new file mode 100644
index 000000000000..9b79d5453758
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoCommentInspection.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.maturity;
+
+import com.intellij.psi.PsiComment;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class TodoCommentInspection extends BaseInspection {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("todo.comment.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("todo.comment.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassWithoutToStringVisitor();
+ }
+
+ private static class ClassWithoutToStringVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitComment(PsiComment comment) {
+ super.visitComment(comment);
+ if (TodoUtil.isTodoComment(comment)) {
+ registerError(comment);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoUtil.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoUtil.java
new file mode 100644
index 000000000000..a75f9185bf3e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/maturity/TodoUtil.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003-2005 Dave Griffith
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.maturity;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.PsiTodoSearchHelper;
+import com.intellij.psi.search.TodoItem;
+
+public class TodoUtil {
+ private TodoUtil() {
+ super();
+ }
+
+ public static boolean isTodoComment(PsiComment comment) {
+ final PsiFile file = comment.getContainingFile();
+ final PsiTodoSearchHelper searchHelper = PsiTodoSearchHelper.SERVICE.getInstance(comment.getProject());
+ final TodoItem[] todoItems = searchHelper.findTodoItems(file);
+ for (final TodoItem todoItem : todoItems) {
+ final TextRange commentTextRange = comment.getTextRange();
+ final TextRange todoTextRange = todoItem.getTextRange();
+ if (commentTextRange.contains(todoTextRange)) {
+ return true;
+ }
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ZeroLengthArrayInitializationInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ZeroLengthArrayInitializationInspectionBase.java
new file mode 100644
index 000000000000..05d57bb072c0
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ZeroLengthArrayInitializationInspectionBase.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.memory;
+
+import com.intellij.psi.PsiArrayInitializerExpression;
+import com.intellij.psi.PsiExpression;
+import com.intellij.psi.PsiNewExpression;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ZeroLengthArrayInitializationInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "ZeroLengthArrayAllocation";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "array.allocation.zero.length.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "array.allocation.zero.length.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ZeroLengthArrayInitializationVisitor();
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ private static class ZeroLengthArrayInitializationVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitNewExpression(
+ @NotNull PsiNewExpression expression) {
+ super.visitNewExpression(expression);
+ if (!ExpressionUtils.isZeroLengthArrayConstruction(expression)) {
+ return;
+ }
+ if (ExpressionUtils.isDeclaredConstant(expression)) {
+ return;
+ }
+ registerError(expression);
+ }
+
+ @Override
+ public void visitArrayInitializerExpression(
+ PsiArrayInitializerExpression expression) {
+ super.visitArrayInitializerExpression(expression);
+ final PsiExpression[] initializers = expression.getInitializers();
+ if (initializers.length > 0) {
+ return;
+ }
+ if (expression.getParent() instanceof PsiNewExpression) {
+ return;
+ }
+ if (ExpressionUtils.isDeclaredConstant(expression)) {
+ return;
+ }
+ registerError(expression);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java
new file mode 100644
index 000000000000..a8b59188e92d
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/CollectionsFieldAccessReplaceableByMethodCallInspection.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2008-2011 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ExpectedTypeUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class CollectionsFieldAccessReplaceableByMethodCallInspection
+ extends BaseInspection {
+
+ @Override
+ @Nls
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "collections.field.access.replaceable.by.method.call.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "collections.field.access.replaceable.by.method.call.problem.descriptor",
+ infos[1]);
+ }
+
+ @Override
+ @Nullable
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ final PsiReferenceExpression expression =
+ (PsiReferenceExpression)infos[0];
+ return new CollectionsFieldAccessReplaceableByMethodCallFix(
+ expression.getReferenceName());
+ }
+
+ private static class CollectionsFieldAccessReplaceableByMethodCallFix
+ extends InspectionGadgetsFix {
+
+ private final String replacementText;
+
+ private CollectionsFieldAccessReplaceableByMethodCallFix(
+ String referenceName) {
+ replacementText = getCollectionsMethodCallText(referenceName);
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "Replace Collections.EMPTY_* with call";
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message(
+ "collections.field.access.replaceable.by.method.call.quickfix",
+ replacementText);
+ }
+
+ @NonNls
+ private static String getCollectionsMethodCallText(
+ PsiReferenceExpression referenceExpression) {
+ final String referenceName = referenceExpression.getReferenceName();
+ final PsiElement parent = referenceExpression.getParent();
+ if (!(parent instanceof PsiExpressionList)) {
+ return getUntypedCollectionsMethodCallText(referenceName);
+ }
+ final PsiType type = ExpectedTypeUtils.findExpectedType(
+ referenceExpression, false);
+ if (!(type instanceof PsiClassType)) {
+ return getUntypedCollectionsMethodCallText(referenceName);
+ }
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiType[] parameterTypes = classType.getParameters();
+ boolean useTypeParameter = false;
+ final String[] canonicalTexts = new String[parameterTypes.length];
+ for (int i = 0, parameterTypesLength = parameterTypes.length;
+ i < parameterTypesLength; i++) {
+ final PsiType parameterType = parameterTypes[i];
+ if (parameterType instanceof PsiWildcardType) {
+ final PsiWildcardType wildcardType =
+ (PsiWildcardType)parameterType;
+ final PsiType bound = wildcardType.getBound();
+ if (bound != null) {
+ if (!bound.equalsToText(
+ CommonClassNames.JAVA_LANG_OBJECT)) {
+ useTypeParameter = true;
+ }
+ canonicalTexts[i] = bound.getCanonicalText();
+ }
+ else {
+ canonicalTexts[i] = CommonClassNames.JAVA_LANG_OBJECT;
+ }
+ }
+ else {
+ if (!parameterType.equalsToText(
+ CommonClassNames.JAVA_LANG_OBJECT)) {
+ useTypeParameter = true;
+ }
+ canonicalTexts[i] = parameterType.getCanonicalText();
+ }
+ }
+ if (useTypeParameter) {
+ return "Collections.<" + StringUtil.join(canonicalTexts, ",") +
+ '>' + getCollectionsMethodCallText(referenceName);
+ }
+ else {
+ return getUntypedCollectionsMethodCallText(referenceName);
+ }
+ }
+
+ @NonNls
+ private static String getUntypedCollectionsMethodCallText(
+ String referenceName) {
+ return "Collections." + getCollectionsMethodCallText(referenceName);
+ }
+
+ @NonNls
+ private static String getCollectionsMethodCallText(
+ @NonNls String referenceName) {
+ if ("EMPTY_LIST".equals(referenceName)) {
+ return "emptyList()";
+ }
+ else if ("EMPTY_MAP".equals(referenceName)) {
+ return "emptyMap()";
+ }
+ else if ("EMPTY_SET".equals(referenceName)) {
+ return "emptySet()";
+ }
+ else {
+ throw new AssertionError("unknown collections field name: " +
+ referenceName);
+ }
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor)
+ throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ if (!(element instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)element;
+ final String newMethodCallText =
+ getCollectionsMethodCallText(referenceExpression);
+ replaceExpression(referenceExpression,
+ "java.util." + newMethodCallText);
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new CollectionsFieldAccessReplaceableByMethodCallVisitor();
+ }
+
+ private static class CollectionsFieldAccessReplaceableByMethodCallVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitReferenceExpression(
+ PsiReferenceExpression expression) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(expression)) {
+ return;
+ }
+ super.visitReferenceExpression(expression);
+ @NonNls final String name = expression.getReferenceName();
+ @NonNls final String replacement;
+ if ("EMPTY_LIST".equals(name)) {
+ replacement = "emptyList()";
+ }
+ else if ("EMPTY_MAP".equals(name)) {
+ replacement = "emptyMap()";
+ }
+ else if ("EMPTY_SET".equals(name)) {
+ replacement = "emptySet()";
+ }
+ else {
+ return;
+ }
+ final PsiElement target = expression.resolve();
+ if (!(target instanceof PsiField)) {
+ return;
+ }
+ final PsiField field = (PsiField)target;
+ final PsiClass containingClass = field.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final String qualifiedName = containingClass.getQualifiedName();
+ if (!CommonClassNames.JAVA_UTIL_COLLECTIONS.equals(qualifiedName)) {
+ return;
+ }
+ registerError(expression, expression, replacement);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspectionBase.java
new file mode 100644
index 000000000000..a12c193d42dc
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EnumerationCanBeIterationInspectionBase.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TypeUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class EnumerationCanBeIterationInspectionBase extends BaseInspection {
+ protected static final int KEEP_NOTHING = 0;
+ protected static final int KEEP_INITIALIZATION = 1;
+ protected static final int KEEP_DECLARATION = 2;
+ @NonNls
+ static final String ITERATOR_TEXT = "iterator()";
+ @NonNls
+ static final String KEY_SET_ITERATOR_TEXT = "keySet().iterator()";
+ @NonNls
+ static final String VALUES_ITERATOR_TEXT = "values().iterator()";
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "enumeration.can.be.iteration.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "enumeration.can.be.iteration.problem.descriptor", infos[0]);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new EnumerationCanBeIterationVisitor();
+ }
+
+ private static class EnumerationCanBeIterationVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(
+ PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression =
+ expression.getMethodExpression();
+ @NonNls final String methodName =
+ methodExpression.getReferenceName();
+ final boolean isElements;
+ if ("elements".equals(methodName)) {
+ isElements = true;
+ }
+ else if ("keys".equals(methodName)) {
+ isElements = false;
+ }
+ else {
+ return;
+ }
+ if (!TypeUtils.expressionHasTypeOrSubtype(expression,
+ "java.util.Enumeration")) {
+ return;
+ }
+ final PsiElement parent = expression.getParent();
+ final PsiVariable variable;
+ if (parent instanceof PsiLocalVariable) {
+ variable = (PsiVariable)parent;
+ }
+ else if (parent instanceof PsiAssignmentExpression) {
+ final PsiAssignmentExpression assignmentExpression =
+ (PsiAssignmentExpression)parent;
+ final PsiExpression lhs = assignmentExpression.getLExpression();
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)lhs;
+ final PsiElement element = referenceExpression.resolve();
+ if (!(element instanceof PsiVariable)) {
+ return;
+ }
+ variable = (PsiVariable)element;
+ }
+ else {
+ return;
+ }
+ final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(
+ expression, PsiMethod.class);
+ if (containingMethod == null) {
+ return;
+ }
+ if (!isEnumerationMethodCalled(variable, containingMethod)) {
+ return;
+ }
+ if (isElements) {
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (InheritanceUtil.isInheritor(containingClass,
+ "java.util.Vector")) {
+ registerMethodCallError(expression, ITERATOR_TEXT);
+ }
+ else if (InheritanceUtil.isInheritor(containingClass,
+ "java.util.Hashtable")) {
+ registerMethodCallError(expression, VALUES_ITERATOR_TEXT);
+ }
+ }
+ else {
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (InheritanceUtil.isInheritor(containingClass,
+ "java.util.Hashtable")) {
+ registerMethodCallError(expression, KEY_SET_ITERATOR_TEXT);
+ }
+ }
+ }
+
+ private static boolean isEnumerationMethodCalled(
+ @NotNull PsiVariable variable, @NotNull PsiElement context) {
+ final EnumerationCanBeIterationVisitor.EnumerationMethodCalledVisitor visitor =
+ new EnumerationCanBeIterationVisitor.EnumerationMethodCalledVisitor(variable);
+ context.accept(visitor);
+ return visitor.isEnumerationMethodCalled();
+ }
+
+ private static class EnumerationMethodCalledVisitor
+ extends JavaRecursiveElementVisitor {
+
+ private final PsiVariable variable;
+ private boolean enumerationMethodCalled = false;
+
+ EnumerationMethodCalledVisitor(@NotNull PsiVariable variable) {
+ this.variable = variable;
+ }
+
+ @Override
+ public void visitMethodCallExpression(
+ PsiMethodCallExpression expression) {
+ if (enumerationMethodCalled) {
+ return;
+ }
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression =
+ expression.getMethodExpression();
+ @NonNls final String methodName =
+ methodExpression.getReferenceName();
+ if (!"hasMoreElements".equals(methodName) &&
+ !"nextElement".equals(methodName)) {
+ return;
+ }
+ final PsiExpression qualifierExpression =
+ methodExpression.getQualifierExpression();
+ if (!(qualifierExpression instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)qualifierExpression;
+ final PsiElement element = referenceExpression.resolve();
+ if (!(element instanceof PsiVariable)) {
+ return;
+ }
+ final PsiVariable variable = (PsiVariable)element;
+ enumerationMethodCalled = this.variable.equals(variable);
+ }
+
+ public boolean isEnumerationMethodCalled() {
+ return enumerationMethodCalled;
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java
new file mode 100644
index 000000000000..f2597139bed2
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.*;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ForCanBeForeachInspectionBase extends BaseInspection {
+ @SuppressWarnings("PublicField")
+ public boolean REPORT_INDEXED_LOOP = true;
+ @SuppressWarnings("PublicField")
+ public boolean ignoreUntypedCollections = false;
+
+ protected static boolean isIndexedListLoopStatement(PsiForStatement forStatement, boolean ignoreUntypedCollections) {
+ final PsiStatement initialization = forStatement.getInitialization();
+ if (!(initialization instanceof PsiDeclarationStatement)) {
+ return false;
+ }
+ final PsiDeclarationStatement declaration = (PsiDeclarationStatement)initialization;
+ final PsiElement[] declaredElements = declaration.getDeclaredElements();
+ final PsiElement secondDeclaredElement;
+ if (declaredElements.length == 1) {
+ secondDeclaredElement = null;
+ }
+ else if (declaredElements.length == 2) {
+ secondDeclaredElement = declaredElements[1];
+ }
+ else {
+ return false;
+ }
+ final PsiElement declaredElement = declaredElements[0];
+ if (!(declaredElement instanceof PsiVariable)) {
+ return false;
+ }
+ final PsiVariable indexVariable = (PsiVariable)declaredElement;
+ final PsiExpression initialValue = indexVariable.getInitializer();
+ if (initialValue == null) {
+ return false;
+ }
+ final Object constant = ExpressionUtils.computeConstantExpression(initialValue);
+ if (!(constant instanceof Number)) {
+ return false;
+ }
+ final Number number = (Number)constant;
+ if (number.intValue() != 0) {
+ return false;
+ }
+ final PsiExpression condition = forStatement.getCondition();
+ final Holder collectionHolder = getCollectionFromSizeComparison(condition, indexVariable, secondDeclaredElement);
+ if (collectionHolder == null) {
+ return false;
+ }
+ final PsiStatement update = forStatement.getUpdate();
+ if (!VariableAccessUtils.variableIsIncremented(indexVariable, update)) {
+ return false;
+ }
+ final PsiStatement body = forStatement.getBody();
+ if (!isIndexVariableOnlyUsedAsListIndex(collectionHolder, indexVariable, body)) {
+ return false;
+ }
+ if (collectionHolder != Holder.DUMMY) {
+ final PsiVariable collection = collectionHolder.getVariable();
+ final PsiClassType collectionType = (PsiClassType)collection.getType();
+ final PsiType[] parameters = collectionType.getParameters();
+ if (ignoreUntypedCollections && parameters.length == 0) {
+ return false;
+ }
+ return !VariableAccessUtils.variableIsAssigned(collection, body);
+ }
+ return true;
+ }
+
+ static boolean isArrayLoopStatement(PsiForStatement forStatement) {
+ final PsiStatement initialization = forStatement.getInitialization();
+ if (!(initialization instanceof PsiDeclarationStatement)) {
+ return false;
+ }
+ final PsiDeclarationStatement declaration = (PsiDeclarationStatement)initialization;
+ final PsiElement[] declaredElements = declaration.getDeclaredElements();
+ final PsiElement secondDeclaredElement;
+ if (declaredElements.length == 1) {
+ secondDeclaredElement = null;
+ }
+ else if (declaredElements.length == 2) {
+ secondDeclaredElement = declaredElements[1];
+ }
+ else {
+ return false;
+ }
+ final PsiElement declaredElement = declaredElements[0];
+ if (!(declaredElement instanceof PsiVariable)) {
+ return false;
+ }
+ final PsiVariable indexVariable = (PsiVariable)declaredElement;
+ final PsiExpression initialValue = indexVariable.getInitializer();
+ if (initialValue == null) {
+ return false;
+ }
+ final Object constant = ExpressionUtils.computeConstantExpression(initialValue);
+ if (!(constant instanceof Integer)) {
+ return false;
+ }
+ final Integer integer = (Integer)constant;
+ if (integer.intValue() != 0) {
+ return false;
+ }
+ final PsiStatement update = forStatement.getUpdate();
+ if (!VariableAccessUtils.variableIsIncremented(indexVariable, update)) {
+ return false;
+ }
+ final PsiExpression condition = forStatement.getCondition();
+ final PsiReferenceExpression arrayReference = getVariableReferenceFromCondition(condition, indexVariable, secondDeclaredElement);
+ if (arrayReference == null) {
+ return false;
+ }
+ if (!(arrayReference.getType() instanceof PsiArrayType)) {
+ return false;
+ }
+ final PsiElement element = arrayReference.resolve();
+ if (!(element instanceof PsiVariable)) {
+ return false;
+ }
+ final PsiVariable arrayVariable = (PsiVariable)element;
+ final PsiStatement body = forStatement.getBody();
+ return body == null ||
+ isIndexVariableOnlyUsedAsIndex(arrayVariable, indexVariable, body) &&
+ !VariableAccessUtils.variableIsAssigned(arrayVariable, body) &&
+ !VariableAccessUtils.arrayContentsAreAssigned(arrayVariable, body);
+ }
+
+ private static boolean isIndexVariableOnlyUsedAsIndex(
+ @NotNull PsiVariable arrayVariable,
+ @NotNull PsiVariable indexVariable,
+ @Nullable PsiStatement body) {
+ if (body == null) {
+ return true;
+ }
+ final VariableOnlyUsedAsIndexVisitor visitor =
+ new VariableOnlyUsedAsIndexVisitor(arrayVariable, indexVariable);
+ body.accept(visitor);
+ return visitor.isIndexVariableUsedOnlyAsIndex();
+ }
+
+ private static boolean isIndexVariableOnlyUsedAsListIndex(
+ Holder collectionHolder, PsiVariable indexVariable,
+ PsiStatement body) {
+ if (body == null) {
+ return true;
+ }
+ final VariableOnlyUsedAsListIndexVisitor visitor =
+ new VariableOnlyUsedAsListIndexVisitor(collectionHolder,
+ indexVariable);
+ body.accept(visitor);
+ return visitor.isIndexVariableUsedOnlyAsIndex();
+ }
+
+ static boolean isCollectionLoopStatement(
+ PsiForStatement forStatement, boolean ignoreUntypedCollections) {
+ final PsiStatement initialization = forStatement.getInitialization();
+ if (!(initialization instanceof PsiDeclarationStatement)) {
+ return false;
+ }
+ final PsiDeclarationStatement declaration =
+ (PsiDeclarationStatement)initialization;
+ final PsiElement[] declaredElements = declaration.getDeclaredElements();
+ if (declaredElements.length != 1) {
+ return false;
+ }
+ final PsiElement declaredElement = declaredElements[0];
+ if (!(declaredElement instanceof PsiVariable)) {
+ return false;
+ }
+ final PsiVariable variable = (PsiVariable)declaredElement;
+ if (!TypeUtils.variableHasTypeOrSubtype(variable,
+ CommonClassNames.JAVA_UTIL_ITERATOR,
+ "java.util.ListIterator")) {
+ return false;
+ }
+ final PsiExpression initialValue = variable.getInitializer();
+ if (initialValue == null) {
+ return false;
+ }
+ if (!(initialValue instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression initialCall =
+ (PsiMethodCallExpression)initialValue;
+ final PsiReferenceExpression initialMethodExpression =
+ initialCall.getMethodExpression();
+ @NonNls final String initialCallName =
+ initialMethodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.ITERATOR.equals(initialCallName) &&
+ !"listIterator".equals(initialCallName)) {
+ return false;
+ }
+ final PsiExpressionList argumentList = initialCall.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 0) {
+ return false;
+ }
+ final PsiExpression qualifier =
+ initialMethodExpression.getQualifierExpression();
+ final PsiClass qualifierClass;
+ if (qualifier == null) {
+ qualifierClass =
+ ClassUtils.getContainingClass(initialMethodExpression);
+ if (ignoreUntypedCollections) {
+ final PsiClassType type = (PsiClassType)variable.getType();
+ final PsiType[] parameters = type.getParameters();
+ if (parameters.length == 0) {
+ return false;
+ }
+ }
+ }
+ else {
+ final PsiType qualifierType = qualifier.getType();
+ if (!(qualifierType instanceof PsiClassType)) {
+ return false;
+ }
+ final PsiClassType classType = (PsiClassType)qualifierType;
+ qualifierClass = classType.resolve();
+ if (ignoreUntypedCollections) {
+ final PsiClassType type = (PsiClassType)variable.getType();
+ final PsiType[] parameters = type.getParameters();
+ final PsiType[] parameters1 = classType.getParameters();
+ if (parameters.length == 0 && parameters1.length == 0) {
+ return false;
+ }
+ }
+ }
+ if (qualifierClass == null) {
+ return false;
+ }
+ if (!InheritanceUtil.isInheritor(qualifierClass,
+ CommonClassNames.JAVA_LANG_ITERABLE) &&
+ !InheritanceUtil.isInheritor(qualifierClass,
+ CommonClassNames.JAVA_UTIL_COLLECTION)) {
+ return false;
+ }
+ final PsiExpression condition = forStatement.getCondition();
+ if (!isHasNext(condition, variable)) {
+ return false;
+ }
+ final PsiStatement update = forStatement.getUpdate();
+ if (update != null && !(update instanceof PsiEmptyStatement)) {
+ return false;
+ }
+ final PsiStatement body = forStatement.getBody();
+ if (body == null) {
+ return false;
+ }
+ if (calculateCallsToIteratorNext(variable, body) != 1) {
+ return false;
+ }
+ if (isIteratorMethodCalled(variable, body)) {
+ return false;
+ }
+ return !VariableAccessUtils.variableIsReturned(variable, body) &&
+ !VariableAccessUtils.variableIsAssigned(variable, body) &&
+ !VariableAccessUtils.variableIsPassedAsMethodArgument(variable, body);
+ }
+
+ private static int calculateCallsToIteratorNext(PsiVariable iterator,
+ PsiStatement body) {
+ if (body == null) {
+ return 0;
+ }
+ final NumCallsToIteratorNextVisitor visitor =
+ new NumCallsToIteratorNextVisitor(iterator);
+ body.accept(visitor);
+ return visitor.getNumCallsToIteratorNext();
+ }
+
+ private static boolean isIteratorMethodCalled(PsiVariable iterator,
+ PsiStatement body) {
+ final IteratorMethodCallVisitor visitor =
+ new IteratorMethodCallVisitor(iterator);
+ body.accept(visitor);
+ return visitor.isMethodCalled();
+ }
+
+ private static boolean isHasNext(PsiExpression condition,
+ PsiVariable iterator) {
+ if (!(condition instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression call =
+ (PsiMethodCallExpression)condition;
+ final PsiExpressionList argumentList = call.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 0) {
+ return false;
+ }
+ final PsiReferenceExpression methodExpression =
+ call.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.HAS_NEXT.equals(methodName)) {
+ return false;
+ }
+ final PsiExpression qualifier =
+ methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return true;
+ }
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ return iterator.equals(target);
+ }
+
+ @Nullable
+ private static PsiReferenceExpression getVariableReferenceFromCondition(PsiExpression condition,
+ PsiVariable variable,
+ PsiElement secondDeclaredElement) {
+ condition = ParenthesesUtils.stripParentheses(condition);
+ if (!(condition instanceof PsiBinaryExpression)) {
+ return null;
+ }
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)condition;
+ final IElementType tokenType = binaryExpression.getOperationTokenType();
+ final PsiExpression lhs = ParenthesesUtils.stripParentheses(binaryExpression.getLOperand());
+ final PsiExpression rhs = ParenthesesUtils.stripParentheses(binaryExpression.getROperand());
+ if (rhs == null) {
+ return null;
+ }
+ PsiReferenceExpression referenceExpression;
+ if (tokenType.equals(JavaTokenType.LT)) {
+ if (!VariableAccessUtils.evaluatesToVariable(lhs, variable) || !(rhs instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ referenceExpression = (PsiReferenceExpression)rhs;
+ }
+ else if (tokenType.equals(JavaTokenType.GT)) {
+ if (!VariableAccessUtils.evaluatesToVariable(rhs, variable) || !(lhs instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ referenceExpression = (PsiReferenceExpression)lhs;
+ }
+ else {
+ return null;
+ }
+ if (!expressionIsArrayLengthLookup(referenceExpression)) {
+ final PsiElement target = referenceExpression.resolve();
+ if (secondDeclaredElement != null && !secondDeclaredElement.equals(target)) {
+ return null;
+ }
+ if (target instanceof PsiVariable) {
+ final PsiVariable maxVariable = (PsiVariable)target;
+ final PsiCodeBlock context = PsiTreeUtil.getParentOfType(maxVariable, PsiCodeBlock.class);
+ if (context == null) {
+ return null;
+ }
+ if (VariableAccessUtils.variableIsAssigned(maxVariable, context)) {
+ return null;
+ }
+ final PsiExpression expression = ParenthesesUtils.stripParentheses(maxVariable.getInitializer());
+ if (!(expression instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ referenceExpression = (PsiReferenceExpression)expression;
+ if (!expressionIsArrayLengthLookup(referenceExpression)) {
+ return null;
+ }
+ }
+ }
+ else {
+ if (secondDeclaredElement != null) {
+ return null;
+ }
+ }
+ final PsiExpression qualifierExpression = referenceExpression.getQualifierExpression();
+ if (qualifierExpression instanceof PsiReferenceExpression) {
+ return (PsiReferenceExpression)qualifierExpression;
+ }
+ else if (qualifierExpression instanceof PsiThisExpression ||
+ qualifierExpression instanceof PsiSuperExpression ||
+ qualifierExpression == null) {
+ return referenceExpression;
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Nullable
+ private static Holder getCollectionFromSizeComparison(PsiExpression condition, PsiVariable variable, PsiElement secondDeclaredElement) {
+ condition = ParenthesesUtils.stripParentheses(condition);
+ if (!(condition instanceof PsiBinaryExpression)) {
+ return null;
+ }
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)condition;
+ final IElementType tokenType = binaryExpression.getOperationTokenType();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ if (tokenType.equals(JavaTokenType.LT)) {
+ if (!VariableAccessUtils.evaluatesToVariable(lhs, variable)) {
+ return null;
+ }
+ return getCollectionFromListMethodCall(rhs, HardcodedMethodConstants.SIZE, secondDeclaredElement);
+ }
+ else if (tokenType.equals(JavaTokenType.GT)) {
+ if (!VariableAccessUtils.evaluatesToVariable(rhs, variable)) {
+ return null;
+ }
+ return getCollectionFromListMethodCall(lhs, HardcodedMethodConstants.SIZE, secondDeclaredElement);
+ }
+ return null;
+ }
+
+ static boolean expressionIsListGetLookup(PsiExpression expression) {
+ expression = ParenthesesUtils.stripParentheses(expression);
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression reference =
+ (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression =
+ reference.getMethodExpression();
+ final PsiElement resolved = methodExpression.resolve();
+ if (!(resolved instanceof PsiMethod)) {
+ return false;
+ }
+ final PsiMethod method = (PsiMethod)resolved;
+ if (!HardcodedMethodConstants.GET.equals(method.getName())) {
+ return false;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ return InheritanceUtil.isInheritor(aClass,
+ CommonClassNames.JAVA_UTIL_LIST);
+ }
+
+ @Nullable
+ private static Holder getCollectionFromListMethodCall(PsiExpression expression, String methodName, PsiElement secondDeclaredElement) {
+ expression = ParenthesesUtils.stripParentheses(expression);
+ if (expression instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression;
+ final PsiElement target = referenceExpression.resolve();
+ if (secondDeclaredElement != null && !secondDeclaredElement.equals(target)) {
+ return null;
+ }
+ if (!(target instanceof PsiVariable)) {
+ return null;
+ }
+ final PsiVariable variable = (PsiVariable)target;
+ final PsiCodeBlock context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
+ if (context == null) {
+ return null;
+ }
+ if (VariableAccessUtils.variableIsAssigned(variable, context)) {
+ return null;
+ }
+ expression = ParenthesesUtils.stripParentheses(variable.getInitializer());
+ }
+ else if (secondDeclaredElement != null) {
+ return null;
+ }
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return null;
+ }
+ final PsiMethodCallExpression methodCallExpression =
+ (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression =
+ methodCallExpression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (!methodName.equals(referenceName)) {
+ return null;
+ }
+ final PsiMethod method = methodCallExpression.resolveMethod();
+ if (method == null) {
+ return null;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (!InheritanceUtil.isInheritor(containingClass,
+ CommonClassNames.JAVA_UTIL_LIST)) {
+ return null;
+ }
+ final PsiExpression qualifierExpression =
+ ParenthesesUtils.stripParentheses(
+ methodExpression.getQualifierExpression());
+ if (qualifierExpression == null ||
+ qualifierExpression instanceof PsiThisExpression ||
+ qualifierExpression instanceof PsiSuperExpression) {
+ return Holder.DUMMY;
+ }
+ if (!(qualifierExpression instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)qualifierExpression;
+ final PsiElement target = referenceExpression.resolve();
+ if (!(target instanceof PsiVariable)) {
+ return null;
+ }
+ final PsiVariable variable = (PsiVariable)target;
+ return new Holder(variable);
+ }
+
+ private static boolean expressionIsArrayLengthLookup(PsiExpression expression) {
+ expression = ParenthesesUtils.stripParentheses(expression);
+ if (!(expression instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression reference =
+ (PsiReferenceExpression)expression;
+ final String referenceName = reference.getReferenceName();
+ if (!HardcodedMethodConstants.LENGTH.equals(referenceName)) {
+ return false;
+ }
+ final PsiExpression qualifier = reference.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiType type = qualifier.getType();
+ return type != null && type.getArrayDimensions() > 0;
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "ForLoopReplaceableByForEach";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "for.can.be.foreach.display.name");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "for.can.be.foreach.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ForCanBeForeachVisitor();
+ }
+
+ private static class NumCallsToIteratorNextVisitor
+ extends JavaRecursiveElementVisitor {
+
+ private int numCallsToIteratorNext = 0;
+ private final PsiVariable iterator;
+
+ NumCallsToIteratorNextVisitor(PsiVariable iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public void visitMethodCallExpression(
+ @NotNull PsiMethodCallExpression callExpression) {
+ super.visitMethodCallExpression(callExpression);
+ final PsiReferenceExpression methodExpression =
+ callExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.NEXT.equals(methodName)) {
+ return;
+ }
+ final PsiExpression qualifier =
+ methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return;
+ }
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (!iterator.equals(target)) {
+ return;
+ }
+ numCallsToIteratorNext++;
+ }
+
+ public int getNumCallsToIteratorNext() {
+ return numCallsToIteratorNext;
+ }
+ }
+
+ private static class IteratorMethodCallVisitor
+ extends JavaRecursiveElementVisitor {
+
+ private boolean methodCalled = false;
+ private final PsiVariable iterator;
+
+ IteratorMethodCallVisitor(PsiVariable iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (!methodCalled) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitMethodCallExpression(
+ @NotNull PsiMethodCallExpression expression) {
+ if (methodCalled) {
+ return;
+ }
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression =
+ expression.getMethodExpression();
+ final String name = methodExpression.getReferenceName();
+ if (HardcodedMethodConstants.NEXT.equals(name)) {
+ return;
+ }
+ final PsiExpression qualifier =
+ methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (iterator.equals(target)) {
+ methodCalled = true;
+ }
+ }
+
+ public boolean isMethodCalled() {
+ return methodCalled;
+ }
+ }
+
+ private static class VariableOnlyUsedAsIndexVisitor
+ extends JavaRecursiveElementVisitor {
+
+ private boolean indexVariableUsedOnlyAsIndex = true;
+ private final PsiVariable arrayVariable;
+ private final PsiVariable indexVariable;
+
+ VariableOnlyUsedAsIndexVisitor(PsiVariable arrayVariable,
+ PsiVariable indexVariable) {
+ this.arrayVariable = arrayVariable;
+ this.indexVariable = indexVariable;
+ }
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (indexVariableUsedOnlyAsIndex) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitReferenceExpression(
+ @NotNull PsiReferenceExpression reference) {
+ if (!indexVariableUsedOnlyAsIndex) {
+ return;
+ }
+ super.visitReferenceExpression(reference);
+ final PsiElement element = reference.resolve();
+ if (!indexVariable.equals(element)) {
+ return;
+ }
+ final PsiElement parent = reference.getParent();
+ if (!(parent instanceof PsiArrayAccessExpression)) {
+ indexVariableUsedOnlyAsIndex = false;
+ return;
+ }
+ final PsiArrayAccessExpression arrayAccessExpression =
+ (PsiArrayAccessExpression)parent;
+ final PsiExpression arrayExpression =
+ arrayAccessExpression.getArrayExpression();
+ if (!(arrayExpression instanceof PsiReferenceExpression)) {
+ indexVariableUsedOnlyAsIndex = false;
+ return;
+ }
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)arrayExpression;
+ final PsiExpression qualifier =
+ referenceExpression.getQualifierExpression();
+ if (qualifier != null && !(qualifier instanceof PsiThisExpression)
+ && !(qualifier instanceof PsiSuperExpression)) {
+ indexVariableUsedOnlyAsIndex = false;
+ return;
+ }
+ final PsiElement target = referenceExpression.resolve();
+ if (!arrayVariable.equals(target)) {
+ indexVariableUsedOnlyAsIndex = false;
+ return;
+ }
+ final PsiElement arrayExpressionContext =
+ arrayAccessExpression.getParent();
+ if (arrayExpressionContext instanceof PsiAssignmentExpression) {
+ final PsiAssignmentExpression assignment =
+ (PsiAssignmentExpression)arrayExpressionContext;
+ final PsiExpression lhs = assignment.getLExpression();
+ if (lhs.equals(arrayAccessExpression)) {
+ indexVariableUsedOnlyAsIndex = false;
+ }
+ }
+ }
+
+ public boolean isIndexVariableUsedOnlyAsIndex() {
+ return indexVariableUsedOnlyAsIndex;
+ }
+ }
+
+ private static class VariableOnlyUsedAsListIndexVisitor
+ extends JavaRecursiveElementVisitor {
+
+ private boolean indexVariableUsedOnlyAsIndex = true;
+ private final PsiVariable indexVariable;
+ private final Holder collection;
+
+ VariableOnlyUsedAsListIndexVisitor(
+ @NotNull Holder collection,
+ @NotNull PsiVariable indexVariable) {
+ this.collection = collection;
+ this.indexVariable = indexVariable;
+ }
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (indexVariableUsedOnlyAsIndex) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitReferenceExpression(
+ @NotNull PsiReferenceExpression reference) {
+ if (!indexVariableUsedOnlyAsIndex) {
+ return;
+ }
+ super.visitReferenceExpression(reference);
+ final PsiElement element = reference.resolve();
+ if (indexVariable.equals(element)) {
+ if (!isListIndexExpression(reference)) {
+ indexVariableUsedOnlyAsIndex = false;
+ }
+ }
+ else if (collection == Holder.DUMMY) {
+ if (isListNonGetMethodCall(reference)) {
+ indexVariableUsedOnlyAsIndex = false;
+ }
+ }
+ else if (collection.getVariable().equals(element) &&
+ !isListReferenceInIndexExpression(reference)) {
+ indexVariableUsedOnlyAsIndex = false;
+ }
+ }
+
+ public boolean isIndexVariableUsedOnlyAsIndex() {
+ return indexVariableUsedOnlyAsIndex;
+ }
+
+ private boolean isListNonGetMethodCall(
+ PsiReferenceExpression reference) {
+ final PsiElement parent = reference.getParent();
+ if (!(parent instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression =
+ (PsiMethodCallExpression)parent;
+ final PsiMethod method =
+ methodCallExpression.resolveMethod();
+ if (method == null) {
+ return false;
+ }
+ final PsiClass parentClass = PsiTreeUtil.getParentOfType(
+ methodCallExpression, PsiClass.class);
+ final PsiClass containingClass = method.getContainingClass();
+ if (!InheritanceUtil.isInheritorOrSelf(parentClass,
+ containingClass, true)) {
+ return false;
+ }
+ return !isListGetExpression(methodCallExpression);
+ }
+
+ private boolean isListIndexExpression(PsiReferenceExpression reference) {
+ final PsiElement referenceParent = reference.getParent();
+ if (!(referenceParent instanceof PsiExpressionList)) {
+ return false;
+ }
+ final PsiExpressionList expressionList =
+ (PsiExpressionList)referenceParent;
+ final PsiElement parent = expressionList.getParent();
+ if (!(parent instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression =
+ (PsiMethodCallExpression)parent;
+ return isListGetExpression(methodCallExpression);
+ }
+
+ private boolean isListReferenceInIndexExpression(
+ PsiReferenceExpression reference) {
+ final PsiElement parent = reference.getParent();
+ if (!(parent instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiElement grandParent = parent.getParent();
+ if (!(grandParent instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression =
+ (PsiMethodCallExpression)grandParent;
+ final PsiElement greatGrandParent =
+ methodCallExpression.getParent();
+ if (greatGrandParent instanceof PsiExpressionStatement) {
+ return false;
+ }
+ return isListGetExpression(methodCallExpression);
+ }
+
+ private boolean isListGetExpression(
+ PsiMethodCallExpression methodCallExpression) {
+ if (methodCallExpression == null) {
+ return false;
+ }
+ final PsiReferenceExpression methodExpression =
+ methodCallExpression.getMethodExpression();
+ final PsiExpression qualifierExpression =
+ methodExpression.getQualifierExpression();
+ if (!(qualifierExpression instanceof PsiReferenceExpression)) {
+ if (collection == Holder.DUMMY &&
+ (qualifierExpression == null ||
+ qualifierExpression instanceof PsiThisExpression ||
+ qualifierExpression instanceof PsiSuperExpression)) {
+ return expressionIsListGetLookup(methodCallExpression);
+ }
+ return false;
+ }
+ final PsiReferenceExpression reference =
+ (PsiReferenceExpression)qualifierExpression;
+ final PsiExpression qualifier = reference.getQualifierExpression();
+ if (qualifier != null && !(qualifier instanceof PsiThisExpression)
+ && !(qualifier instanceof PsiSuperExpression)) {
+ return false;
+ }
+ final PsiElement target = reference.resolve();
+ if (collection == Holder.DUMMY ||
+ !collection.getVariable().equals(target)) {
+ return false;
+ }
+ return expressionIsListGetLookup(methodCallExpression);
+ }
+ }
+
+ private static class Holder {
+
+ public static final Holder DUMMY = new Holder();
+
+ private final PsiVariable variable;
+
+ public Holder(@NotNull PsiVariable variable) {
+ this.variable = variable;
+ }
+
+ private Holder() {
+ variable = null;
+ }
+
+ public PsiVariable getVariable() {
+ return variable;
+ }
+ }
+
+ private class ForCanBeForeachVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitForStatement(
+ @NotNull PsiForStatement forStatement) {
+ super.visitForStatement(forStatement);
+ if (!PsiUtil.isLanguageLevel5OrHigher(forStatement)) {
+ return;
+ }
+ if (isArrayLoopStatement(forStatement)
+ || isCollectionLoopStatement(forStatement,
+ ignoreUntypedCollections)
+ || (REPORT_INDEXED_LOOP &&
+ isIndexedListLoopStatement(forStatement,
+ ignoreUntypedCollections))) {
+ registerStatementError(forStatement);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java
new file mode 100644
index 000000000000..08ea82310e0e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2011-2013 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInsight.NullableNotNullManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.ui.DocumentAdapter;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ControlFlowUtils;
+import com.siyeh.ig.psiutils.EquivalenceChecker;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import com.siyeh.ig.psiutils.SwitchUtils;
+import com.siyeh.ig.psiutils.SwitchUtils.IfStatementBranch;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.Document;
+import java.awt.*;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class IfCanBeSwitchInspection extends BaseInspection {
+
+ @SuppressWarnings({"PublicField"})
+ public int minimumBranches = 3;
+
+ @SuppressWarnings({"PublicField"})
+ public boolean suggestIntSwitches = false;
+
+ @SuppressWarnings({"PublicField"})
+ public boolean suggestEnumSwitches = false;
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("if.can.be.switch.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("if.can.be.switch.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new IfCanBeSwitchFix(minimumBranches);
+ }
+
+ @Override
+ public JComponent createOptionsPanel() {
+ final JPanel panel = new JPanel(new GridBagLayout());
+ final JLabel label = new JLabel(InspectionGadgetsBundle.message("if.can.be.switch.minimum.branch.option"));
+ final NumberFormat formatter = NumberFormat.getIntegerInstance();
+ formatter.setParseIntegerOnly(true);
+ final JFormattedTextField valueField = new JFormattedTextField(formatter);
+ valueField.setValue(Integer.valueOf(minimumBranches));
+ valueField.setColumns(2);
+ final Document document = valueField.getDocument();
+ document.addDocumentListener(new DocumentAdapter() {
+ @Override
+ public void textChanged(DocumentEvent e) {
+ try {
+ valueField.commitEdit();
+ minimumBranches =
+ ((Number)valueField.getValue()).intValue();
+ }
+ catch (ParseException e1) {
+ // No luck this time
+ }
+ }
+ });
+ final GridBagConstraints constraints = new GridBagConstraints();
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.insets.bottom = 4;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.BASELINE_LEADING;
+ constraints.fill = GridBagConstraints.NONE;
+ constraints.insets.right = 10;
+ panel.add(label, constraints);
+ constraints.gridx = 1;
+ constraints.gridy = 0;
+ constraints.weightx = 1.0;
+ constraints.insets.right = 0;
+ panel.add(valueField, constraints);
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.gridwidth = 2;
+ final JCheckBox checkBox1 = new JCheckBox(InspectionGadgetsBundle.message("if.can.be.switch.int.option"), suggestIntSwitches);
+ final ButtonModel model1 = checkBox1.getModel();
+ model1.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ suggestIntSwitches = model1.isSelected();
+ }
+ });
+ panel.add(checkBox1, constraints);
+ constraints.gridy = 2;
+ constraints.weighty = 1.0;
+ final JCheckBox checkBox2 = new JCheckBox(InspectionGadgetsBundle.message("if.can.be.switch.enum.option"), suggestEnumSwitches);
+ final ButtonModel model2 = checkBox2.getModel();
+ model2.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ suggestEnumSwitches = model2.isSelected();
+ }
+ });
+ panel.add(checkBox2, constraints);
+ return panel;
+ }
+
+ private static class IfCanBeSwitchFix extends InspectionGadgetsFix {
+ private final int myMinimumBranches;
+
+ public IfCanBeSwitchFix(int minimumBranches) {
+ myMinimumBranches = minimumBranches;
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("if.can.be.switch.quickfix");
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement().getParent();
+ if (!(element instanceof PsiIfStatement)) {
+ return;
+ }
+ PsiIfStatement ifStatement = (PsiIfStatement)element;
+ boolean breaksNeedRelabeled = false;
+ PsiStatement breakTarget = null;
+ String labelString = "";
+ if (ControlFlowUtils.statementContainsNakedBreak(ifStatement)) {
+ breakTarget = PsiTreeUtil.getParentOfType(ifStatement, PsiLoopStatement.class, PsiSwitchStatement.class);
+ if (breakTarget != null) {
+ final PsiElement parent = breakTarget.getParent();
+ if (parent instanceof PsiLabeledStatement) {
+ final PsiLabeledStatement labeledStatement = (PsiLabeledStatement)parent;
+ labelString = labeledStatement.getLabelIdentifier().getText();
+ breakTarget = labeledStatement;
+ breaksNeedRelabeled = true;
+ }
+ else {
+ labelString = SwitchUtils.findUniqueLabelName(ifStatement, "label");
+ breaksNeedRelabeled = true;
+ }
+ }
+ }
+ final PsiIfStatement statementToReplace = ifStatement;
+ final PsiExpression switchExpression = SwitchUtils.getSwitchExpression(ifStatement, myMinimumBranches);
+ if (switchExpression == null) {
+ return;
+ }
+ final List<IfStatementBranch> branches = new ArrayList<IfStatementBranch>(20);
+ while (true) {
+ final PsiExpression condition = ifStatement.getCondition();
+ final PsiStatement thenBranch = ifStatement.getThenBranch();
+ final IfStatementBranch ifBranch = new IfStatementBranch(thenBranch, false);
+ extractCaseExpressions(condition, switchExpression, ifBranch);
+ if (!branches.isEmpty()) {
+ extractIfComments(ifStatement, ifBranch);
+ }
+ extractStatementComments(thenBranch, ifBranch);
+ branches.add(ifBranch);
+ final PsiStatement elseBranch = ifStatement.getElseBranch();
+ if (elseBranch instanceof PsiIfStatement) {
+ ifStatement = (PsiIfStatement)elseBranch;
+ }
+ else if (elseBranch == null) {
+ break;
+ }
+ else {
+ final IfStatementBranch elseIfBranch = new IfStatementBranch(elseBranch, true);
+ final PsiKeyword elseKeyword = ifStatement.getElseElement();
+ extractIfComments(elseKeyword, elseIfBranch);
+ extractStatementComments(elseBranch, elseIfBranch);
+ branches.add(elseIfBranch);
+ break;
+ }
+ }
+
+ @NonNls final StringBuilder switchStatementText = new StringBuilder();
+ switchStatementText.append("switch(").append(switchExpression.getText()).append("){");
+ final PsiType type = switchExpression.getType();
+ final boolean castToInt = type != null && type.equalsToText(CommonClassNames.JAVA_LANG_INTEGER);
+ for (IfStatementBranch branch : branches) {
+ boolean hasConflicts = false;
+ for (IfStatementBranch testBranch : branches) {
+ if (branch == testBranch) {
+ continue;
+ }
+ if (branch.topLevelDeclarationsConflictWith(testBranch)) {
+ hasConflicts = true;
+ }
+ }
+ dumpBranch(branch, castToInt, hasConflicts, breaksNeedRelabeled, labelString, switchStatementText);
+ }
+ switchStatementText.append('}');
+ final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(element.getProject());
+ final PsiElementFactory factory = psiFacade.getElementFactory();
+ if (breaksNeedRelabeled) {
+ final StringBuilder out = new StringBuilder();
+ if (!(breakTarget instanceof PsiLabeledStatement)) {
+ out.append(labelString).append(':');
+ }
+ termReplace(breakTarget, statementToReplace, switchStatementText, out);
+ final String newStatementText = out.toString();
+ final PsiStatement newStatement = factory.createStatementFromText(newStatementText, element);
+ breakTarget.replace(newStatement);
+ }
+ else {
+ final PsiStatement newStatement = factory.createStatementFromText(switchStatementText.toString(), element);
+ statementToReplace.replace(newStatement);
+ }
+ }
+
+ @Nullable
+ public static <T extends PsiElement> T getPrevSiblingOfType(@Nullable PsiElement element, @NotNull Class<T> aClass,
+ @NotNull Class<? extends PsiElement>... stopAt) {
+ if (element == null) {
+ return null;
+ }
+ PsiElement sibling = element.getPrevSibling();
+ while (sibling != null && !aClass.isInstance(sibling)) {
+ for (Class<? extends PsiElement> stopClass : stopAt) {
+ if (stopClass.isInstance(sibling)) {
+ return null;
+ }
+ }
+ sibling = sibling.getPrevSibling();
+ }
+ return (T)sibling;
+ }
+
+ private static void extractIfComments(PsiElement element, IfStatementBranch out) {
+ PsiComment comment = getPrevSiblingOfType(element, PsiComment.class, PsiStatement.class);
+ while (comment != null) {
+ final PsiElement sibling = comment.getPrevSibling();
+ final String commentText;
+ if (sibling instanceof PsiWhiteSpace) {
+ final String whiteSpaceText = sibling.getText();
+ if (whiteSpaceText.startsWith("\n")) {
+ commentText = whiteSpaceText.substring(1) + comment.getText();
+ }
+ else {
+ commentText = comment.getText();
+ }
+ }
+ else {
+ commentText = comment.getText();
+ }
+ out.addComment(commentText);
+ comment = getPrevSiblingOfType(comment, PsiComment.class, PsiStatement.class);
+ }
+ }
+
+ private static void extractStatementComments(PsiElement element, IfStatementBranch out) {
+ PsiComment comment = getPrevSiblingOfType(element, PsiComment.class, PsiStatement.class, PsiKeyword.class);
+ while (comment != null) {
+ final PsiElement sibling = comment.getPrevSibling();
+ final String commentText;
+ if (sibling instanceof PsiWhiteSpace) {
+ final String whiteSpaceText = sibling.getText();
+ if (whiteSpaceText.startsWith("\n")) {
+ commentText = whiteSpaceText.substring(1) + comment.getText();
+ }
+ else {
+ commentText = comment.getText();
+ }
+ }
+ else {
+ commentText = comment.getText();
+ }
+ out.addStatementComment(commentText);
+ comment = getPrevSiblingOfType(comment, PsiComment.class, PsiStatement.class, PsiKeyword.class);
+ }
+ }
+
+ private static void termReplace(PsiElement target, PsiElement replace, StringBuilder stringToReplaceWith, StringBuilder out) {
+ if (target.equals(replace)) {
+ out.append(stringToReplaceWith);
+ }
+ else if (target.getChildren().length == 0) {
+ out.append(target.getText());
+ }
+ else {
+ final PsiElement[] children = target.getChildren();
+ for (final PsiElement child : children) {
+ termReplace(child, replace, stringToReplaceWith, out);
+ }
+ }
+ }
+
+ private static void extractCaseExpressions(PsiExpression expression, PsiExpression switchExpression, IfStatementBranch branch) {
+ if (expression instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ final PsiExpression argument = arguments[0];
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ if (EquivalenceChecker.expressionsAreEquivalent(switchExpression, argument)) {
+ branch.addCaseExpression(qualifierExpression);
+ }
+ else {
+ branch.addCaseExpression(argument);
+ }
+ }
+ else if (expression instanceof PsiPolyadicExpression) {
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ final IElementType tokenType = polyadicExpression.getOperationTokenType();
+ if (JavaTokenType.OROR.equals(tokenType)) {
+ for (PsiExpression operand : operands) {
+ extractCaseExpressions(operand, switchExpression, branch);
+ }
+ }
+ else if (operands.length == 2) {
+ final PsiExpression lhs = operands[0];
+ final PsiExpression rhs = operands[1];
+ if (EquivalenceChecker.expressionsAreEquivalent(switchExpression, rhs)) {
+ branch.addCaseExpression(lhs);
+ }
+ else {
+ branch.addCaseExpression(rhs);
+ }
+ }
+ }
+ else if (expression instanceof PsiParenthesizedExpression) {
+ final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
+ final PsiExpression contents = parenthesizedExpression.getExpression();
+ extractCaseExpressions(contents, switchExpression, branch);
+ }
+ }
+
+ private static void dumpBranch(IfStatementBranch branch, boolean castToInt, boolean wrap, boolean renameBreaks, String breakLabelName,
+ @NonNls StringBuilder switchStatementText) {
+ dumpComments(branch.getComments(), switchStatementText);
+ if (branch.isElse()) {
+ switchStatementText.append("default: ");
+ }
+ else {
+ for (PsiExpression caseExpression : branch.getCaseExpressions()) {
+ switchStatementText.append("case ").append(getCaseLabelText(caseExpression, castToInt)).append(": ");
+ }
+ }
+ dumpComments(branch.getStatementComments(), switchStatementText);
+ dumpBody(branch.getStatement(), wrap, renameBreaks, breakLabelName, switchStatementText);
+ }
+
+ @NonNls
+ private static String getCaseLabelText(PsiExpression expression, boolean castToInt) {
+ if (expression instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression;
+ final PsiElement target = referenceExpression.resolve();
+ if (target instanceof PsiEnumConstant) {
+ final PsiEnumConstant enumConstant = (PsiEnumConstant)target;
+ return enumConstant.getName();
+ }
+ }
+ if (castToInt) {
+ final PsiType type = expression.getType();
+ if (!PsiType.INT.equals(type)) {
+ /*
+ because
+ Integer a = 1;
+ switch (a) {
+ case (byte)7:
+ }
+ does not compile with javac (but does with Eclipse)
+ */
+ return "(int)" + expression.getText();
+ }
+ }
+ return expression.getText();
+ }
+
+ private static void dumpComments(List<String> comments, StringBuilder switchStatementText) {
+ if (comments.isEmpty()) {
+ return;
+ }
+ switchStatementText.append('\n');
+ for (String comment : comments) {
+ switchStatementText.append(comment).append('\n');
+ }
+ }
+
+ private static void dumpBody(PsiStatement bodyStatement, boolean wrap, boolean renameBreaks, String breakLabelName,
+ @NonNls StringBuilder switchStatementText) {
+ if (wrap) {
+ switchStatementText.append('{');
+ }
+ if (bodyStatement instanceof PsiBlockStatement) {
+ final PsiCodeBlock codeBlock = ((PsiBlockStatement)bodyStatement).getCodeBlock();
+ final PsiElement[] children = codeBlock.getChildren();
+ //skip the first and last members, to unwrap the block
+ for (int i = 1; i < children.length - 1; i++) {
+ final PsiElement child = children[i];
+ appendElement(child, renameBreaks, breakLabelName, switchStatementText);
+ }
+ }
+ else {
+ appendElement(bodyStatement, renameBreaks, breakLabelName, switchStatementText);
+ }
+ if (ControlFlowUtils.statementMayCompleteNormally(bodyStatement)) {
+ switchStatementText.append("break;");
+ }
+ if (wrap) {
+ switchStatementText.append('}');
+ }
+ }
+
+ private static void appendElement(PsiElement element, boolean renameBreakElements, String breakLabelString,
+ @NonNls StringBuilder switchStatementText) {
+ final String text = element.getText();
+ if (!renameBreakElements) {
+ switchStatementText.append(text);
+ }
+ else if (element instanceof PsiBreakStatement) {
+ final PsiBreakStatement breakStatement = (PsiBreakStatement)element;
+ final PsiIdentifier identifier = breakStatement.getLabelIdentifier();
+ if (identifier == null) {
+ switchStatementText.append("break ").append(breakLabelString).append(';');
+ }
+ else {
+ switchStatementText.append(text);
+ }
+ }
+ else if (element instanceof PsiBlockStatement || element instanceof PsiCodeBlock || element instanceof PsiIfStatement) {
+ final PsiElement[] children = element.getChildren();
+ for (final PsiElement child : children) {
+ appendElement(child, renameBreakElements, breakLabelString, switchStatementText);
+ }
+ }
+ else {
+ switchStatementText.append(text);
+ }
+ final PsiElement lastChild = element.getLastChild();
+ if (isEndOfLineComment(lastChild)) {
+ switchStatementText.append('\n');
+ }
+ }
+
+ private static boolean isEndOfLineComment(PsiElement element) {
+ if (!(element instanceof PsiComment)) {
+ return false;
+ }
+ final PsiComment comment = (PsiComment)element;
+ final IElementType tokenType = comment.getTokenType();
+ return JavaTokenType.END_OF_LINE_COMMENT.equals(tokenType);
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new IfCanBeSwitchVisitor();
+ }
+
+ private class IfCanBeSwitchVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitIfStatement(PsiIfStatement statement) {
+ super.visitIfStatement(statement);
+ final PsiElement parent = statement.getParent();
+ if (parent instanceof PsiIfStatement) {
+ return;
+ }
+ final PsiExpression switchExpression = SwitchUtils.getSwitchExpression(statement, minimumBranches);
+ if (switchExpression == null) {
+ return;
+ }
+ final PsiExpression unwrappedExpression = ParenthesesUtils.stripParentheses(switchExpression);
+ if (unwrappedExpression instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)unwrappedExpression;
+ final PsiElement target = referenceExpression.resolve();
+ if (target instanceof PsiModifierListOwner && NullableNotNullManager.isNullable((PsiModifierListOwner)target)) {
+ return;
+ }
+ }
+ final PsiType type = switchExpression.getType();
+ if (!suggestIntSwitches) {
+ if (type instanceof PsiClassType) {
+ if (type.equalsToText(CommonClassNames.JAVA_LANG_INTEGER) ||
+ type.equalsToText(CommonClassNames.JAVA_LANG_SHORT) ||
+ type.equalsToText(CommonClassNames.JAVA_LANG_BYTE) ||
+ type.equalsToText(CommonClassNames.JAVA_LANG_CHARACTER)) {
+ return;
+ }
+ }
+ else if (PsiType.INT.equals(type) || PsiType.SHORT.equals(type) || PsiType.BYTE.equals(type) || PsiType.CHAR.equals(type)) {
+ return;
+ }
+ }
+ if (!suggestEnumSwitches && type instanceof PsiClassType) {
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiClass aClass = classType.resolve();
+ if (aClass == null || aClass.isEnum()) {
+ return;
+ }
+ }
+ registerStatementError(statement, switchExpression);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java
new file mode 100644
index 000000000000..bd7acc861042
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2005-2011 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ComparisonUtils;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class IndexOfReplaceableByContainsInspection
+ extends BaseInspection {
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "indexof.replaceable.by.contains.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final PsiBinaryExpression expression = (PsiBinaryExpression)infos[0];
+ final PsiExpression lhs = expression.getLOperand();
+ final String text;
+ if (lhs instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression callExpression =
+ (PsiMethodCallExpression)lhs;
+ text = createContainsExpressionText(callExpression, false,
+ expression.getOperationTokenType());
+ }
+ else {
+ final PsiMethodCallExpression callExpression =
+ (PsiMethodCallExpression)expression.getROperand();
+ assert callExpression != null;
+ text = createContainsExpressionText(callExpression, true,
+ expression.getOperationTokenType());
+ }
+ return InspectionGadgetsBundle.message(
+ "expression.can.be.replaced.problem.descriptor", text);
+ }
+
+ @Override
+ @Nullable
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new IndexOfReplaceableByContainsFix();
+ }
+
+ private static class IndexOfReplaceableByContainsFix
+ extends InspectionGadgetsFix {
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor)
+ throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ if (!(element instanceof PsiBinaryExpression)) {
+ return;
+ }
+ final PsiBinaryExpression expression =
+ (PsiBinaryExpression)element;
+ final PsiExpression lhs = expression.getLOperand();
+ final PsiExpression rhs = expression.getROperand();
+ final String newExpressionText;
+ if (lhs instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression callExpression =
+ (PsiMethodCallExpression)lhs;
+ newExpressionText =
+ createContainsExpressionText(callExpression, false,
+ expression.getOperationTokenType());
+ }
+ else if (rhs instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression callExpression =
+ (PsiMethodCallExpression)rhs;
+ newExpressionText =
+ createContainsExpressionText(callExpression, true,
+ expression.getOperationTokenType());
+ }
+ else {
+ return;
+ }
+ replaceExpression(expression, newExpressionText);
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message(
+ "replace.indexof.with.contains.quickfix");
+ }
+
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ }
+
+ static String createContainsExpressionText(
+ @NotNull PsiMethodCallExpression call,
+ boolean flipped, IElementType tokenType) {
+ final PsiReferenceExpression methodExpression =
+ call.getMethodExpression();
+ final PsiExpression qualifierExpression =
+ methodExpression.getQualifierExpression();
+ final String qualifierText;
+ if (qualifierExpression == null) {
+ qualifierText = "";
+ }
+ else {
+ qualifierText = qualifierExpression.getText();
+ }
+ final PsiExpressionList argumentList = call.getArgumentList();
+ final PsiExpression expression = argumentList.getExpressions()[0];
+ @NonNls final String newExpressionText =
+ qualifierText + ".contains(" + expression.getText() + ')';
+ if (tokenType.equals(JavaTokenType.EQEQ)) {
+ return '!' + newExpressionText;
+ }
+ else if (!flipped && (tokenType.equals(JavaTokenType.LT) ||
+ tokenType.equals(JavaTokenType.LE))) {
+ return '!' + newExpressionText;
+ }
+ else if (flipped && (tokenType.equals(JavaTokenType.GT) ||
+ tokenType.equals(JavaTokenType.GE))) {
+ return '!' + newExpressionText;
+ }
+ return newExpressionText;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new IndexOfReplaceableByContainsVisitor();
+ }
+
+ private static class IndexOfReplaceableByContainsVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitBinaryExpression(
+ PsiBinaryExpression expression) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(expression)) {
+ return;
+ }
+ super.visitBinaryExpression(expression);
+ final PsiExpression rhs = expression.getROperand();
+ if (rhs == null) {
+ return;
+ }
+ if (!ComparisonUtils.isComparison(expression)) {
+ return;
+ }
+ final PsiExpression lhs = expression.getLOperand();
+ if (lhs instanceof PsiMethodCallExpression) {
+ if (canBeReplacedByContains(lhs, rhs, false,
+ expression.getOperationTokenType())) {
+ registerError(expression, expression);
+ }
+ }
+ else if (rhs instanceof PsiMethodCallExpression) {
+ if (canBeReplacedByContains(rhs, lhs, true,
+ expression.getOperationTokenType())) {
+ registerError(expression, expression);
+ }
+ }
+ }
+
+ private static boolean canBeReplacedByContains(
+ PsiExpression lhs,
+ PsiExpression rhs, boolean flipped, IElementType tokenType) {
+ final PsiMethodCallExpression callExpression =
+ (PsiMethodCallExpression)lhs;
+ if (!isIndexOfCall(callExpression)) {
+ return false;
+ }
+ final Object object =
+ ExpressionUtils.computeConstantExpression(rhs);
+ if (!(object instanceof Integer)) {
+ return false;
+ }
+ final Integer integer = (Integer)object;
+ final int constant = integer.intValue();
+ if (flipped) {
+ if (constant == -1 && (JavaTokenType.NE.equals(tokenType) ||
+ JavaTokenType.LT.equals(tokenType) ||
+ JavaTokenType.EQEQ.equals(tokenType) ||
+ JavaTokenType.GE.equals(tokenType))) {
+ return true;
+ }
+ else if (constant == 0 &&
+ (JavaTokenType.LE.equals(tokenType) ||
+ JavaTokenType.GT.equals(tokenType))) {
+ return true;
+ }
+ }
+ else {
+ if (constant == -1 && (JavaTokenType.NE.equals(tokenType) ||
+ JavaTokenType.GT.equals(tokenType) ||
+ JavaTokenType.EQEQ.equals(tokenType) ||
+ JavaTokenType.LE.equals(tokenType))) {
+ return true;
+ }
+ else if (constant == 0 &&
+ (JavaTokenType.GE.equals(tokenType) ||
+ JavaTokenType.LT.equals(tokenType))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isIndexOfCall(
+ @NotNull PsiMethodCallExpression expression) {
+ final PsiReferenceExpression methodExpression =
+ expression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.INDEX_OF.equals(methodName)) {
+ return false;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 1) {
+ return false;
+ }
+ final PsiType argumentType = arguments[0].getType();
+ if (argumentType == null ||
+ !argumentType.equalsToText(
+ CommonClassNames.JAVA_LANG_STRING)) {
+ return false;
+ }
+ final PsiExpression qualifier =
+ methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return false;
+ }
+ final PsiType qualifierType = qualifier.getType();
+ return qualifierType != null &&
+ qualifierType.equalsToText(CommonClassNames.JAVA_LANG_STRING);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java
new file mode 100644
index 000000000000..ef1591864c0e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2011-2013 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.LibraryUtil;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class MethodCanBeVariableArityMethodInspection extends BaseInspection {
+
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreByteAndShortArrayParameters = false;
+
+ @SuppressWarnings("PublicField")
+ public boolean ignoreOverridingMethods = false;
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("method.can.be.variable.arity.method.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("method.can.be.variable.arity.method.problem.descriptor");
+ }
+
+ @Override
+ public JComponent createOptionsPanel() {
+ final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
+ panel.addCheckbox(InspectionGadgetsBundle.message("method.can.be.variable.arity.method.ignore.byte.short.option"),
+ "ignoreByteAndShortArrayParameters");
+ panel.addCheckbox(InspectionGadgetsBundle.message("ignore.methods.overriding.super.method"),
+ "ignoreOverridingMethods");
+ return panel;
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new MethodCanBeVariableArityMethodFix();
+ }
+
+ private static class MethodCanBeVariableArityMethodFix extends InspectionGadgetsFix {
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return InspectionGadgetsBundle.message("convert.to.variable.arity.method.quickfix");
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiElement parent = element.getParent();
+ if (!(parent instanceof PsiMethod)) {
+ return;
+ }
+ final PsiMethod method = (PsiMethod)parent;
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() == 0) {
+ return;
+ }
+ final PsiParameter[] parameters = parameterList.getParameters();
+ final PsiParameter lastParameter = parameters[parameters.length - 1];
+ final PsiType type = lastParameter.getType();
+ if (!(type instanceof PsiArrayType)) {
+ return;
+ }
+ final PsiArrayType arrayType = (PsiArrayType)type;
+ final PsiType componentType = arrayType.getComponentType();
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
+ final PsiTypeElement newTypeElement = factory.createTypeElementFromText(componentType.getCanonicalText() + "...", method);
+ final PsiTypeElement typeElement = lastParameter.getTypeElement();
+ if (typeElement != null) {
+ typeElement.replace(newTypeElement);
+ }
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MethodCanBeVariableArityMethodVisitor();
+ }
+
+ private class MethodCanBeVariableArityMethodVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(method)) {
+ return;
+ }
+ super.visitMethod(method);
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() == 0) {
+ return;
+ }
+ final PsiParameter[] parameters = parameterList.getParameters();
+ final PsiParameter lastParameter = parameters[parameters.length - 1];
+ final PsiType type = lastParameter.getType();
+ if (!(type instanceof PsiArrayType)) {
+ return;
+ }
+ if (type instanceof PsiEllipsisType) {
+ return;
+ }
+ final PsiArrayType arrayType = (PsiArrayType)type;
+ final PsiType componentType = arrayType.getComponentType();
+ if (componentType instanceof PsiArrayType) {
+ // don't report when it is multidimensional array
+ return;
+ }
+ if (ignoreByteAndShortArrayParameters) {
+ if (PsiType.BYTE.equals(componentType) || PsiType.SHORT.equals(componentType)) {
+ return;
+ }
+ }
+ if (LibraryUtil.isOverrideOfLibraryMethod(method)) {
+ return;
+ }
+ if (ignoreOverridingMethods && MethodUtils.hasSuper(method)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java
new file mode 100644
index 000000000000..4ff81ab84798
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/RawUseOfParameterizedTypeInspection.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class RawUseOfParameterizedTypeInspection extends BaseInspection {
+
+ @SuppressWarnings("PublicField") public boolean ignoreObjectConstruction = true;
+
+ @SuppressWarnings("PublicField") public boolean ignoreTypeCasts = false;
+
+ @SuppressWarnings("PublicField") public boolean ignoreUncompilable = false;
+
+ @SuppressWarnings("PublicField") public boolean ignoreParametersOfOverridingMethods = false;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("raw.use.of.parameterized.type.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("raw.use.of.parameterized.type.problem.descriptor");
+ }
+
+ @Override
+ @Nullable
+ public JComponent createOptionsPanel() {
+ final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this);
+ optionsPanel.addCheckbox(InspectionGadgetsBundle.message("raw.use.of.parameterized.type.ignore.new.objects.option"),
+ "ignoreObjectConstruction");
+ optionsPanel.addCheckbox(InspectionGadgetsBundle.message("raw.use.of.parameterized.type.ignore.type.casts.option"),
+ "ignoreTypeCasts");
+ optionsPanel.addCheckbox(InspectionGadgetsBundle.message("raw.use.of.parameterized.type.ignore.uncompilable.option"),
+ "ignoreUncompilable");
+ optionsPanel.addCheckbox(InspectionGadgetsBundle.message("raw.use.of.parameterized.type.ignore.overridden.parameter.option"),
+ "ignoreParametersOfOverridingMethods");
+ return optionsPanel;
+ }
+
+ @Override
+ public String getAlternativeID() {
+ return "rawtypes";
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new RawUseOfParameterizedTypeVisitor();
+ }
+
+ private class RawUseOfParameterizedTypeVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitNewExpression(@NotNull PsiNewExpression expression) {
+ if (!hasNeededLanguageLevel(expression)) {
+ return;
+ }
+ super.visitNewExpression(expression);
+ if (ignoreObjectConstruction) {
+ return;
+ }
+ if (ignoreUncompilable && (expression.getArrayInitializer() != null || expression.getArrayDimensions().length > 0)) {
+ //array creation can (almost) never be generic
+ return;
+ }
+ final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
+ checkReferenceElement(classReference);
+ }
+
+ @Override
+ public void visitTypeElement(@NotNull PsiTypeElement typeElement) {
+ if (!hasNeededLanguageLevel(typeElement)) {
+ return;
+ }
+ final PsiType type = typeElement.getType();
+ if (!(type instanceof PsiClassType)) {
+ return;
+ }
+ super.visitTypeElement(typeElement);
+ final PsiElement parent = PsiTreeUtil.skipParentsOfType(typeElement, PsiTypeElement.class);
+ if (parent instanceof PsiInstanceOfExpression || parent instanceof PsiClassObjectAccessExpression) {
+ return;
+ }
+ if (ignoreTypeCasts && parent instanceof PsiTypeCastExpression) {
+ return;
+ }
+ if (PsiTreeUtil.getParentOfType(typeElement, PsiComment.class) != null) {
+ return;
+ }
+ final PsiAnnotationMethod annotationMethod =
+ PsiTreeUtil.getParentOfType(typeElement, PsiAnnotationMethod.class, true, PsiClass.class);
+ if (ignoreUncompilable && annotationMethod != null) {
+ // type of class type parameter cannot be parameterized if annotation method has default value
+ final PsiAnnotationMemberValue defaultValue = annotationMethod.getDefaultValue();
+ if (defaultValue != null && parent != annotationMethod) {
+ return;
+ }
+ }
+ if (parent instanceof PsiParameter && ignoreParametersOfOverridingMethods) {
+ final PsiParameter parameter = (PsiParameter)parent;
+ final PsiElement declarationScope = parameter.getDeclarationScope();
+ if (declarationScope instanceof PsiMethod) {
+ final PsiMethod method = (PsiMethod)declarationScope;
+ if (MethodUtils.hasSuper(method)) {
+ return;
+ }
+ }
+ }
+ final PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement();
+ checkReferenceElement(referenceElement);
+ }
+
+ @Override
+ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
+ if (!hasNeededLanguageLevel(reference)) {
+ return;
+ }
+ super.visitReferenceElement(reference);
+ final PsiElement referenceParent = reference.getParent();
+ if (!(referenceParent instanceof PsiReferenceList)) {
+ return;
+ }
+ final PsiReferenceList referenceList = (PsiReferenceList)referenceParent;
+ final PsiElement listParent = referenceList.getParent();
+ if (!(listParent instanceof PsiClass)) {
+ return;
+ }
+ checkReferenceElement(reference);
+ }
+
+ private void checkReferenceElement(PsiJavaCodeReferenceElement reference) {
+ if (reference == null) {
+ return;
+ }
+ final PsiType[] typeParameters = reference.getTypeParameters();
+ if (typeParameters.length > 0) {
+ return;
+ }
+ final PsiElement element = reference.resolve();
+ if (!(element instanceof PsiClass)) {
+ return;
+ }
+ final PsiClass aClass = (PsiClass)element;
+ final PsiElement qualifier = reference.getQualifier();
+ if (qualifier instanceof PsiJavaCodeReferenceElement) {
+ final PsiJavaCodeReferenceElement qualifierReference = (PsiJavaCodeReferenceElement)qualifier;
+ if (!aClass.hasModifierProperty(PsiModifier.STATIC) && !aClass.isInterface() && !aClass.isEnum()) {
+ checkReferenceElement(qualifierReference);
+ }
+ }
+ if (!aClass.hasTypeParameters()) {
+ return;
+ }
+ registerError(reference);
+ }
+
+ private boolean hasNeededLanguageLevel(PsiElement element) {
+ return element.getLanguage().isKindOf(JavaLanguage.INSTANCE) && PsiUtil.isLanguageLevel5OrHigher(element);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java
new file mode 100644
index 000000000000..33b1a947acc8
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.TypeUtils;
+import com.siyeh.ig.psiutils.VariableAccessUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class StringBufferReplaceableByStringBuilderInspection extends BaseInspection {
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "StringBufferMayBeStringBuilder";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("string.buffer.replaceable.by.string.builder.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("string.buffer.replaceable.by.string.builder.problem.descriptor");
+ }
+
+ @Override
+ public InspectionGadgetsFix buildFix(Object... infos) {
+ return new StringBufferMayBeStringBuilderFix();
+ }
+
+ @Nullable
+ private static PsiNewExpression getNewStringBuffer(PsiExpression expression) {
+ if (expression == null) {
+ return null;
+ }
+ else if (expression instanceof PsiNewExpression) {
+ return (PsiNewExpression)expression;
+ }
+ else if (expression instanceof PsiMethodCallExpression) {
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ @NonNls final String methodName = methodExpression.getReferenceName();
+ if (!"append".equals(methodName)) {
+ return null;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ return getNewStringBuffer(qualifier);
+ }
+ return null;
+ }
+
+ private static class StringBufferMayBeStringBuilderFix extends InspectionGadgetsFix {
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("string.buffer.replaceable.by.string.builder.replace.quickfix");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiElement parent = element.getParent();
+ final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
+ final PsiClass stringBuilderClass = psiFacade.findClass(CommonClassNames.JAVA_LANG_STRING_BUILDER, element.getResolveScope());
+ if (stringBuilderClass == null) {
+ return;
+ }
+ final PsiElementFactory factory = psiFacade.getElementFactory();
+ final PsiJavaCodeReferenceElement stringBuilderClassReference = factory.createClassReferenceElement(stringBuilderClass);
+ final PsiClassType stringBuilderType = factory.createType(stringBuilderClass);
+ final PsiTypeElement stringBuilderTypeElement = factory.createTypeElement(stringBuilderType);
+ final PsiElement grandParent = parent.getParent();
+ final PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)grandParent;
+ final PsiElement[] declaredElements = declarationStatement.getDeclaredElements();
+ for (PsiElement declaredElement : declaredElements) {
+ if (!(declaredElement instanceof PsiVariable)) {
+ continue;
+ }
+ replaceWithStringBuilder(stringBuilderClassReference, stringBuilderTypeElement, (PsiVariable)declaredElement);
+ }
+ }
+
+ private static void replaceWithStringBuilder(PsiJavaCodeReferenceElement newClassReference,
+ PsiTypeElement newTypeElement,
+ PsiVariable variable) {
+ final PsiExpression initializer = getNewStringBuffer(variable.getInitializer());
+ if (initializer == null) {
+ return;
+ }
+ final PsiNewExpression newExpression = (PsiNewExpression)initializer;
+ final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference(); // no anonymous classes because StringBuffer is final
+ if (classReference == null) {
+ return;
+ }
+ final PsiTypeElement typeElement = variable.getTypeElement();
+ if (typeElement != null && typeElement.getParent() == variable) {
+ typeElement.replace(newTypeElement);
+ }
+ classReference.replace(newClassReference);
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new StringBufferReplaceableByStringBuilderVisitor();
+ }
+
+ private static class StringBufferReplaceableByStringBuilderVisitor extends BaseInspectionVisitor {
+
+ private static final Set<String> excludes = new HashSet(Arrays.asList(CommonClassNames.JAVA_LANG_STRING_BUILDER,
+ CommonClassNames.JAVA_LANG_STRING_BUFFER));
+
+ @Override
+ public void visitDeclarationStatement(PsiDeclarationStatement statement) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(statement)) {
+ return;
+ }
+ super.visitDeclarationStatement(statement);
+ final PsiElement[] declaredElements = statement.getDeclaredElements();
+ if (declaredElements.length == 0) {
+ return;
+ }
+ for (PsiElement declaredElement : declaredElements) {
+ if (!(declaredElement instanceof PsiLocalVariable)) {
+ return;
+ }
+ final PsiLocalVariable variable = (PsiLocalVariable)declaredElement;
+ final PsiElement context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class, true, PsiClass.class);
+ if (!isReplaceableStringBuffer(variable, context)) {
+ return;
+ }
+ }
+ final PsiLocalVariable firstVariable = (PsiLocalVariable)declaredElements[0];
+ registerVariableError(firstVariable);
+ }
+
+ private static boolean isReplaceableStringBuffer(PsiVariable variable, PsiElement context) {
+ if (context == null) {
+ return false;
+ }
+ final PsiType type = variable.getType();
+ if (!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUFFER, type)) {
+ return false;
+ }
+ final PsiExpression initializer = variable.getInitializer();
+ if (initializer == null) {
+ return false;
+ }
+ if (getNewStringBuffer(initializer) == null) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsAssigned(variable, context)) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsAssignedFrom(variable, context)) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsReturned(variable, context, true)) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, excludes, context, true)) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsUsedInInnerClass(variable, context)) {
+ return false;
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java
new file mode 100644
index 000000000000..804a290d4d06
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class TryFinallyCanBeTryWithResourcesInspection extends BaseInspection {
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("try.finally.can.be.try.with.resources.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("try.finally.can.be.try.with.resources.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new TryFinallyCanBeTryWithResourcesFix();
+ }
+
+ private static class TryFinallyCanBeTryWithResourcesFix extends InspectionGadgetsFix {
+
+ public TryFinallyCanBeTryWithResourcesFix() {}
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("try.finally.can.be.try.with.resources.quickfix");
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiElement parent = element.getParent();
+ if (!(parent instanceof PsiTryStatement)) {
+ return;
+ }
+ final PsiTryStatement tryStatement = (PsiTryStatement)parent;
+ final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
+ if (tryBlock == null) {
+ return;
+ }
+ final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
+ if (finallyBlock == null) {
+ return;
+ }
+ final PsiElement[] tryBlockChildren = tryBlock.getChildren();
+ final Set<PsiLocalVariable> variables = new HashSet();
+ for (PsiLocalVariable variable : collectVariables(tryStatement)) {
+ if (!isVariableUsedOutsideContext(variable, tryBlock)) {
+ variables.add(variable);
+ }
+ }
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
+ @NonNls final StringBuilder newTryStatementText = new StringBuilder("try (");
+ final Set<Integer> unwantedChildren = new HashSet(2);
+ boolean separator = false;
+ for (PsiLocalVariable variable : variables) {
+ final boolean hasInitializer;
+ final PsiExpression initializer = variable.getInitializer();
+ if (initializer == null) {
+ hasInitializer = false;
+ }
+ else {
+ final PsiType type = initializer.getType();
+ hasInitializer = !PsiType.NULL.equals(type);
+ }
+ if (separator) {
+ newTryStatementText.append(';');
+ }
+ newTryStatementText.append(variable.getTypeElement().getText()).append(' ').append(variable.getName()).append('=');
+ if (hasInitializer) {
+ newTryStatementText.append(initializer.getText());
+ }
+ else {
+ final int index = findInitialization(tryBlockChildren, variable, hasInitializer);
+ if (index < 0) {
+ return;
+ }
+ unwantedChildren.add(Integer.valueOf(index));
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)tryBlockChildren[index];
+ if (expressionStatement.getNextSibling() instanceof PsiWhiteSpace) {
+ unwantedChildren.add(Integer.valueOf(index + 1));
+ }
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expressionStatement.getExpression();
+ final PsiExpression rhs = assignmentExpression.getRExpression();
+ if (rhs == null) {
+ return;
+ }
+ newTryStatementText.append(rhs.getText());
+ }
+ separator = true;
+ }
+ newTryStatementText.append(") {");
+ final int tryBlockStatementsLength = tryBlockChildren.length - 1;
+ for (int i = 1; i < tryBlockStatementsLength; i++) {
+ final PsiElement child = tryBlockChildren[i];
+ if (unwantedChildren.contains(Integer.valueOf(i))) {
+ continue;
+ }
+ newTryStatementText.append(child.getText());
+ }
+ newTryStatementText.append('}');
+ final PsiCatchSection[] catchSections = tryStatement.getCatchSections();
+ for (PsiCatchSection catchSection : catchSections) {
+ newTryStatementText.append(catchSection.getText());
+ }
+ final PsiElement[] finallyChildren = finallyBlock.getChildren();
+ boolean appended = false;
+ final int finallyChildrenLength = finallyChildren.length - 1;
+ final List<PsiElement> savedComments = new ArrayList();
+ for (int i = 1; i < finallyChildrenLength; i++) {
+ final PsiElement child = finallyChildren[i];
+ if (isCloseStatement(child, variables)) {
+ continue;
+ }
+ if (!appended) {
+ if (child instanceof PsiComment) {
+ final PsiElement prevSibling = child.getPrevSibling();
+ if (prevSibling instanceof PsiWhiteSpace) {
+ savedComments.add(prevSibling);
+ }
+ savedComments.add(child);
+ }
+ else if (!(child instanceof PsiWhiteSpace)) {
+ newTryStatementText.append(" finally {");
+ for (PsiElement savedComment : savedComments) {
+ newTryStatementText.append(savedComment.getText());
+ }
+ newTryStatementText.append(child.getText());
+ appended = true;
+ }
+ }
+ else {
+ newTryStatementText.append(child.getText());
+ }
+ }
+ if (appended) {
+ newTryStatementText.append('}');
+ }
+ for (PsiLocalVariable variable : variables) {
+ variable.delete();
+ }
+ if (!appended) {
+ final int savedCommentsSize = savedComments.size();
+ final PsiElement parent1 = tryStatement.getParent();
+ for (int i = savedCommentsSize - 1; i >= 0; i--) {
+ final PsiElement savedComment = savedComments.get(i);
+ parent1.addAfter(savedComment, tryStatement);
+ }
+ }
+ final PsiStatement newTryStatement = factory.createStatementFromText(newTryStatementText.toString(), element);
+ tryStatement.replace(newTryStatement);
+ }
+
+ private static boolean isCloseStatement(PsiElement element, Set<PsiLocalVariable> variables) {
+ if (element instanceof PsiExpressionStatement) {
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)element;
+ final PsiExpression expression = expressionStatement.getExpression();
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.CLOSE.equals(methodName)) {
+ return false;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (!(target instanceof PsiLocalVariable)) {
+ return false;
+ }
+ final PsiLocalVariable variable = (PsiLocalVariable)target;
+ return variables.contains(variable);
+ }
+ else if (element instanceof PsiIfStatement) {
+ final PsiIfStatement ifStatement = (PsiIfStatement)element;
+ if (ifStatement.getElseBranch() != null) {
+ return false;
+ }
+ final PsiExpression condition = ifStatement.getCondition();
+ if (!(condition instanceof PsiBinaryExpression)) {
+ return false;
+ }
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)condition;
+ final IElementType tokenType = binaryExpression.getOperationTokenType();
+ if (!JavaTokenType.NE.equals(tokenType)) {
+ return false;
+ }
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ if (rhs == null) {
+ return false;
+ }
+ final PsiElement variable;
+ if (PsiType.NULL.equals(rhs.getType())) {
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
+ variable = referenceExpression.resolve();
+ if (!(variable instanceof PsiLocalVariable)) {
+ return false;
+ }
+ }
+ else if (PsiType.NULL.equals(lhs.getType())) {
+ if (!(rhs instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)rhs;
+ variable = referenceExpression.resolve();
+ if (!(variable instanceof PsiLocalVariable)) {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ final PsiStatement thenBranch = ifStatement.getThenBranch();
+ if (thenBranch instanceof PsiExpressionStatement) {
+ return isCloseStatement(thenBranch, variables);
+ }
+ else if (thenBranch instanceof PsiBlockStatement) {
+ final PsiBlockStatement blockStatement = (PsiBlockStatement)thenBranch;
+ final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
+ final PsiStatement[] statements = codeBlock.getStatements();
+ return statements.length == 1 && isCloseStatement(statements[0], variables);
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new TryFinallyCanBeTryWithResourcesVisitor();
+ }
+
+ private static class TryFinallyCanBeTryWithResourcesVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitTryStatement(PsiTryStatement tryStatement) {
+ super.visitTryStatement(tryStatement);
+ if (!PsiUtil.isLanguageLevel7OrHigher(tryStatement)) {
+ return;
+ }
+ final PsiResourceList resourceList = tryStatement.getResourceList();
+ if (resourceList != null) {
+ return;
+ }
+ final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
+ if (tryBlock == null) {
+ return;
+ }
+ final List<PsiLocalVariable> variables = collectVariables(tryStatement);
+ if (variables.isEmpty()) {
+ return;
+ }
+ final PsiStatement[] tryBlockStatements = tryBlock.getStatements();
+ boolean found = false;
+ for (PsiVariable variable : variables) {
+ final boolean hasInitializer;
+ final PsiExpression initializer = variable.getInitializer();
+ if (initializer == null) {
+ hasInitializer = false;
+ }
+ else {
+ final PsiType type = initializer.getType();
+ hasInitializer = !PsiType.NULL.equals(type);
+ }
+ final int index = findInitialization(tryBlockStatements, variable, hasInitializer);
+ if (index >= 0 ^ hasInitializer) {
+ if (isVariableUsedOutsideContext(variable, tryBlock)) {
+ continue;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return;
+ }
+ registerStatementError(tryStatement);
+ }
+ }
+
+ static boolean isVariableUsedOutsideContext(PsiVariable variable, PsiElement context) {
+ final VariableUsedOutsideContextVisitor visitor = new VariableUsedOutsideContextVisitor(variable, context);
+ final PsiElement declarationScope = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
+ if (declarationScope == null) {
+ return true;
+ }
+ declarationScope.accept(visitor);
+ return visitor.variableIsUsed();
+ }
+
+ static List<PsiLocalVariable> collectVariables(PsiTryStatement tryStatement) {
+ final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
+ if (finallyBlock == null) {
+ return Collections.EMPTY_LIST;
+ }
+ final PsiStatement[] statements = finallyBlock.getStatements();
+ if (statements.length == 0) {
+ return Collections.EMPTY_LIST;
+ }
+ final List<PsiLocalVariable> variables = new ArrayList();
+ for (PsiStatement statement : statements) {
+ final PsiLocalVariable variable = findAutoCloseableVariable(statement);
+ if (variable != null) {
+ variables.add(variable);
+ }
+ }
+ return variables;
+ }
+
+ @Nullable
+ static PsiLocalVariable findAutoCloseableVariable(PsiStatement statement) {
+ if (statement instanceof PsiIfStatement) {
+ final PsiIfStatement ifStatement = (PsiIfStatement)statement;
+ if (ifStatement.getElseBranch() != null) {
+ return null;
+ }
+ final PsiExpression condition = ifStatement.getCondition();
+ if (!(condition instanceof PsiBinaryExpression)) {
+ return null;
+ }
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)condition;
+ final IElementType tokenType = binaryExpression.getOperationTokenType();
+ if (!JavaTokenType.NE.equals(tokenType)) {
+ return null;
+ }
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ if (rhs == null) {
+ return null;
+ }
+ final PsiElement variable;
+ if (PsiType.NULL.equals(rhs.getType())) {
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
+ variable = referenceExpression.resolve();
+ if (!(variable instanceof PsiLocalVariable)) {
+ return null;
+ }
+ }
+ else if (PsiType.NULL.equals(lhs.getType())) {
+ if (!(rhs instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)rhs;
+ variable = referenceExpression.resolve();
+ if (!(variable instanceof PsiLocalVariable)) {
+ return null;
+ }
+ }
+ else {
+ return null;
+ }
+ final PsiStatement thenBranch = ifStatement.getThenBranch();
+ final PsiLocalVariable resourceVariable;
+ if (thenBranch instanceof PsiExpressionStatement) {
+ resourceVariable = findAutoCloseableVariable(thenBranch);
+ }
+ else if (thenBranch instanceof PsiBlockStatement) {
+ final PsiBlockStatement blockStatement = (PsiBlockStatement)thenBranch;
+ final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
+ final PsiStatement[] statements = codeBlock.getStatements();
+ if (statements.length != 1) {
+ return null;
+ }
+ resourceVariable = findAutoCloseableVariable(statements[0]);
+ }
+ else {
+ return null;
+ }
+ if (variable.equals(resourceVariable)) {
+ return resourceVariable;
+ }
+ }
+ else if (statement instanceof PsiExpressionStatement) {
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statement;
+ final PsiExpression expression = expressionStatement.getExpression();
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return null;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.CLOSE.equals(methodName)) {
+ return null;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return null;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (!(target instanceof PsiLocalVariable) || target instanceof PsiResourceVariable) {
+ return null;
+ }
+ final PsiLocalVariable variable = (PsiLocalVariable)target;
+ if (!isAutoCloseable(variable)) {
+ return null;
+ }
+ return variable;
+ }
+ return null;
+ }
+
+ private static boolean isAutoCloseable(PsiVariable variable) {
+ final PsiType type = variable.getType();
+ if (!(type instanceof PsiClassType)) {
+ return false;
+ }
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiClass aClass = classType.resolve();
+ return aClass != null && InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE);
+ }
+
+ static int findInitialization(PsiElement[] elements, PsiVariable variable,
+ boolean hasInitializer) {
+ int result = -1;
+ final int statementsLength = elements.length;
+ for (int i = 0; i < statementsLength; i++) {
+ final PsiElement element = elements[i];
+ if (!(element instanceof PsiExpressionStatement)) {
+ continue;
+ }
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)element;
+ final PsiExpression expression = expressionStatement.getExpression();
+ if (!(expression instanceof PsiAssignmentExpression)) {
+ continue;
+ }
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
+ final PsiExpression lhs = assignmentExpression.getLExpression();
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ continue;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
+ final PsiElement target = referenceExpression.resolve();
+ if (variable.equals(target)) {
+ if (result >= 0 && !hasInitializer) {
+ return -1;
+ }
+ result = i;
+ }
+ }
+ return result;
+ }
+
+ static class VariableUsedOutsideContextVisitor extends JavaRecursiveElementVisitor {
+
+ private boolean used = false;
+ @NotNull private final PsiVariable variable;
+ private final PsiElement skipContext;
+
+ public VariableUsedOutsideContextVisitor(@NotNull PsiVariable variable, PsiElement skipContext) {
+ this.variable = variable;
+ this.skipContext = skipContext;
+ }
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (element.equals(skipContext)) {
+ return;
+ }
+ if (used) {
+ return;
+ }
+ super.visitElement(element);
+ }
+
+ @Override
+ public void visitReferenceExpression(@NotNull PsiReferenceExpression referenceExpression) {
+ if (used) {
+ return;
+ }
+ super.visitReferenceExpression(referenceExpression);
+ final PsiElement target = referenceExpression.resolve();
+ if (target == null) {
+ return;
+ }
+ if (target.equals(variable) && !isCloseMethodCalled(referenceExpression)) {
+ used = true;
+ }
+ }
+
+ private static boolean isCloseMethodCalled(PsiReferenceExpression referenceExpression) {
+ final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(referenceExpression, PsiMethodCallExpression.class);
+ if (methodCallExpression == null) {
+ return false;
+ }
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ if (argumentList.getExpressions().length != 0) {
+ return false;
+ }
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final String name = methodExpression.getReferenceName();
+ return HardcodedMethodConstants.CLOSE.equals(name);
+ }
+
+ public boolean variableIsUsed() {
+ return used;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryWithIdenticalCatchesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryWithIdenticalCatchesInspection.java
new file mode 100644
index 000000000000..532589663a57
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/TryWithIdenticalCatchesInspection.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.TypeConversionUtil;
+import com.intellij.refactoring.extractMethod.InputVariables;
+import com.intellij.refactoring.util.duplicates.DuplicatesFinder;
+import com.intellij.refactoring.util.duplicates.Match;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author yole, Bas Leijdekkers
+ */
+public class TryWithIdenticalCatchesInspection extends BaseInspection {
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final PsiType type = (PsiType)infos[1];
+ return InspectionGadgetsBundle.message("try.with.identical.catches.problem.descriptor", type.getPresentableText());
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new TryWithIdenticalCatchesVisitor();
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("try.with.identical.catches.display.name");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new CollapseCatchSectionsFix(((Integer)infos[0]).intValue());
+ }
+
+ private static class TryWithIdenticalCatchesVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitTryStatement(PsiTryStatement statement) {
+ super.visitTryStatement(statement);
+ if (!PsiUtil.isLanguageLevel7OrHigher(statement)) {
+ return;
+ }
+ final PsiCatchSection[] catchSections = statement.getCatchSections();
+ if (catchSections.length < 2) {
+ return;
+ }
+ final PsiParameter[] parameters = statement.getCatchBlockParameters();
+ if (catchSections.length != parameters.length) {
+ return;
+ }
+ final boolean[] duplicates = new boolean[catchSections.length];
+ for (int i = 0; i < catchSections.length - 1; i++) {
+ final PsiCatchSection catchSection = catchSections[i];
+ final PsiCodeBlock catchBlock = catchSection.getCatchBlock();
+ if (catchBlock == null) {
+ continue;
+ }
+ final PsiParameter parameter = catchSection.getParameter();
+ if (parameter == null) {
+ continue;
+ }
+ final InputVariables inputVariables = new InputVariables(Collections.singletonList(parameter),
+ statement.getProject(),
+ new LocalSearchScope(catchBlock),
+ false);
+ final DuplicatesFinder finder = new DuplicatesFinder(new PsiElement[]{catchBlock},
+ inputVariables, null, Collections.<PsiVariable>emptyList());
+ for (int j = i + 1; j < catchSections.length; j++) {
+ if (duplicates[j]) {
+ continue;
+ }
+ final PsiCatchSection otherSection = catchSections[j];
+ final PsiCodeBlock otherCatchBlock = otherSection.getCatchBlock();
+ if (otherCatchBlock == null) {
+ continue;
+ }
+ final Match match = finder.isDuplicate(otherCatchBlock, true);
+ if (match == null || match.getReturnValue() != null) {
+ continue;
+ }
+ final List<PsiElement> parameterValues = match.getParameterValues(parameter);
+ if (parameterValues != null && (parameterValues.size() != 1 || !(parameterValues.get(0) instanceof PsiReferenceExpression))) {
+ continue;
+ }
+ if (!canCollapse(parameters, i, j)) {
+ continue;
+ }
+ final PsiJavaToken rParenth = otherSection.getRParenth();
+ if (rParenth != null) {
+ registerErrorAtOffset(otherSection, 0, rParenth.getStartOffsetInParent() + 1, Integer.valueOf(i), parameter.getType());
+ }
+ duplicates[i] = true;
+ duplicates[j] = true;
+ }
+ }
+ }
+
+ private static boolean canCollapse(PsiParameter[] parameters, int index1, int index2) {
+ if (index2 > index1) {
+ final PsiType type = parameters[index2].getType();
+ for (int i = index1 + 1; i < index2; i++) {
+ final PsiType otherType = parameters[i].getType();
+ if (TypeConversionUtil.isAssignable(type, otherType)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ else {
+ final PsiType type = parameters[index1].getType();
+ for (int i = index2 + 1; i < index1; i++) {
+ final PsiType otherType = parameters[i].getType();
+ if (TypeConversionUtil.isAssignable(otherType, type)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ }
+
+ private static class CollapseCatchSectionsFix extends InspectionGadgetsFix {
+
+ private final int myCollapseIntoIndex;
+
+ public CollapseCatchSectionsFix(int collapseIntoIndex) {
+ myCollapseIntoIndex = collapseIntoIndex;
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("try.with.identical.catches.quickfix");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiCatchSection section = (PsiCatchSection)descriptor.getPsiElement();
+ final PsiTryStatement tryStatement = (PsiTryStatement)section.getParent();
+ final PsiCatchSection[] catchSections = tryStatement.getCatchSections();
+ if (myCollapseIntoIndex >= catchSections.length) {
+ return; // something has gone stale
+ }
+ final PsiCatchSection collapseInto = catchSections[myCollapseIntoIndex];
+ final PsiParameter parameter1 = collapseInto.getParameter();
+ final PsiParameter parameter2 = section.getParameter();
+ if (parameter1 == null || parameter2 == null) {
+ return;
+ }
+ final PsiType type1 = parameter1.getType();
+ final PsiType type2 = parameter2.getType();
+ if (TypeConversionUtil.isAssignable(type1, type2)) {
+ section.delete();
+ return;
+ }
+ else if (TypeConversionUtil.isAssignable(type2, type1)) {
+ collapseInto.delete();
+ return;
+ }
+ final List<PsiType> types = new ArrayList();
+ collectDisjunctTypes(type1, types);
+ collectDisjunctTypes(type2, types);
+ final StringBuilder typeText = new StringBuilder();
+ for (PsiType type : types) {
+ if (typeText.length() > 0) {
+ typeText.append(" | ");
+ }
+ typeText.append(type.getCanonicalText());
+ }
+ final PsiTypeElement newTypeElement =
+ JavaPsiFacade.getElementFactory(project).createTypeElementFromText(typeText.toString(), tryStatement);
+ final PsiTypeElement typeElement = parameter1.getTypeElement();
+ if (typeElement == null) {
+ return;
+ }
+ typeElement.replace(newTypeElement);
+ section.delete();
+ }
+
+ private static void collectDisjunctTypes(PsiType type, List<PsiType> out) {
+ if (type instanceof PsiDisjunctionType) {
+ final PsiDisjunctionType disjunctionType = (PsiDisjunctionType)type;
+ final List<PsiType> disjunctions = disjunctionType.getDisjunctions();
+ for (PsiType disjunction : disjunctions) {
+ collectDisjunctTypes(disjunction, out);
+ }
+ return;
+ }
+ final int size = out.size();
+ for (int i = 0; i < size; i++) {
+ final PsiType collectedType = out.get(i);
+ if (TypeConversionUtil.isAssignable(type, collectedType)) {
+ out.remove(i);
+ out.add(type);
+ return;
+ } else if (TypeConversionUtil.isAssignable(collectedType, type)) {
+ return;
+ }
+ }
+ out.add(type);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java
new file mode 100644
index 000000000000..2b1551e15387
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryBoxingInspection.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.MethodCallUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class UnnecessaryBoxingInspection extends BaseInspection {
+
+ @NonNls static final Map<String, String> boxedPrimitiveMap = new HashMap<String, String>(8);
+
+ static {
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_INTEGER, "int");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_SHORT, "short");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_BOOLEAN, "boolean");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_LONG, "long");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_BYTE, "byte");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_FLOAT, "float");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_DOUBLE, "double");
+ boxedPrimitiveMap.put(CommonClassNames.JAVA_LANG_CHARACTER, "char");
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("unnecessary.boxing.display.name");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("unnecessary.boxing.problem.descriptor");
+ }
+
+ @Override
+ public InspectionGadgetsFix buildFix(Object... infos) {
+ return new UnnecessaryBoxingFix();
+ }
+
+ private static class UnnecessaryBoxingFix extends InspectionGadgetsFix {
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("unnecessary.boxing.remove.quickfix");
+ }
+
+ @Override
+ public void doFix(@NotNull Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiCallExpression expression = (PsiCallExpression)descriptor.getPsiElement();
+ final PsiType boxedType = expression.getType();
+ if (boxedType == null) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ if (argumentList == null) {
+ return;
+ }
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 1) {
+ return;
+ }
+ final PsiExpression unboxedExpression = arguments[0];
+ final PsiType unboxedType = unboxedExpression.getType();
+ if (unboxedType == null) {
+ return;
+ }
+ final String cast = getCastString(unboxedType, boxedType);
+ if (cast == null) {
+ return;
+ }
+ final int precedence = ParenthesesUtils.getPrecedence(unboxedExpression);
+ if (cast.length() > 0 && precedence > ParenthesesUtils.TYPE_CAST_PRECEDENCE) {
+ replaceExpression(expression, cast + '(' + unboxedExpression.getText() + ')');
+ }
+ else {
+ replaceExpression(expression, cast + unboxedExpression.getText());
+ }
+ }
+
+ @Nullable
+ private static String getCastString(@NotNull PsiType fromType, @NotNull PsiType toType) {
+ final String toTypeText = toType.getCanonicalText();
+ final String fromTypeText = fromType.getCanonicalText();
+ final String unboxedType = boxedPrimitiveMap.get(toTypeText);
+ if (unboxedType == null) {
+ return null;
+ }
+ if (fromTypeText.equals(unboxedType)) {
+ return "";
+ }
+ else {
+ return '(' + unboxedType + ')';
+ }
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UnnecessaryBoxingVisitor();
+ }
+
+ private static class UnnecessaryBoxingVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitNewExpression(@NotNull PsiNewExpression expression) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(expression)) {
+ return;
+ }
+ super.visitNewExpression(expression);
+ final PsiType constructorType = expression.getType();
+ if (constructorType == null) {
+ return;
+ }
+ final String constructorTypeText = constructorType.getCanonicalText();
+ if (!boxedPrimitiveMap.containsKey(constructorTypeText)) {
+ return;
+ }
+ final PsiMethod constructor = expression.resolveConstructor();
+ if (constructor == null) {
+ return;
+ }
+ final PsiParameterList parameterList = constructor.getParameterList();
+ if (parameterList.getParametersCount() != 1) {
+ return;
+ }
+ final PsiParameter[] parameters = parameterList.getParameters();
+ final PsiParameter parameter = parameters[0];
+ final PsiType parameterType = parameter.getType();
+ final String parameterTypeText = parameterType.getCanonicalText();
+ final String boxableConstructorType = boxedPrimitiveMap.get(constructorTypeText);
+ if (!boxableConstructorType.equals(parameterTypeText)) {
+ return;
+ }
+ if (!canBeUnboxed(expression)) {
+ return;
+ }
+ registerError(expression);
+ }
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(expression)) {
+ return;
+ }
+ super.visitMethodCallExpression(expression);
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 1) {
+ return;
+ }
+ if (!(arguments[0].getType() instanceof PsiPrimitiveType)) {
+ return;
+ }
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ @NonNls
+ final String referenceName = methodExpression.getReferenceName();
+ if (!"valueOf".equals(referenceName)) {
+ return;
+ }
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ if (!(qualifierExpression instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifierExpression;
+ final String canonicalText = referenceExpression.getCanonicalText();
+ if (!boxedPrimitiveMap.containsKey(canonicalText)) {
+ return;
+ }
+ if (!canBeUnboxed(expression)) {
+ return;
+ }
+ registerError(expression);
+ }
+
+ private static boolean canBeUnboxed(PsiExpression expression) {
+ PsiElement parent = expression.getParent();
+ while (parent instanceof PsiParenthesizedExpression) {
+ parent = parent.getParent();
+ }
+ if (parent instanceof PsiExpressionStatement || parent instanceof PsiReferenceExpression) {
+ return false;
+ }
+ else if (parent instanceof PsiTypeCastExpression) {
+ final PsiTypeCastExpression castExpression = (PsiTypeCastExpression)parent;
+ final PsiType castType = castExpression.getType();
+ if (castType instanceof PsiClassType) {
+ final PsiClassType classType = (PsiClassType)castType;
+ final PsiClass aClass = classType.resolve();
+ if (aClass instanceof PsiTypeParameter) {
+ return false;
+ }
+ }
+ }
+ else if (parent instanceof PsiConditionalExpression) {
+ final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)parent;
+ final PsiExpression thenExpression = conditionalExpression.getThenExpression();
+ final PsiExpression elseExpression = conditionalExpression.getElseExpression();
+ if (elseExpression == null || thenExpression == null) {
+ return false;
+ }
+ if (PsiTreeUtil.isAncestor(thenExpression, expression, false)) {
+ final PsiType type = elseExpression.getType();
+ return type instanceof PsiPrimitiveType;
+ }
+ else if (PsiTreeUtil.isAncestor(elseExpression, expression, false)) {
+ final PsiType type = thenExpression.getType();
+ return type instanceof PsiPrimitiveType;
+ }
+ else {
+ return true;
+ }
+ }
+ else if (parent instanceof PsiBinaryExpression) {
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent;
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ if (rhs == null) {
+ return false;
+ }
+ final PsiType rhsType = rhs.getType();
+ if (rhsType == null) {
+ return false;
+ }
+ final PsiType lhsType = lhs.getType();
+ if (lhsType == null) {
+ return false;
+ }
+ if (PsiTreeUtil.isAncestor(rhs, expression, false)) {
+ final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(rhsType);
+ return unboxedType != null && unboxedType.isAssignableFrom(lhsType);
+ }
+ else {
+ final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(lhsType);
+ return unboxedType != null && unboxedType.isAssignableFrom(rhsType);
+ }
+ }
+ final PsiMethodCallExpression containingMethodCallExpression = getParentMethodCallExpression(expression);
+ return containingMethodCallExpression == null || isSameMethodCalledWithoutBoxing(containingMethodCallExpression, expression);
+ }
+
+ @Nullable
+ private static PsiMethodCallExpression getParentMethodCallExpression(@NotNull PsiElement expression) {
+ final PsiElement parent = expression.getParent();
+ if (parent instanceof PsiParenthesizedExpression || parent instanceof PsiExpressionList) {
+ return getParentMethodCallExpression(parent);
+ }
+ else if (parent instanceof PsiMethodCallExpression) {
+ return (PsiMethodCallExpression)parent;
+ }
+ else {
+ return null;
+ }
+ }
+
+ private static boolean isSameMethodCalledWithoutBoxing(@NotNull PsiMethodCallExpression methodCallExpression,
+ @NotNull PsiExpression boxingExpression) {
+ final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
+ final PsiExpression[] expressions = argumentList.getExpressions();
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiElement element = methodExpression.resolve();
+ if (!(element instanceof PsiMethod)) {
+ return false;
+ }
+ final PsiMethod originalMethod = (PsiMethod)element;
+ final String name = originalMethod.getName();
+ final PsiClass containingClass = originalMethod.getContainingClass();
+ if (containingClass == null) {
+ return false;
+ }
+ final PsiType[] types = new PsiType[expressions.length];
+ for (int i = 0; i < expressions.length; i++) {
+ final PsiExpression expression = expressions[i];
+ final PsiType type = expression.getType();
+ if (boxingExpression.equals(expression)) {
+ final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
+ if (unboxedType == null) {
+ return false;
+ }
+ types[i] = unboxedType;
+ }
+ else {
+ types[i] = type;
+ }
+ }
+ final PsiMethod[] methods = containingClass.findMethodsByName(name, true);
+ for (PsiMethod method : methods) {
+ if (!originalMethod.equals(method)) {
+ if (MethodCallUtils.isApplicable(method, PsiSubstitutor.EMPTY, types)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java
new file mode 100644
index 000000000000..d3acf7d8d5c3
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/UnnecessaryUnboxingInspection.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ComparisonUtils;
+import com.siyeh.ig.psiutils.MethodCallUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class UnnecessaryUnboxingInspection extends BaseInspection {
+
+ @NonNls static final Map<String, String> s_unboxingMethods =
+ new HashMap<String, String>(8);
+
+ static {
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_INTEGER, "intValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_SHORT, "shortValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_BOOLEAN, "booleanValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_LONG, "longValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_BYTE, "byteValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_FLOAT, "floatValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_DOUBLE, "doubleValue");
+ s_unboxingMethods.put(CommonClassNames.JAVA_LANG_CHARACTER, "charValue");
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "unnecessary.unboxing.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "unnecessary.unboxing.problem.descriptor");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UnnecessaryUnboxingVisitor();
+ }
+
+ @Override
+ public InspectionGadgetsFix buildFix(Object... infos) {
+ return new UnnecessaryUnboxingFix();
+ }
+
+ private static class UnnecessaryUnboxingFix extends InspectionGadgetsFix {
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message(
+ "unnecessary.unboxing.remove.quickfix");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ public void doFix(Project project, ProblemDescriptor descriptor)
+ throws IncorrectOperationException {
+ final PsiMethodCallExpression methodCall =
+ (PsiMethodCallExpression)descriptor.getPsiElement();
+ final PsiReferenceExpression methodExpression =
+ methodCall.getMethodExpression();
+ final PsiExpression qualifier =
+ methodExpression.getQualifierExpression();
+ final PsiExpression strippedQualifier =
+ ParenthesesUtils.stripParentheses(qualifier);
+ if (strippedQualifier == null) {
+ return;
+ }
+ if (strippedQualifier instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)strippedQualifier;
+ final PsiElement element = referenceExpression.resolve();
+ if (element instanceof PsiField) {
+ final PsiField field = (PsiField)element;
+ final PsiClass containingClass = field.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final String classname = containingClass.getQualifiedName();
+ if (CommonClassNames.JAVA_LANG_BOOLEAN.equals(classname)) {
+ @NonNls final String name = field.getName();
+ if ("TRUE".equals(name)) {
+ replaceExpression(methodCall, "true");
+ return;
+ }
+ else if ("FALSE".equals(name)) {
+ replaceExpression(methodCall, "false");
+ return;
+ }
+ }
+ }
+ }
+ final String strippedQualifierText = strippedQualifier.getText();
+ replaceExpression(methodCall, strippedQualifierText);
+ }
+ }
+
+ private static class UnnecessaryUnboxingVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(
+ @NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ if (!PsiUtil.isLanguageLevel5OrHigher(expression)) {
+ return;
+ }
+ if (!isUnboxingExpression(expression)) {
+ return;
+ }
+ final PsiExpression containingExpression =
+ getContainingExpression(expression);
+ if (containingExpression instanceof PsiTypeCastExpression) {
+ return;
+ }
+ if (isPossibleObjectComparison(expression, containingExpression)) {
+ return;
+ }
+ if (containingExpression instanceof PsiConditionalExpression) {
+ final PsiConditionalExpression conditionalExpression =
+ (PsiConditionalExpression)containingExpression;
+ final PsiExpression thenExpression =
+ conditionalExpression.getThenExpression();
+ if (thenExpression == null) {
+ return;
+ }
+ final PsiExpression elseExpression =
+ conditionalExpression.getElseExpression();
+ if (elseExpression == null) {
+ return;
+ }
+ if (PsiTreeUtil.isAncestor(thenExpression, expression, false)) {
+ final PsiType type = elseExpression.getType();
+ if (!(type instanceof PsiPrimitiveType)) {
+ return;
+ }
+ }
+ else if (PsiTreeUtil.isAncestor(elseExpression, expression,
+ false)) {
+ final PsiType type = thenExpression.getType();
+ if (!(type instanceof PsiPrimitiveType)) {
+ return;
+ }
+ }
+ }
+ else if (containingExpression instanceof PsiCallExpression) {
+ final PsiCallExpression methodCallExpression =
+ (PsiCallExpression)containingExpression;
+ if (!isSameMethodCalledWithoutUnboxing(methodCallExpression,
+ expression)) {
+ return;
+ }
+ }
+ registerError(expression);
+ }
+
+ private static boolean isPossibleObjectComparison(
+ PsiMethodCallExpression expression,
+ PsiExpression containingExpression) {
+ if (!(containingExpression instanceof PsiBinaryExpression)) {
+ return false;
+ }
+ final PsiBinaryExpression binaryExpression =
+ (PsiBinaryExpression)containingExpression;
+ if (!ComparisonUtils.isEqualityComparison(binaryExpression)) {
+ return false;
+ }
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ if (rhs == null) {
+ return true;
+ }
+ if (expression == lhs) {
+ if (!(rhs.getType() instanceof PsiPrimitiveType) ||
+ isUnboxingExpression(rhs)) {
+ return true;
+ }
+ }
+ if (expression == rhs) {
+ if (!(lhs.getType() instanceof PsiPrimitiveType) ||
+ isUnboxingExpression(lhs)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isUnboxingExpression(
+ PsiExpression expression) {
+ if (!(expression instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression methodCallExpression =
+ (PsiMethodCallExpression)expression;
+ final PsiReferenceExpression methodExpression =
+ methodCallExpression.getMethodExpression();
+ final PsiExpression qualifier =
+ methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return false;
+ }
+ final PsiType qualifierType = qualifier.getType();
+ if (qualifierType == null) {
+ return false;
+ }
+ final String qualifierTypeName = qualifierType.getCanonicalText();
+ if (!s_unboxingMethods.containsKey(qualifierTypeName)) {
+ return false;
+ }
+ final String methodName = methodExpression.getReferenceName();
+ final String unboxingMethod =
+ s_unboxingMethods.get(qualifierTypeName);
+ return unboxingMethod.equals(methodName);
+ }
+
+ private static boolean isSameMethodCalledWithoutUnboxing(
+ @NotNull PsiCallExpression callExpression,
+ @NotNull PsiMethodCallExpression unboxingExpression) {
+ final PsiExpressionList argumentList =
+ callExpression.getArgumentList();
+ if (argumentList == null) {
+ return false;
+ }
+ final PsiExpression[] expressions = argumentList.getExpressions();
+ final PsiMethod originalMethod =
+ callExpression.resolveMethod();
+ if (originalMethod == null) {
+ return false;
+ }
+ final String name = originalMethod.getName();
+ final PsiClass containingClass =
+ originalMethod.getContainingClass();
+ if (containingClass == null) {
+ return false;
+ }
+ final PsiType[] types = new PsiType[expressions.length];
+ for (int i = 0; i < expressions.length; i++) {
+ final PsiExpression expression = expressions[i];
+ final PsiType type = expression.getType();
+ if (unboxingExpression.equals(expression)) {
+ if (!(type instanceof PsiPrimitiveType)) {
+ return false;
+ }
+ final PsiPrimitiveType primitiveType =
+ (PsiPrimitiveType)type;
+ types[i] = primitiveType.getBoxedType(unboxingExpression);
+ }
+ else {
+ types[i] = type;
+ }
+ }
+ final PsiMethod[] methods =
+ containingClass.findMethodsByName(name, true);
+ for (PsiMethod method : methods) {
+ if (!originalMethod.equals(method)) {
+ if (MethodCallUtils.isApplicable(method,
+ PsiSubstitutor.EMPTY, types)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Nullable
+ private static PsiExpression getContainingExpression(
+ @NotNull PsiElement expression) {
+ final PsiElement parent = expression.getParent();
+ if (parent == null || !(parent instanceof PsiExpression) &&
+ !(parent instanceof PsiExpressionList)) {
+ return null;
+ }
+ if (parent instanceof PsiParenthesizedExpression ||
+ parent instanceof PsiExpressionList) {
+ return getContainingExpression(parent);
+ }
+ else {
+ return (PsiExpression)parent;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java
new file mode 100644
index 000000000000..50ade6b36a09
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.migration;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TypeUtils;
+import com.siyeh.ig.psiutils.VariableAccessUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class WhileCanBeForeachInspectionBase extends BaseInspection {
+ @Nullable
+ public static PsiStatement getPreviousStatement(PsiElement context) {
+ final PsiElement prevStatement = PsiTreeUtil.skipSiblingsBackward(context, PsiWhiteSpace.class, PsiComment.class);
+ if (!(prevStatement instanceof PsiStatement)) {
+ return null;
+ }
+ return (PsiStatement)prevStatement;
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "WhileLoopReplaceableByForEach";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("while.can.be.foreach.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("while.can.be.foreach.problem.descriptor");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new WhileCanBeForeachVisitor();
+ }
+
+ private static class WhileCanBeForeachVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitWhileStatement(@NotNull PsiWhileStatement whileStatement) {
+ super.visitWhileStatement(whileStatement);
+ if (!PsiUtil.isLanguageLevel5OrHigher(whileStatement)) {
+ return;
+ }
+ if (!isCollectionLoopStatement(whileStatement)) {
+ return;
+ }
+ registerStatementError(whileStatement);
+ }
+
+ private static boolean isCollectionLoopStatement(PsiWhileStatement whileStatement) {
+ final PsiStatement initialization = getPreviousStatement(whileStatement);
+ if (!(initialization instanceof PsiDeclarationStatement)) {
+ return false;
+ }
+ final PsiDeclarationStatement declaration = (PsiDeclarationStatement)initialization;
+ final PsiElement[] declaredElements = declaration.getDeclaredElements();
+ if (declaredElements.length != 1) {
+ return false;
+ }
+ final PsiElement declaredElement = declaredElements[0];
+ if (!(declaredElement instanceof PsiVariable)) {
+ return false;
+ }
+ final PsiVariable variable = (PsiVariable)declaredElement;
+ if (!TypeUtils.variableHasTypeOrSubtype(variable, CommonClassNames.JAVA_UTIL_ITERATOR, "java.util.ListIterator")) {
+ return false;
+ }
+ final PsiExpression initialValue = variable.getInitializer();
+ if (initialValue == null) {
+ return false;
+ }
+ if (!(initialValue instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression initialCall = (PsiMethodCallExpression)initialValue;
+ final PsiExpressionList argumentList = initialCall.getArgumentList();
+ final PsiExpression[] argument = argumentList.getExpressions();
+ if (argument.length != 0) {
+ return false;
+ }
+ final PsiReferenceExpression initialMethodExpression = initialCall.getMethodExpression();
+ @NonNls final String initialCallName = initialMethodExpression.getReferenceName();
+ if (!"iterator".equals(initialCallName) && !"listIterator".equals(initialCallName)) {
+ return false;
+ }
+ final PsiExpression qualifier = initialMethodExpression.getQualifierExpression();
+ if (qualifier instanceof PsiSuperExpression) {
+ return false;
+ }
+ final PsiClass qualifierClass;
+ if (qualifier != null) {
+ final PsiType qualifierType = qualifier.getType();
+ if (!(qualifierType instanceof PsiClassType)) {
+ return false;
+ }
+ qualifierClass = ((PsiClassType)qualifierType).resolve();
+ }
+ else {
+ qualifierClass = PsiTreeUtil.getParentOfType(whileStatement, PsiClass.class);
+ }
+ if (qualifierClass == null) {
+ return false;
+ }
+ if (!InheritanceUtil.isInheritor(qualifierClass, CommonClassNames.JAVA_LANG_ITERABLE)) {
+ return false;
+ }
+ final PsiExpression condition = whileStatement.getCondition();
+ if (!isHasNextCalled(variable, condition)) {
+ return false;
+ }
+ final PsiStatement body = whileStatement.getBody();
+ if (body == null) {
+ return false;
+ }
+ if (calculateCallsToIteratorNext(variable, body) != 1) {
+ return false;
+ }
+ if (isIteratorRemoveCalled(variable, body)) {
+ return false;
+ }
+ //noinspection SimplifiableIfStatement
+ if (isIteratorHasNextCalled(variable, body)) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsAssigned(variable, body)) {
+ return false;
+ }
+ if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, body)) {
+ return false;
+ }
+ PsiElement nextSibling = whileStatement.getNextSibling();
+ while (nextSibling != null) {
+ if (VariableAccessUtils.variableValueIsUsed(variable, nextSibling)) {
+ return false;
+ }
+ nextSibling = nextSibling.getNextSibling();
+ }
+ return true;
+ }
+
+ private static boolean isHasNextCalled(PsiVariable iterator, PsiExpression condition) {
+ if (!(condition instanceof PsiMethodCallExpression)) {
+ return false;
+ }
+ final PsiMethodCallExpression call = (PsiMethodCallExpression)condition;
+ final PsiExpressionList argumentList = call.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 0) {
+ return false;
+ }
+ final PsiReferenceExpression methodExpression = call.getMethodExpression();
+ @NonNls final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.HAS_NEXT.equals(methodName)) {
+ return false;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (qualifier == null) {
+ return true;
+ }
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ return iterator.equals(target);
+ }
+
+ private static int calculateCallsToIteratorNext(PsiVariable iterator, PsiElement context) {
+ final NumberCallsToIteratorNextVisitor visitor = new NumberCallsToIteratorNextVisitor(iterator);
+ context.accept(visitor);
+ return visitor.getNumCallsToIteratorNext();
+ }
+
+ private static boolean isIteratorRemoveCalled(PsiVariable iterator, PsiElement context) {
+ final IteratorMethodCallVisitor visitor = new IteratorMethodCallVisitor(iterator);
+ context.accept(visitor);
+ return visitor.isMethodCalled();
+ }
+
+ private static boolean isIteratorHasNextCalled(PsiVariable iterator, PsiElement context) {
+ final IteratorHasNextVisitor visitor = new IteratorHasNextVisitor(iterator);
+ context.accept(visitor);
+ return visitor.isHasNextCalled();
+ }
+ }
+
+ private static class NumberCallsToIteratorNextVisitor extends JavaRecursiveElementVisitor {
+
+ private int numCallsToIteratorNext = 0;
+ private final PsiVariable iterator;
+
+ private NumberCallsToIteratorNextVisitor(PsiVariable iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression callExpression) {
+ super.visitMethodCallExpression(callExpression);
+ final PsiReferenceExpression methodExpression = callExpression.getMethodExpression();
+ @NonNls final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.NEXT.equals(methodName)) {
+ return;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (!iterator.equals(target)) {
+ return;
+ }
+ numCallsToIteratorNext++;
+ }
+
+ public int getNumCallsToIteratorNext() {
+ return numCallsToIteratorNext;
+ }
+ }
+
+ private static class IteratorMethodCallVisitor extends JavaRecursiveElementVisitor {
+
+ private boolean methodCalled = false;
+ private final PsiVariable iterator;
+
+ IteratorMethodCallVisitor(PsiVariable iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (!methodCalled) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ if (methodCalled) {
+ return;
+ }
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String name = methodExpression.getReferenceName();
+ if (HardcodedMethodConstants.NEXT.equals(name)) {
+ return;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (iterator.equals(target)) {
+ methodCalled = true;
+ }
+ }
+
+ public boolean isMethodCalled() {
+ return methodCalled;
+ }
+ }
+
+ private static class IteratorHasNextVisitor extends JavaRecursiveElementVisitor {
+
+ private boolean hasNextCalled = false;
+ private final PsiVariable iterator;
+
+ private IteratorHasNextVisitor(PsiVariable iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public void visitElement(@NotNull PsiElement element) {
+ if (!hasNextCalled) {
+ super.visitElement(element);
+ }
+ }
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ @NonNls final String name = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.HAS_NEXT.equals(name)) {
+ return;
+ }
+ final PsiExpression qualifier = methodExpression.getQualifierExpression();
+ if (!(qualifier instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
+ final PsiElement target = referenceExpression.resolve();
+ if (iterator.equals(target)) {
+ hasNextCalled = true;
+ }
+ }
+
+ public boolean isHasNextCalled() {
+ return hasNextCalled;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/AnnotationNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/AnnotationNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..2df5cac1c55d
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/AnnotationNamingConventionInspectionBase.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class AnnotationNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 8;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "annotation.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String annotationName = (String)infos[0];
+ if (annotationName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "annotation.naming.convention.problem.descriptor.short");
+ }
+ else if (annotationName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "annotation.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "annotation.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (!aClass.isAnnotationType()) {
+ return;
+ }
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerClassError(aClass, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/BooleanMethodNameMustStartWithQuestionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/BooleanMethodNameMustStartWithQuestionInspectionBase.java
new file mode 100644
index 000000000000..d0ce6de63884
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/BooleanMethodNameMustStartWithQuestionInspectionBase.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiType;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.LibraryUtil;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BooleanMethodNameMustStartWithQuestionInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreBooleanMethods = false;
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreInAnnotationInterface = true;
+ @SuppressWarnings({"PublicField"})
+ public boolean onlyWarnOnBaseMethods = true;
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls public String questionString = "is,can,has,should,could,will,shall,check,contains,equals,add,put,remove,startsWith,endsWith";List<String>
+ questionList = new ArrayList(32);
+
+ public BooleanMethodNameMustStartWithQuestionInspectionBase() {
+ parseString(questionString, questionList);
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("boolean.method.name.must.start.with.question.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("boolean.method.name.must.start.with.question.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(questionString, questionList);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ questionString = formatString(questionList);
+ super.writeSettings(element);
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BooleanMethodNameMustStartWithQuestionVisitor();
+ }
+
+ private class BooleanMethodNameMustStartWithQuestionVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ final PsiType returnType = method.getReturnType();
+ if (returnType == null) {
+ return;
+ }
+ else if (!returnType.equals(PsiType.BOOLEAN)) {
+ if (ignoreBooleanMethods || !returnType.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN)) {
+ return;
+ }
+ }
+ if (ignoreInAnnotationInterface) {
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass != null && containingClass.isAnnotationType()) {
+ return;
+ }
+ }
+ final String name = method.getName();
+ for (String question : questionList) {
+ if (name.startsWith(question)) {
+ return;
+ }
+ }
+ if (onlyWarnOnBaseMethods) {
+ if (MethodUtils.hasSuper(method)) {
+ return;
+ }
+ }
+ else if (LibraryUtil.isOverrideOfLibraryMethod(method)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspectionBase.java
new file mode 100644
index 000000000000..f381faaa74d5
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspectionBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.StringTokenizer;
+
+public class ClassNamePrefixedWithPackageNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "class.name.prefixed.with.package.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "class.name.prefixed.with.package.name.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassNameBePrefixedWithPackageNameVisitor();
+ }
+
+ private static class ClassNameBePrefixedWithPackageNameVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down into inner classes
+ final String className = aClass.getName();
+ if (className == null) {
+ return;
+ }
+ final PsiClass outerClass =
+ ClassUtils.getOutermostContainingClass(aClass);
+ final String qualifiedName = outerClass.getQualifiedName();
+ if (qualifiedName == null) {
+ return;
+ }
+ if (className.equals(qualifiedName)) {
+ return;
+ }
+ final StringTokenizer tokenizer =
+ new StringTokenizer(qualifiedName, ".");
+ String currentPackageName = null;
+ String lastPackageName = null;
+ while (tokenizer.hasMoreTokens()) {
+ lastPackageName = currentPackageName;
+ currentPackageName = tokenizer.nextToken();
+ }
+ if (lastPackageName == null) {
+ return;
+ }
+ final String lowercaseClassName = className.toLowerCase();
+ final String lowercasePackageName = lastPackageName.toLowerCase();
+ if (!lowercaseClassName.startsWith(lowercasePackageName)) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspectionBase.java
new file mode 100644
index 000000000000..b54ae74f9799
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspectionBase.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class ClassNameSameAsAncestorNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "class.name.same.as.ancestor.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "class.name.same.as.ancestor.name.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ClassNameSameAsAncestorNameVisitor();
+ }
+
+ private static class ClassNameSameAsAncestorNameVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down into inner classes
+ final String className = aClass.getName();
+ if (className == null) {
+ return;
+ }
+ final Set<PsiClass> alreadyVisited = new HashSet<PsiClass>(8);
+ final PsiClass[] supers = aClass.getSupers();
+ for (final PsiClass aSuper : supers) {
+ if (hasMatchingName(aSuper, className, alreadyVisited)) {
+ registerClassError(aClass);
+ }
+ }
+ }
+
+ private static boolean hasMatchingName(PsiClass aSuper,
+ String className,
+ Set<PsiClass> alreadyVisited) {
+ if (aSuper == null) {
+ return false;
+ }
+ if (alreadyVisited.contains(aSuper)) {
+ return false;
+ }
+ alreadyVisited.add(aSuper);
+ final String superName = aSuper.getName();
+ if (className.equals(superName)) {
+ return true;
+ }
+ final PsiClass[] supers = aSuper.getSupers();
+ for (PsiClass aSupers : supers) {
+ if (hasMatchingName(aSupers, className, alreadyVisited)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..ede181d76220
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ClassNamingConventionInspectionBase.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiTypeParameter;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class ClassNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 8;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "class.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String className = (String)infos[0];
+ if (className.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "class.name.convention.problem.descriptor.short");
+ }
+ else if (className.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "class.name.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "class.name.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isAnnotationType() ||
+ aClass.isEnum()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerClassError(aClass, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConfusingMainMethodInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConfusingMainMethodInspectionBase.java
new file mode 100644
index 000000000000..5cddcb5615ae
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConfusingMainMethodInspectionBase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.*;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TypeUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ConfusingMainMethodInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "confusing.main.method.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "confusing.main.method.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ConfusingMainMethodVisitor();
+ }
+
+ private static class ConfusingMainMethodVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod aMethod) {
+ // no call to super, so it doesn't drill down into inner classes
+ final String methodName = aMethod.getName();
+ if (!HardcodedMethodConstants.MAIN.equals(methodName)) {
+ return;
+ }
+ if (!aMethod.hasModifierProperty(PsiModifier.PUBLIC)) {
+ registerMethodError(aMethod);
+ return;
+ }
+ if (!aMethod.hasModifierProperty(PsiModifier.STATIC)) {
+ registerMethodError(aMethod);
+ return;
+ }
+ final PsiType returnType = aMethod.getReturnType();
+
+ if (!TypeUtils.typeEquals(PsiKeyword.VOID, returnType)) {
+ registerMethodError(aMethod);
+ return;
+ }
+ final PsiParameterList parameterList = aMethod.getParameterList();
+ if (parameterList.getParametersCount() != 1) {
+ registerMethodError(aMethod);
+ return;
+ }
+ final PsiParameter[] parameters = parameterList.getParameters();
+ final PsiType parameterType = parameters[0].getType();
+ if (!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING + "[]",
+ parameterType)) {
+ registerMethodError(aMethod);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConstantNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConstantNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..3ae903515ab6
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConstantNamingConventionInspectionBase.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiEnumConstant;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiType;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ConstantNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 5;
+ private static final int DEFAULT_MAX_LENGTH = 32;
+ @SuppressWarnings({"PublicField"})
+ public boolean onlyCheckImmutables = false;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "constant.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String fieldName = (String)infos[0];
+ if (fieldName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message("constant.naming.convention.problem.descriptor.short");
+ }
+ else if (fieldName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message("constant.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message("constant.naming.convention.problem.descriptor.regex.mismatch", getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Z_\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ super.visitField(field);
+ if (field instanceof PsiEnumConstant) {
+ return;
+ }
+ if (!field.hasModifierProperty(PsiModifier.STATIC) || !field.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ final String name = field.getName();
+ if (name == null) {
+ return;
+ }
+ final PsiType type = field.getType();
+ if (onlyCheckImmutables && !ClassUtils.isImmutable(type)) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerFieldError(field, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConventionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConventionInspection.java
new file mode 100644
index 000000000000..7afacaf647fd
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ConventionInspection.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.codeInspection.ui.ConventionOptionsPanel;
+import com.intellij.openapi.util.InvalidDataException;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.ig.BaseInspection;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class ConventionInspection extends BaseInspection {
+
+ public static final JComponent[] EMPTY_JCOMPONENT_ARRAY = {};
+ /**
+ * @noinspection PublicField
+ */
+ public String m_regex = getDefaultRegex();
+ /**
+ * @noinspection PublicField
+ */
+ public int m_minLength = getDefaultMinLength();
+ /**
+ * @noinspection PublicField
+ */
+ public int m_maxLength = getDefaultMaxLength();
+
+ protected Pattern m_regexPattern = Pattern.compile(m_regex);
+
+ @NonNls
+ protected abstract String getDefaultRegex();
+
+ protected abstract int getDefaultMinLength();
+
+ protected abstract int getDefaultMaxLength();
+
+ protected String getRegex() {
+ return m_regex;
+ }
+
+ protected int getMinLength() {
+ return m_minLength;
+ }
+
+ protected int getMaxLength() {
+ return m_maxLength;
+ }
+
+ protected boolean isValid(String name) {
+ final int length = name.length();
+ if (length < m_minLength) {
+ return false;
+ }
+ if (m_maxLength > 0 && length > m_maxLength) {
+ return false;
+ }
+ if (HardcodedMethodConstants.SERIAL_VERSION_UID.equals(name)) {
+ return true;
+ }
+ final Matcher matcher = m_regexPattern.matcher(name);
+ return matcher.matches();
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ m_regexPattern = Pattern.compile(m_regex);
+ }
+
+ public JComponent[] createExtraOptions() {
+ return EMPTY_JCOMPONENT_ARRAY;
+ }
+
+ @Override
+ public final JComponent createOptionsPanel() {
+ return new ConventionOptionsPanel(this, "m_minLength", "m_maxLength", "m_regex", "m_regexPattern", createExtraOptions());
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/DollarSignInNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/DollarSignInNameInspectionBase.java
new file mode 100644
index 000000000000..7287dc5fa21b
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/DollarSignInNameInspectionBase.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiVariable;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class DollarSignInNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "dollar.sign.in.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "dollar.sign.in.name.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new DollarSignInNameVisitor();
+ }
+
+ private static class DollarSignInNameVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitVariable(@NotNull PsiVariable variable) {
+ super.visitVariable(variable);
+ final String name = variable.getName();
+ if (name == null) {
+ return;
+ }
+ if (name.indexOf((int)'$') < 0) {
+ return;
+ }
+ registerVariableError(variable);
+ }
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ final String name = method.getName();
+ if (name.indexOf((int)'$') < 0) {
+ return;
+ }
+ registerMethodError(method);
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ //note: no call to super, to avoid drill-down
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (name.indexOf((int)'$') < 0) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedClassNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedClassNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..09cb8e6b338f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedClassNamingConventionInspectionBase.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class EnumeratedClassNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 8;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "enumerated.class.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String className = (String)infos[0];
+ if (className.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "enumerated.class.naming.convention.problem.descriptor.short");
+ }
+ else if (className.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "enumerated.class.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "enumerated.class.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (!aClass.isEnum()) {
+ return;
+ }
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerClassError(aClass, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedConstantNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedConstantNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..5cb0ba9fc3dd
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/EnumeratedConstantNamingConventionInspectionBase.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiEnumConstant;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class EnumeratedConstantNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 5;
+ private static final int DEFAULT_MAX_LENGTH = 32;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("enumerated.constant.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String fieldName = (String)infos[0];
+ if (fieldName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message("enumerated.constant.naming.convention.problem.descriptor.short");
+ }
+ else if (fieldName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message("enumerated.constant.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message("enumerated.constant.naming.convention.problem.descriptor.regex.mismatch", getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Z_\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitEnumConstant(PsiEnumConstant constant) {
+ super.visitEnumConstant(constant);
+ final String name = constant.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerFieldError(constant, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspectionBase.java
new file mode 100644
index 000000000000..f4cf0a4e57b0
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspectionBase.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiTypeParameter;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class ExceptionNameDoesntEndWithExceptionInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "ExceptionClassNameDoesntEndWithException";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "exception.name.doesnt.end.with.exception.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "exception.name.doesnt.end.with.exception.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ExceptionNameDoesntEndWithExceptionVisitor();
+ }
+
+ private static class ExceptionNameDoesntEndWithExceptionVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down into inner classes
+ if (aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ final String className = aClass.getName();
+ if (className == null) {
+ return;
+ }
+ @NonNls final String exception = "Exception";
+ if (className.endsWith(exception)) {
+ return;
+ }
+ if (!InheritanceUtil.isInheritor(aClass,
+ CommonClassNames.JAVA_LANG_EXCEPTION)) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..9f1e86052986
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiIdentifier;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.LibraryUtil;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class InstanceMethodNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 4;
+ private static final int DEFAULT_MAX_LENGTH = 32;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("instance.method.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String methodName = (String)infos[0];
+ if (methodName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message("instance.method.name.convention.problem.descriptor.short");
+ }
+ else if (methodName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message("instance.method.name.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message("instance.method.name.convention.problem.descriptor.regex.mismatch", getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[a-z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final PsiIdentifier nameIdentifier = method.getNameIdentifier();
+ if (nameIdentifier == null) {
+ return;
+ }
+ final String name = method.getName();
+ if (isValid(name)) {
+ return;
+ }
+ if (!isOnTheFly()) {
+ if (MethodUtils.hasSuper(method)) {
+ return;
+ }
+ }
+ if (LibraryUtil.isOverrideOfLibraryMethod(method)) {
+ return;
+ }
+ registerMethodError(method, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..53cac98431a3
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspectionBase.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class InstanceVariableNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 5;
+ private static final int DEFAULT_MAX_LENGTH = 32;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "instance.variable.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String fieldName = (String)infos[0];
+ if (fieldName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "instance.variable.name.convention.problem.descriptor.short");
+ }
+ else if (fieldName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "instance.variable.name.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "instance.variable.name.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "m_[a-z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ super.visitField(field);
+ if (field.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final String name = field.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerFieldError(field, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InterfaceNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InterfaceNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..9a1049fc3f5e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InterfaceNamingConventionInspectionBase.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class InterfaceNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 8;
+ private static final int DEFAULT_MAX_LENGTH = 64;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "interface.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String interfaceName = (String)infos[0];
+ if (interfaceName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "interface.name.convention.problem.descriptor.short");
+ }
+ else if (interfaceName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "interface.name.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "interface.name.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (!aClass.isInterface() || aClass.isAnnotationType()) {
+ return;
+ }
+ final String name = aClass.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerClassError(aClass, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..5f4f13ee4c3c
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspectionBase.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class LocalVariableNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 1;
+ private static final int DEFAULT_MAX_LENGTH = 20;
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreForLoopParameters = false;
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreCatchParameters = false;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("local.variable.naming.convention.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String varName = (String)infos[0];
+ if (varName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message("local.variable.naming.convention.problem.descriptor.short");
+ }
+ else if (varName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message("local.variable.naming.convention.problem.descriptor.long");
+ }
+ else {
+ return InspectionGadgetsBundle.message("local.variable.naming.convention.problem.descriptor.regex.mismatch", getRegex());
+ }
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[a-z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitLocalVariable(@NotNull PsiLocalVariable variable) {
+ super.visitLocalVariable(variable);
+ if (m_ignoreForLoopParameters) {
+ final PsiElement parent = variable.getParent();
+ if (parent != null) {
+ final PsiElement grandparent = parent.getParent();
+ if (grandparent instanceof PsiForStatement) {
+ final PsiForStatement forLoop = (PsiForStatement)grandparent;
+ final PsiStatement initialization = forLoop.getInitialization();
+ if (parent.equals(initialization)) {
+ return;
+ }
+ }
+ }
+ }
+ final String name = variable.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerVariableError(variable, name);
+ }
+
+ @Override
+ public void visitParameter(@NotNull PsiParameter variable) {
+ final PsiElement scope = variable.getDeclarationScope();
+ final boolean isCatchParameter = scope instanceof PsiCatchSection;
+ final boolean isForeachParameter = scope instanceof PsiForeachStatement;
+ if (!isCatchParameter && !isForeachParameter) {
+ return;
+ }
+ if (m_ignoreCatchParameters && isCatchParameter) {
+ return;
+ }
+ if (m_ignoreForLoopParameters && isForeachParameter) {
+ return;
+ }
+ final String name = variable.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerVariableError(variable, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspectionBase.java
new file mode 100644
index 000000000000..e5bcd718a1ad
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspectionBase.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class MethodNameSameAsClassNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "method.name.same.as.class.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "method.name.same.as.class.name.problem.descriptor");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MethodNameSameAsClassNameVisitor();
+ }
+
+ private static class MethodNameSameAsClassNameVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ // no call to super, so it doesn't drill down into inner classes
+ if (method.isConstructor()) {
+ return;
+ }
+ final String methodName = method.getName();
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final String className = containingClass.getName();
+ if (className == null) {
+ return;
+ }
+ if (!methodName.equals(className)) {
+ return;
+ }
+ registerMethodError(method, Boolean.valueOf(isOnTheFly()));
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspectionBase.java
new file mode 100644
index 000000000000..7ac137c5444e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspectionBase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class MethodNameSameAsParentNameInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "method.name.same.as.parent.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "method.name.same.as.parent.name.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MethodNameSameAsParentClassNameVisitor();
+ }
+
+ private static class MethodNameSameAsParentClassNameVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ // no call to super, so it doesn't drill down into inner classes
+ if (method.isConstructor()) {
+ return;
+ }
+ if (method.getNameIdentifier() == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final PsiClass parent = containingClass.getSuperClass();
+ if (parent == null) {
+ return;
+ }
+ final String parentName = parent.getName();
+ if (parentName == null) {
+ return;
+ }
+ final String methodName = method.getName();
+ if (!methodName.equals(parentName)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNamesDifferOnlyByCaseInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNamesDifferOnlyByCaseInspectionBase.java
new file mode 100644
index 000000000000..4fa3b520bc2e
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/MethodNamesDifferOnlyByCaseInspectionBase.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiIdentifier;
+import com.intellij.psi.PsiMethod;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class MethodNamesDifferOnlyByCaseInspectionBase extends BaseInspection {
+ @SuppressWarnings("PublicField")
+ public boolean ignoreIfMethodIsOverride = true;
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "MethodNamesDifferingOnlyByCase";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("method.names.differ.only.by.case.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("method.names.differ.only.by.case.problem.descriptor", infos[0]);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new MethodNamesDifferOnlyByCaseVisitor();
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ private class MethodNamesDifferOnlyByCaseVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ if (method.isConstructor()) {
+ return;
+ }
+ final PsiIdentifier nameIdentifier = method.getNameIdentifier();
+ if (nameIdentifier == null) {
+ return;
+ }
+ final String methodName = method.getName();
+ if (ignoreIfMethodIsOverride && MethodUtils.hasSuper(method)) {
+ return;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ final PsiMethod[] methods = aClass.getAllMethods();
+ for (PsiMethod testMethod : methods) {
+ final String testMethodName = testMethod.getName();
+ if (!methodName.equals(testMethodName) && methodName.equalsIgnoreCase(testMethodName)) {
+ registerError(nameIdentifier, testMethodName);
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonBooleanMethodNameMayNotStartWithQuestionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonBooleanMethodNameMayNotStartWithQuestionInspectionBase.java
new file mode 100644
index 000000000000..80d9fbb7fc1f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonBooleanMethodNameMayNotStartWithQuestionInspectionBase.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiType;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.LibraryUtil;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NonBooleanMethodNameMayNotStartWithQuestionInspectionBase extends BaseInspection {
+ public NonBooleanMethodNameMayNotStartWithQuestionInspectionBase() {
+ parseString(questionString, questionList);
+ }
+
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls public String questionString = "is,can,has,should,could,will,shall,check,contains,equals,startsWith,endsWith";
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreBooleanMethods = false;
+ @SuppressWarnings({"PublicField"})
+ public boolean onlyWarnOnBaseMethods = true;List<String> questionList = new ArrayList(32);
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("non.boolean.method.name.must.not.start.with.question.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("non.boolean.method.name.must.not.start.with.question.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(questionString, questionList);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ questionString = formatString(questionList);
+ super.writeSettings(element);
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NonBooleanMethodNameMayNotStartWithQuestionVisitor();
+ }
+
+ private class NonBooleanMethodNameMayNotStartWithQuestionVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ final PsiType returnType = method.getReturnType();
+ if (returnType == null || returnType.equals(PsiType.BOOLEAN)) {
+ return;
+ }
+ if (ignoreBooleanMethods && returnType.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN)) {
+ return;
+ }
+ final String name = method.getName();
+ boolean startsWithQuestionWord = false;
+ for (String question : questionList) {
+ if (name.startsWith(question)) {
+ if (name.length() == question.length()) {
+ startsWithQuestionWord = true;
+ break;
+ }
+ final char nextChar = name.charAt(question.length());
+ if (Character.isUpperCase(nextChar) || nextChar == '_') {
+ startsWithQuestionWord = true;
+ break;
+ }
+ }
+ }
+ if (!startsWithQuestionWord) {
+ return;
+ }
+ if (onlyWarnOnBaseMethods) {
+ if (MethodUtils.hasSuper(method)) {
+ return;
+ }
+ }
+ else if (LibraryUtil.isOverrideOfLibraryMethod(method)) {
+ return;
+ }
+ registerMethodError(method);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspectionBase.java
new file mode 100644
index 000000000000..7dfd0199605a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspectionBase.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class NonExceptionNameEndsWithExceptionInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "non.exception.name.ends.with.exception.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "non.exception.name.ends.with.exception.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NonExceptionNameEndsWithExceptionVisitor();
+ }
+
+ private static class NonExceptionNameEndsWithExceptionVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down into inner classes
+ final String className = aClass.getName();
+ if (className == null) {
+ return;
+ }
+ @NonNls final String exception = "Exception";
+ if (!className.endsWith(exception)) {
+ return;
+ }
+ if (InheritanceUtil.isInheritor(aClass,
+ CommonClassNames.JAVA_LANG_EXCEPTION)) {
+ return;
+ }
+ registerClassError(aClass, className,
+ Boolean.valueOf(isOnTheFly()));
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedMethodsWithSameNumberOfParametersInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedMethodsWithSameNumberOfParametersInspection.java
new file mode 100644
index 000000000000..b3efd217b8a4
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedMethodsWithSameNumberOfParametersInspection.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.MethodUtils;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class OverloadedMethodsWithSameNumberOfParametersInspection extends BaseInspection {
+
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreInconvertibleTypes = true;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("overloaded.methods.with.same.number.parameters.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("overloaded.methods.with.same.number.parameters.problem.descriptor");
+ }
+
+ @Override
+ public JComponent createOptionsPanel() {
+ return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message(
+ "overloaded.methods.with.same.number.parameters.option"), this, "ignoreInconvertibleTypes");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new OverloadedMethodsWithSameNumberOfParametersVisitor();
+ }
+
+ private class OverloadedMethodsWithSameNumberOfParametersVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ if (method.isConstructor()) {
+ return;
+ }
+ if (method.getNameIdentifier() == null) {
+ return;
+ }
+ final PsiParameterList parameterList = method.getParameterList();
+ final int parameterCount = parameterList.getParametersCount();
+ if (parameterCount == 0) {
+ return;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ if (MethodUtils.hasSuper(method)) {
+ return;
+ }
+ final String methodName = method.getName();
+ final PsiMethod[] sameNameMethods = aClass.findMethodsByName(methodName, false);
+ for (PsiMethod sameNameMethod : sameNameMethods) {
+ if (method.equals(sameNameMethod)) {
+ continue;
+ }
+ final PsiParameterList otherParameterList = sameNameMethod.getParameterList();
+ if (parameterCount == otherParameterList.getParametersCount()) {
+ if (ignoreInconvertibleTypes && !areParameterTypesConvertible(parameterList, otherParameterList)) {
+ return;
+ }
+ registerMethodError(method);
+ return;
+ }
+ }
+ }
+
+ private boolean areParameterTypesConvertible(PsiParameterList parameterList, PsiParameterList otherParameterList) {
+ final PsiParameter[] parameters = parameterList.getParameters();
+ final PsiParameter[] otherParameters = otherParameterList.getParameters();
+ for (int i = 0; i < parameters.length; i++) {
+ final PsiType type = parameters[i].getType();
+ final PsiType otherType = otherParameters[i].getType();
+ if (!type.isAssignableFrom(otherType) && !otherType.isAssignableFrom(type)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java
new file mode 100644
index 000000000000..8be3f7e20d3f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2006-2007 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class OverloadedVarargsMethodInspection extends BaseInspection {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "overloaded.vararg.method.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final PsiMethod element = (PsiMethod)infos[0];
+ if (element.isConstructor()) {
+ return InspectionGadgetsBundle.message(
+ "overloaded.vararg.constructor.problem.descriptor");
+ }
+ else {
+ return InspectionGadgetsBundle.message(
+ "overloaded.vararg.method.problem.descriptor");
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new OverloadedVarargMethodVisitor();
+ }
+
+ private static class OverloadedVarargMethodVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ if (!method.isVarArgs()) {
+ return;
+ }
+ final PsiClass aClass = method.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ final String methodName = method.getName();
+ final PsiMethod[] sameNameMethods =
+ aClass.findMethodsByName(methodName, false);
+ for (PsiMethod sameNameMethod : sameNameMethods) {
+ if (!sameNameMethod.equals(method)) {
+ registerMethodError(method, method);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/PackageNamingConventionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/PackageNamingConventionInspection.java
new file mode 100644
index 000000000000..7bad29330828
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/PackageNamingConventionInspection.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.analysis.AnalysisScope;
+import com.intellij.codeInspection.CommonProblemDescriptor;
+import com.intellij.codeInspection.GlobalInspectionContext;
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.reference.RefEntity;
+import com.intellij.codeInspection.reference.RefPackage;
+import com.intellij.codeInspection.ui.ConventionOptionsPanel;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import com.intellij.psi.PsiPackageStatement;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseGlobalInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.BaseSharedLocalInspection;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PackageNamingConventionInspection extends BaseGlobalInspection {
+
+ private static final int DEFAULT_MIN_LENGTH = 3;
+ private static final int DEFAULT_MAX_LENGTH = 16;
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls
+ public String m_regex = "[a-z]*";
+
+ /**
+ * @noinspection PublicField
+ */
+ public int m_minLength = DEFAULT_MIN_LENGTH;
+
+ /**
+ * @noinspection PublicField
+ */
+ public int m_maxLength = DEFAULT_MAX_LENGTH;
+
+ protected Pattern m_regexPattern = Pattern.compile(m_regex);
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("package.naming.convention.display.name");
+ }
+
+ @Override
+ @Nullable
+ public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity, @NotNull AnalysisScope analysisScope,
+ @NotNull InspectionManager inspectionManager,
+ @NotNull GlobalInspectionContext globalInspectionContext) {
+ if (!(refEntity instanceof RefPackage)) {
+ return null;
+ }
+ @NonNls final String name = refEntity.getName();
+ if ("default package".equals(name)) {
+ return null;
+ }
+
+ final int length = name.length();
+ if (length < m_minLength) {
+ final String errorString = InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.short", name);
+ return new CommonProblemDescriptor[]{inspectionManager.createProblemDescriptor(errorString)};
+ }
+ if (length > m_maxLength) {
+ final String errorString = InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.long", name);
+ return new CommonProblemDescriptor[]{inspectionManager.createProblemDescriptor(errorString)};
+ }
+ final Matcher matcher = m_regexPattern.matcher(name);
+ if (matcher.matches()) {
+ return null;
+ }
+ else {
+ final String errorString =
+ InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.regex.mismatch", name, m_regex);
+ return new CommonProblemDescriptor[]{inspectionManager.createProblemDescriptor(errorString)};
+ }
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ m_regexPattern = Pattern.compile(m_regex);
+ }
+
+ @Override
+ public JComponent createOptionsPanel() {
+ return new ConventionOptionsPanel(this, "m_minLength", "m_maxLength", "m_regex", "m_regexPattern");
+ }
+
+ boolean isValid(String name) {
+ final int length = name.length();
+ if (length < m_minLength) {
+ return false;
+ }
+ if (m_maxLength > 0 && length > m_maxLength) {
+ return false;
+ }
+ if (HardcodedMethodConstants.SERIAL_VERSION_UID.equals(name)) {
+ return true;
+ }
+ final Matcher matcher = m_regexPattern.matcher(name);
+ return matcher.matches();
+ }
+
+ @Nullable
+ public LocalInspectionTool getSharedLocalInspectionTool() {
+ return new LocalPackageNamingConventionInspection(this);
+ }
+
+ private static class LocalPackageNamingConventionInspection extends BaseSharedLocalInspection<PackageNamingConventionInspection> {
+
+ public LocalPackageNamingConventionInspection(PackageNamingConventionInspection inspection) {
+ super(inspection);
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final String name = (String)infos[0];
+ if (name.length() < mySettingsDelegate.m_minLength) {
+ return InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.short", name);
+ }
+ else if (name.length() > mySettingsDelegate.m_maxLength) {
+ return InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.long", name);
+ }
+ else {
+ return InspectionGadgetsBundle.message("package.naming.convention.problem.descriptor.regex.mismatch",
+ name, mySettingsDelegate.m_regex);
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new BaseInspectionVisitor() {
+
+ @Override
+ public void visitPackageStatement(PsiPackageStatement statement) {
+ final PsiJavaCodeReferenceElement reference = statement.getPackageReference();
+ if (reference == null) {
+ return;
+ }
+ final String text = reference.getText();
+ int start = 0;
+ int index = text.indexOf('.', start);
+ while (index > 0) {
+ final String name = text.substring(start, index);
+ if (!mySettingsDelegate.isValid(name)) {
+ registerErrorAtOffset(reference, start, index - start, name);
+ }
+ start = index + 1;
+ index = text.indexOf('.', start);
+ }
+ final String lastName = text.substring(start);
+ if (!mySettingsDelegate.isValid(lastName)) {
+ registerErrorAtOffset(reference, start, lastName.length(), lastName);
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspectionBase.java
new file mode 100644
index 000000000000..6464e0efcd27
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspectionBase.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiParameterList;
+import com.intellij.psi.search.searches.SuperMethodsSearch;
+import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
+import com.intellij.util.Query;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.LibraryUtil;
+import org.jetbrains.annotations.NotNull;
+
+public class ParameterNameDiffersFromOverriddenParameterInspectionBase extends BaseInspection {
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreSingleCharacterNames = false;
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreOverridesOfLibraryMethods = false;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "parameter.name.differs.from.overridden.parameter.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "parameter.name.differs.from.overridden.parameter.problem.descriptor",
+ infos[0]);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ParameterNameDiffersFromOverriddenParameterVisitor();
+ }
+
+ private class ParameterNameDiffersFromOverriddenParameterVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() == 0) {
+ return;
+ }
+ final Query<MethodSignatureBackedByPsiMethod> query =
+ SuperMethodsSearch.search(
+ method, method.getContainingClass(), true, false);
+ final MethodSignatureBackedByPsiMethod methodSignature =
+ query.findFirst();
+ if (methodSignature == null) {
+ return;
+ }
+ final PsiMethod superMethod = methodSignature.getMethod();
+ final PsiParameter[] parameters = parameterList.getParameters();
+ checkParameters(superMethod, parameters);
+ }
+
+ private void checkParameters(PsiMethod superMethod,
+ PsiParameter[] parameters) {
+ if (m_ignoreOverridesOfLibraryMethods) {
+ final PsiClass containingClass =
+ superMethod.getContainingClass();
+ if (containingClass != null &&
+ LibraryUtil.classIsInLibrary(containingClass)) {
+ return;
+ }
+ }
+ final PsiParameterList superParameterList =
+ superMethod.getParameterList();
+ final PsiParameter[] superParameters =
+ superParameterList.getParameters();
+ for (int i = 0; i < parameters.length; i++) {
+ final PsiParameter parameter = parameters[i];
+ final String parameterName = parameter.getName();
+ final String superParameterName = superParameters[i].getName();
+ if (superParameterName == null) {
+ continue;
+ }
+ if (superParameterName.equals(parameterName)) {
+ continue;
+ }
+ if (m_ignoreSingleCharacterNames &&
+ superParameterName.length() == 1) {
+ continue;
+ }
+ registerVariableError(parameter, superParameterName);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..a4f1e11071cf
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/ParameterNamingConventionInspectionBase.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiCatchSection;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiForeachStatement;
+import com.intellij.psi.PsiParameter;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class ParameterNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 1;
+ private static final int DEFAULT_MAX_LENGTH = 20;
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "MethodParameterNamingConvention";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "parameter.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String parametername = (String)infos[0];
+ if (parametername.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "parameter.naming.convention.problem.descriptor.short");
+ }
+ else if (parametername.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "parameter.naming.convention.problem.descriptor.long");
+ }
+ else {
+ return InspectionGadgetsBundle.message(
+ "parameter.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[a-z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitParameter(@NotNull PsiParameter variable) {
+ final PsiElement scope = variable.getDeclarationScope();
+ if (scope instanceof PsiCatchSection ||
+ scope instanceof PsiForeachStatement) {
+ return;
+ }
+ final String name = variable.getName();
+ if (name == null || isValid(name)) {
+ return;
+ }
+ registerVariableError(variable, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/QuestionableNameInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/QuestionableNameInspectionBase.java
new file mode 100644
index 000000000000..0fae4532753a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/QuestionableNameInspectionBase.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiVariable;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class QuestionableNameInspectionBase extends BaseInspection {
+ public QuestionableNameInspectionBase() {
+ parseString(nameString, nameList);
+ }
+
+ /**
+ * @noinspection PublicField
+ */
+ @NonNls public String nameString = "aa,abc,bad,bar,bar2,baz,baz1,baz2," +
+ "baz3,bb,blah,bogus,bool,cc,dd,defau1t,dummy,dummy2,ee,fa1se," +
+ "ff,foo,foo1,foo2,foo3,foobar,four,fred,fred1,fred2,gg,hh,hello," +
+ "hello1,hello2,hello3,ii,nu11,one,silly,silly2,string,two,that," +
+ "then,three,whi1e,var";List<String> nameList = new ArrayList<String>(32);
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "questionable.name.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "questionable.name.problem.descriptor");
+ }
+
+ @Override
+ public void readSettings(@NotNull Element element) throws InvalidDataException {
+ super.readSettings(element);
+ parseString(nameString, nameList);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element element) throws WriteExternalException {
+ nameString = formatString(nameList);
+ super.writeSettings(element);
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new QuestionableNameVisitor();
+ }
+
+ private class QuestionableNameVisitor extends BaseInspectionVisitor {
+
+ private final Set<String> nameSet = new HashSet(nameList);
+
+ @Override
+ public void visitVariable(@NotNull PsiVariable variable) {
+ final String name = variable.getName();
+ if (nameSet.contains(name)) {
+ registerVariableError(variable);
+ }
+ }
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ final String name = method.getName();
+ if (nameSet.contains(name)) {
+ registerMethodError(method);
+ }
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ final String name = aClass.getName();
+ if (nameSet.contains(name)) {
+ registerClassError(aClass);
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StandardVariableNamesInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StandardVariableNamesInspectionBase.java
new file mode 100644
index 000000000000..d2dd8c60b160
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StandardVariableNamesInspectionBase.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class StandardVariableNamesInspectionBase extends BaseInspection {
+ @NonNls static final Map<String, String> s_expectedTypes =
+ new HashMap<String, String>(13);
+ @NonNls static final Map<String, String> s_boxingClasses =
+ new HashMap<String, String>(8);
+ @SuppressWarnings("PublicField")
+ public boolean ignoreParameterNameSameAsSuper = false;
+ static {
+ s_expectedTypes.put("b", "byte");
+ s_expectedTypes.put("c", "char");
+ s_expectedTypes.put("ch", "char");
+ s_expectedTypes.put("d", "double");
+ s_expectedTypes.put("f", "float");
+ s_expectedTypes.put("i", "int");
+ s_expectedTypes.put("j", "int");
+ s_expectedTypes.put("k", "int");
+ s_expectedTypes.put("m", "int");
+ s_expectedTypes.put("n", "int");
+ s_expectedTypes.put("l", "long");
+ s_expectedTypes.put("s", CommonClassNames.JAVA_LANG_STRING);
+ s_expectedTypes.put("str", CommonClassNames.JAVA_LANG_STRING);
+
+ s_boxingClasses.put("int", CommonClassNames.JAVA_LANG_INTEGER);
+ s_boxingClasses.put("short", CommonClassNames.JAVA_LANG_SHORT);
+ s_boxingClasses.put("boolean", CommonClassNames.JAVA_LANG_BOOLEAN);
+ s_boxingClasses.put("long", CommonClassNames.JAVA_LANG_LONG);
+ s_boxingClasses.put("byte", CommonClassNames.JAVA_LANG_BYTE);
+ s_boxingClasses.put("float", CommonClassNames.JAVA_LANG_FLOAT);
+ s_boxingClasses.put("double", CommonClassNames.JAVA_LANG_DOUBLE);
+ s_boxingClasses.put("char", CommonClassNames.JAVA_LANG_CHARACTER);
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "standard.variable.names.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final PsiVariable variable = (PsiVariable)infos[0];
+ final String name = variable.getName();
+ final String expectedType = s_expectedTypes.get(name);
+ if (PsiUtil.isLanguageLevel5OrHigher(variable)) {
+ final String boxedType = s_boxingClasses.get(expectedType);
+ if (boxedType != null) {
+ return InspectionGadgetsBundle.message(
+ "standard.variable.names.problem.descriptor2",
+ expectedType, boxedType);
+ }
+ }
+ return InspectionGadgetsBundle.message(
+ "standard.variable.names.problem.descriptor", expectedType);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new StandardVariableNamesVisitor();
+ }
+
+ private class StandardVariableNamesVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitVariable(@NotNull PsiVariable variable) {
+ super.visitVariable(variable);
+ final String variableName = variable.getName();
+ final String expectedType = s_expectedTypes.get(variableName);
+ if (expectedType == null) {
+ return;
+ }
+ final PsiType type = variable.getType();
+ final String typeText = type.getCanonicalText();
+ if (expectedType.equals(typeText)) {
+ return;
+ }
+ if (PsiUtil.isLanguageLevel5OrHigher(variable)) {
+ final PsiPrimitiveType unboxedType =
+ PsiPrimitiveType.getUnboxedType(type);
+ if (unboxedType != null) {
+ final String unboxedTypeText =
+ unboxedType.getCanonicalText();
+ if (expectedType.equals(unboxedTypeText)) {
+ return;
+ }
+ }
+ }
+ if (ignoreParameterNameSameAsSuper &&
+ isVariableNamedSameAsSuper(variable)) {
+ return;
+ }
+ registerVariableError(variable, variable);
+ }
+
+ private boolean isVariableNamedSameAsSuper(PsiVariable variable) {
+ if (!(variable instanceof PsiParameter)) {
+ return false;
+ }
+ final PsiParameter parameter = (PsiParameter)variable;
+ final PsiElement scope = parameter.getDeclarationScope();
+ if (!(scope instanceof PsiMethod)) {
+ return false;
+ }
+ final String variableName = variable.getName();
+ final PsiMethod method = (PsiMethod)scope;
+ final int index =
+ method.getParameterList().getParameterIndex(parameter);
+ final PsiMethod[] superMethods = method.findSuperMethods();
+ for (PsiMethod superMethod : superMethods) {
+ final PsiParameter[] parameters =
+ superMethod.getParameterList().getParameters();
+ final PsiParameter overriddenParameter = parameters[index];
+ if (variableName.equals(overriddenParameter.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..98fd3c5166cd
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class StaticMethodNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 4;
+ private static final int DEFAULT_MAX_LENGTH = 32;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "static.method.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String methodName = (String)infos[0];
+ if (methodName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "static.method.naming.convention.problem.descriptor.short");
+ }
+ else if (methodName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "static.method.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "static.method.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[a-z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethod(@NotNull PsiMethod method) {
+ super.visitMethod(method);
+ if (!method.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final String name = method.getName();
+ if (isValid(name)) {
+ return;
+ }
+ registerMethodError(method, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..55d3c6aa4279
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspectionBase.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiType;
+import com.intellij.util.ui.CheckBox;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class StaticVariableNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 5;
+ private static final int DEFAULT_MAX_LENGTH = 32;
+ @SuppressWarnings({"PublicField"})
+ public boolean checkMutableFinals = false;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("static.variable.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String fieldName = (String)infos[0];
+ if (fieldName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message("static.variable.naming.convention.problem.descriptor.short");
+ }
+ else if (fieldName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message("static.variable.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message("static.variable.naming.convention.problem.descriptor.regex.mismatch", getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "s_[a-z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public JComponent[] createExtraOptions() {
+ return new JComponent[]{
+ new CheckBox(InspectionGadgetsBundle.message("static.variable.naming.convention.mutable.option"), this, "checkMutableFinals")
+ };
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ if (!field.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ if (field.hasModifierProperty(PsiModifier.FINAL)) {
+ if (!checkMutableFinals) {
+ return;
+ }
+ else {
+ final PsiType type = field.getType();
+ if (ClassUtils.isImmutable(type)) {
+ return;
+ }
+ }
+ }
+ final String name = field.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ registerFieldError(field, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/TypeParameterNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/TypeParameterNamingConventionInspectionBase.java
new file mode 100644
index 000000000000..4d0e76be1a60
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/TypeParameterNamingConventionInspectionBase.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiIdentifier;
+import com.intellij.psi.PsiTypeParameter;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class TypeParameterNamingConventionInspectionBase extends ConventionInspection {
+ private static final int DEFAULT_MIN_LENGTH = 1;
+ private static final int DEFAULT_MAX_LENGTH = 1;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "type.parameter.naming.convention.display.name");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final String parameterName = (String)infos[0];
+ if (parameterName.length() < getMinLength()) {
+ return InspectionGadgetsBundle.message(
+ "type.parameter.naming.convention.problem.descriptor.short");
+ }
+ else if (parameterName.length() > getMaxLength()) {
+ return InspectionGadgetsBundle.message(
+ "type.parameter.naming.convention.problem.descriptor.long");
+ }
+ return InspectionGadgetsBundle.message(
+ "enumerated.class.naming.convention.problem.descriptor.regex.mismatch",
+ getRegex());
+ }
+
+ @Override
+ protected String getDefaultRegex() {
+ return "[A-Z][A-Za-z\\d]*";
+ }
+
+ @Override
+ protected int getDefaultMinLength() {
+ return DEFAULT_MIN_LENGTH;
+ }
+
+ @Override
+ protected int getDefaultMaxLength() {
+ return DEFAULT_MAX_LENGTH;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NamingConventionsVisitor();
+ }
+
+ private class NamingConventionsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitTypeParameter(PsiTypeParameter parameter) {
+ super.visitTypeParameter(parameter);
+ final String name = parameter.getName();
+ if (name == null) {
+ return;
+ }
+ if (isValid(name)) {
+ return;
+ }
+ final PsiIdentifier nameIdentifier = parameter.getNameIdentifier();
+ if (nameIdentifier == null) {
+ return;
+ }
+ registerError(nameIdentifier, name);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspectionBase.java
new file mode 100644
index 000000000000..83a65feb7fe5
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspectionBase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.naming;
+
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class UpperCaseFieldNameNotConstantInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "upper.case.field.name.not.constant.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "NonConstantFieldWithUpperCaseName";
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "upper.case.field.name.not.constant.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UpperCaseFieldNameNotConstantVisitor();
+ }
+
+ private static class UpperCaseFieldNameNotConstantVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ super.visitField(field);
+ if (field.hasModifierProperty(PsiModifier.STATIC) &&
+ field.hasModifierProperty(PsiModifier.FINAL)) {
+ return;
+ }
+ final String fieldName = field.getName();
+ if (fieldName == null) {
+ return;
+ }
+ if (!fieldName.equals(fieldName.toUpperCase())) {
+ return;
+ }
+ registerFieldError(field);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/OverlyComplexArithmeticExpressionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/OverlyComplexArithmeticExpressionInspectionBase.java
new file mode 100644
index 000000000000..aca2c81e4546
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/OverlyComplexArithmeticExpressionInspectionBase.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.numeric;
+
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.TypeUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class OverlyComplexArithmeticExpressionInspectionBase extends BaseInspection {
+ protected static final Set<IElementType> arithmeticTokens =
+ new HashSet<IElementType>(5);
+ private static final int TERM_LIMIT = 6;
+ /**
+ * @noinspection PublicField
+ */
+ public int m_limit = TERM_LIMIT; //this is public for the DefaultJDOMExternalizer thingy
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "overly.complex.arithmetic.expression.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "overly.complex.arithmetic.expression.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new OverlyComplexArithmeticExpressionVisitor();
+ }
+
+ private class OverlyComplexArithmeticExpressionVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitBinaryExpression(
+ @NotNull PsiBinaryExpression expression) {
+ super.visitBinaryExpression(expression);
+ checkExpression(expression);
+ }
+
+ @Override
+ public void visitPrefixExpression(
+ @NotNull PsiPrefixExpression expression) {
+ super.visitPrefixExpression(expression);
+ checkExpression(expression);
+ }
+
+ @Override
+ public void visitParenthesizedExpression(
+ PsiParenthesizedExpression expression) {
+ super.visitParenthesizedExpression(expression);
+ checkExpression(expression);
+ }
+
+ private void checkExpression(PsiExpression expression) {
+ if (isParentArithmetic(expression)) {
+ return;
+ }
+ if (!isArithmetic(expression)) {
+ return;
+ }
+ final int numTerms = countTerms(expression);
+ if (numTerms <= m_limit) {
+ return;
+ }
+ registerError(expression);
+ }
+
+ private int countTerms(PsiExpression expression) {
+ if (!isArithmetic(expression)) {
+ return 1;
+ }
+ if (expression instanceof PsiBinaryExpression) {
+ final PsiBinaryExpression binaryExpression =
+ (PsiBinaryExpression)expression;
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ return countTerms(lhs) + countTerms(rhs);
+ }
+ else if (expression instanceof PsiPrefixExpression) {
+ final PsiPrefixExpression prefixExpression =
+ (PsiPrefixExpression)expression;
+ final PsiExpression operand = prefixExpression.getOperand();
+ return countTerms(operand);
+ }
+ else if (expression instanceof PsiParenthesizedExpression) {
+ final PsiParenthesizedExpression parenthesizedExpression =
+ (PsiParenthesizedExpression)expression;
+ final PsiExpression contents = parenthesizedExpression.getExpression();
+ return countTerms(contents);
+ }
+ return 1;
+ }
+
+ private boolean isParentArithmetic(PsiExpression expression) {
+ final PsiElement parent = expression.getParent();
+ return parent instanceof PsiExpression && isArithmetic((PsiExpression)parent);
+ }
+
+ private boolean isArithmetic(PsiExpression expression) {
+ if (expression instanceof PsiBinaryExpression) {
+ final PsiType type = expression.getType();
+ if (TypeUtils.isJavaLangString(type)) {
+ return false; //ignore string concatenations
+ }
+ final PsiBinaryExpression binaryExpression =
+ (PsiBinaryExpression)expression;
+ return arithmeticTokens.contains(binaryExpression.getOperationTokenType());
+ }
+ else if (expression instanceof PsiPrefixExpression) {
+ final PsiPrefixExpression prefixExpression =
+ (PsiPrefixExpression)expression;
+ return arithmeticTokens.contains(prefixExpression.getOperationTokenType());
+ }
+ else if (expression instanceof PsiParenthesizedExpression) {
+ final PsiParenthesizedExpression parenthesizedExpression =
+ (PsiParenthesizedExpression)expression;
+ final PsiExpression contents =
+ parenthesizedExpression.getExpression();
+ return isArithmetic(contents);
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspectionBase.java
new file mode 100644
index 000000000000..86e5f9c3cfe2
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/DynamicRegexReplaceableByCompiledPatternInspectionBase.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.performance;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+public class DynamicRegexReplaceableByCompiledPatternInspectionBase extends BaseInspection {
+ @NonNls
+ protected static final Collection<String> regexMethodNames = new HashSet<String>(4);
+ static {
+ regexMethodNames.add("matches");
+ regexMethodNames.add("replaceFirst");
+ regexMethodNames.add("replaceAll");
+ regexMethodNames.add("split");
+ }
+
+ @Override
+ @Nls
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "dynamic.regex.replaceable.by.compiled.pattern.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "dynamic.regex.replaceable.by.compiled.pattern.problem.descriptor");
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new DynamicRegexReplaceableByCompiledPatternVisitor();
+ }
+
+ private static class DynamicRegexReplaceableByCompiledPatternVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ if (!isCallToRegexMethod(expression)) {
+ return;
+ }
+ registerMethodCallError(expression);
+ }
+
+
+ private static boolean isCallToRegexMethod(PsiMethodCallExpression expression) {
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String name = methodExpression.getReferenceName();
+ if (!regexMethodNames.contains(name)) {
+ return false;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ for (PsiExpression argument : arguments) {
+ if (!PsiUtil.isConstantExpression(argument)) {
+ return false;
+ }
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return false;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null) {
+ return false;
+ }
+ final String className = containingClass.getQualifiedName();
+ return CommonClassNames.JAVA_LANG_STRING.equals(className);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/ToArrayCallWithZeroLengthArrayArgumentInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/ToArrayCallWithZeroLengthArrayArgumentInspectionBase.java
new file mode 100644
index 000000000000..51bee0da98c0
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/ToArrayCallWithZeroLengthArrayArgumentInspectionBase.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.performance;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.CollectionUtils;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class ToArrayCallWithZeroLengthArrayArgumentInspectionBase extends BaseInspection {
+ @Override
+ @Nls
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "to.array.call.with.zero.length.array.argument.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ final PsiExpression argument = (PsiExpression)infos[1];
+ return InspectionGadgetsBundle.message(
+ "to.array.call.with.zero.length.array.argument.problem.descriptor",
+ argument.getText());
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ToArrayCallWithZeroLengthArrayArgument();
+ }
+
+ private static class ToArrayCallWithZeroLengthArrayArgument extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ @NonNls final String methodName = methodExpression.getReferenceName();
+ if (!"toArray".equals(methodName)) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length != 1) {
+ return;
+ }
+ final PsiExpression argument = arguments[0];
+ final PsiType type = argument.getType();
+ if (!(type instanceof PsiArrayType)) {
+ return;
+ }
+ if (type.getArrayDimensions() != 1) {
+ return;
+ }
+ if (argument instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)argument;
+ final PsiElement element = referenceExpression.resolve();
+ if (!(element instanceof PsiField)) {
+ return;
+ }
+ final PsiField field = (PsiField)element;
+ if (!CollectionUtils.isConstantEmptyArray(field)) {
+ return;
+ }
+ }
+ else if (!ExpressionUtils.isZeroLengthArrayConstruction(argument)) {
+ return;
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (!InheritanceUtil.isInheritor(containingClass, CommonClassNames.JAVA_UTIL_COLLECTION)) {
+ return;
+ }
+ registerMethodCallError(expression, expression, argument);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/ExternalizableWithoutPublicNoArgConstructorInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/ExternalizableWithoutPublicNoArgConstructorInspectionBase.java
new file mode 100644
index 000000000000..ede8b3abcdaa
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/ExternalizableWithoutPublicNoArgConstructorInspectionBase.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.psi.*;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ExternalizableWithoutPublicNoArgConstructorInspectionBase extends BaseInspection {
+ @Nullable
+ protected static PsiMethod getNoArgConstructor(PsiClass aClass) {
+ final PsiMethod[] constructors = aClass.getConstructors();
+ for (PsiMethod constructor : constructors) {
+ final PsiParameterList parameterList = constructor.getParameterList();
+ if (parameterList.getParametersCount() == 0) {
+ return constructor;
+ }
+ }
+ return null;
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("externalizable.without.public.no.arg.constructor.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("externalizable.without.public.no.arg.constructor.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ExternalizableWithoutPublicNoArgConstructorVisitor();
+ }
+
+ private static class ExternalizableWithoutPublicNoArgConstructorVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType() || aClass instanceof PsiTypeParameter) {
+ return;
+ }
+ if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return;
+ }
+ if (!isExternalizable(aClass)) {
+ return;
+ }
+ final PsiMethod constructor = getNoArgConstructor(aClass);
+ if (constructor == null) {
+ if (aClass.hasModifierProperty(PsiModifier.PUBLIC)) {
+ return;
+ }
+ } else {
+ if (constructor.hasModifierProperty(PsiModifier.PUBLIC)) {
+ return;
+ }
+ }
+ if (SerializationUtils.hasWriteReplace(aClass)) {
+ return;
+ }
+ registerClassError(aClass, aClass, constructor);
+ }
+
+ private static boolean isExternalizable(PsiClass aClass) {
+ final PsiClass externalizableClass = ClassUtils.findClass("java.io.Externalizable", aClass);
+ return externalizableClass != null && aClass.isInheritor(externalizableClass, true);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/NonSerializableFieldInSerializableClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/NonSerializableFieldInSerializableClassInspectionBase.java
new file mode 100644
index 000000000000..e2c6c3cba44c
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/NonSerializableFieldInSerializableClassInspectionBase.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2006-2012 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.AddToIgnoreIfAnnotatedByListQuickFix;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+
+public class NonSerializableFieldInSerializableClassInspectionBase extends SerializableInspectionBase {
+
+ @SuppressWarnings({"PublicField"})
+ public final ExternalizableStringSet ignorableAnnotations = new ExternalizableStringSet();
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "non.serializable.field.in.serializable.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "non.serializable.field.in.serializable.class.problem.descriptor");
+ }
+
+ @NotNull
+ @Override
+ protected InspectionGadgetsFix[] buildFixes(Object... infos) {
+ final PsiField field = (PsiField)infos[0];
+ return AddToIgnoreIfAnnotatedByListQuickFix.build(field, ignorableAnnotations);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NonSerializableFieldInSerializableClassVisitor();
+ }
+
+ private class NonSerializableFieldInSerializableClassVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitField(@NotNull PsiField field) {
+ if (field.hasModifierProperty(PsiModifier.TRANSIENT) || field.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final PsiClass aClass = field.getContainingClass();
+ if (aClass == null) {
+ return;
+ }
+ if (ignoreAnonymousInnerClasses && aClass instanceof PsiAnonymousClass) {
+ return;
+ }
+ if (!SerializationUtils.isSerializable(aClass)) {
+ return;
+ }
+ if (SerializationUtils.isProbablySerializable(field.getType())) {
+ return;
+ }
+ final boolean hasWriteObject = SerializationUtils.hasWriteObject(aClass);
+ if (hasWriteObject) {
+ return;
+ }
+ if (isIgnoredSubclass(aClass)) {
+ return;
+ }
+ if (AnnotationUtil.isAnnotated(field, ignorableAnnotations)) {
+ return;
+ }
+ registerFieldError(field, field);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspectionBase.java
new file mode 100644
index 000000000000..df06cf01f1e8
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspectionBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.psi.*;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.AddSerialVersionUIDFix;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.intellij.lang.annotations.Pattern;
+import org.jetbrains.annotations.NotNull;
+
+public class SerializableHasSerialVersionUIDFieldInspectionBase extends SerializableInspectionBase {
+
+ @Pattern("[a-zA-Z_0-9.-]+")
+ @Override
+ @NotNull
+ public String getID() {
+ return "serial";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "serializable.class.without.serialversionuid.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "serializable.class.without.serialversionuid.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new AddSerialVersionUIDFix();
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new SerializableHasSerialVersionUIDFieldVisitor();
+ }
+
+ private class SerializableHasSerialVersionUIDFieldVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isAnnotationType() || aClass.isEnum()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter || aClass instanceof PsiEnumConstantInitializer) {
+ return;
+ }
+ if (ignoreAnonymousInnerClasses && aClass instanceof PsiAnonymousClass) {
+ return;
+ }
+ final PsiField serialVersionUIDField = aClass.findFieldByName(HardcodedMethodConstants.SERIAL_VERSION_UID, false);
+ if (serialVersionUIDField != null) {
+ return;
+ }
+ if (!SerializationUtils.isSerializable(aClass)) {
+ return;
+ }
+ if (SerializationUtils.hasWriteReplace(aClass)) {
+ return;
+ }
+ if (isIgnoredSubclass(aClass)) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspectionBase.java
new file mode 100644
index 000000000000..3d9aaef4e71f
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspectionBase.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiEnumConstantInitializer;
+import com.intellij.psi.PsiTypeParameter;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class SerializableHasSerializationMethodsInspectionBase
+ extends SerializableInspectionBase {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "serializable.has.serialization.methods.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ final boolean hasReadObject = ((Boolean)infos[0]).booleanValue();
+ final boolean hasWriteObject = ((Boolean)infos[1]).booleanValue();
+ if (!hasReadObject && !hasWriteObject) {
+ return InspectionGadgetsBundle.message(
+ "serializable.has.serialization.methods.problem.descriptor");
+ }
+ else if (hasReadObject) {
+ return InspectionGadgetsBundle.message(
+ "serializable.has.serialization.methods.problem.descriptor1");
+ }
+ else {
+ return InspectionGadgetsBundle.message(
+ "serializable.has.serialization.methods.problem.descriptor2");
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new SerializableHasSerializationMethodsVisitor();
+ }
+
+ private class SerializableHasSerializationMethodsVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down
+ if (aClass.isInterface() || aClass.isAnnotationType() ||
+ aClass.isEnum()) {
+ return;
+ }
+ if (aClass instanceof PsiTypeParameter ||
+ aClass instanceof PsiEnumConstantInitializer) {
+ return;
+ }
+ if (ignoreAnonymousInnerClasses &&
+ aClass instanceof PsiAnonymousClass) {
+ return;
+ }
+ if (!SerializationUtils.isSerializable(aClass)) {
+ return;
+ }
+ final boolean hasReadObject =
+ SerializationUtils.hasReadObject(aClass);
+ final boolean hasWriteObject =
+ SerializationUtils.hasWriteObject(aClass);
+ if (hasWriteObject && hasReadObject) {
+ return;
+ }
+ if (isIgnoredSubclass(aClass)) {
+ return;
+ }
+ registerClassError(aClass, Boolean.valueOf(hasReadObject),
+ Boolean.valueOf(hasWriteObject));
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspectionBase.java
new file mode 100644
index 000000000000..439cf753ba66
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspectionBase.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.fixes.AddSerialVersionUIDFix;
+import org.jetbrains.annotations.NotNull;
+
+public class SerializableInnerClassHasSerialVersionUIDFieldInspectionBase
+ extends SerializableInspectionBase {
+
+ @Override
+ @NotNull
+ public String getID() {
+ return "SerializableNonStaticInnerClassWithoutSerialVersionUID";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "serializable.inner.class.has.serial.version.uid.field.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "serializable.inner.class.has.serial.version.uid.field.problem.descriptor");
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new AddSerialVersionUIDFix();
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new SerializableInnerClassHasSerialVersionUIDFieldVisitor(this);
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldVisitor.java
new file mode 100644
index 000000000000..9f3c83d110ec
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldVisitor.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.jetbrains.annotations.NotNull;
+
+class SerializableInnerClassHasSerialVersionUIDFieldVisitor
+ extends BaseInspectionVisitor {
+
+ private final SerializableInspectionBase inspection;
+
+ public SerializableInnerClassHasSerialVersionUIDFieldVisitor(
+ SerializableInspectionBase inspection) {
+ this.inspection = inspection;
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ // no call to super, so it doesn't drill down
+ if (aClass.isInterface() || aClass.isAnnotationType() ||
+ aClass.isEnum()) {
+ return;
+ }
+ if (inspection.ignoreAnonymousInnerClasses &&
+ aClass instanceof PsiAnonymousClass) {
+ return;
+ }
+ if (hasSerialVersionUIDField(aClass)) {
+ return;
+ }
+ final PsiClass containingClass = aClass.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ if (aClass.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ if (!SerializationUtils.isSerializable(aClass)) {
+ return;
+ }
+ if (inspection.isIgnoredSubclass(aClass)) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+
+ private static boolean hasSerialVersionUIDField(PsiClass aClass) {
+ final PsiField[] fields = aClass.getFields();
+ boolean hasSerialVersionUID = false;
+ for (PsiField field : fields) {
+ final String fieldName = field.getName();
+ if (HardcodedMethodConstants.SERIAL_VERSION_UID.equals(
+ fieldName)) {
+ hasSerialVersionUID = true;
+ }
+ }
+ return hasSerialVersionUID;
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspectionBase.java
new file mode 100644
index 000000000000..8ea9c1c3ac65
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspectionBase.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class SerializableInnerClassWithNonSerializableOuterClassInspectionBase
+ extends SerializableInspectionBase {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "serializable.inner.class.with.non.serializable.outer.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "serializable.inner.class.with.non.serializable.outer.class.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new SerializableInnerClassWithNonSerializableOuterClassVisitor(this);
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassVisitor.java
new file mode 100644
index 000000000000..a3e9ee3851b6
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassVisitor.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiModifier;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.jetbrains.annotations.NotNull;
+
+class SerializableInnerClassWithNonSerializableOuterClassVisitor
+ extends BaseInspectionVisitor {
+
+ private final SerializableInspectionBase inspection;
+
+ public SerializableInnerClassWithNonSerializableOuterClassVisitor(
+ SerializableInspectionBase inspection) {
+ this.inspection = inspection;
+ }
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isAnnotationType() ||
+ aClass.isEnum()) {
+ return;
+ }
+ if (inspection.ignoreAnonymousInnerClasses &&
+ aClass instanceof PsiAnonymousClass) {
+ return;
+ }
+ final PsiClass containingClass = aClass.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ if (aClass.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ if (!SerializationUtils.isSerializable(aClass)) {
+ return;
+ }
+ if (SerializationUtils.isSerializable(containingClass)) {
+ return;
+ }
+ if (inspection.isIgnoredSubclass(aClass)) {
+ return;
+ }
+ registerClassError(aClass);
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInspectionBase.java
new file mode 100644
index 000000000000..498719c80d13
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/serialization/SerializableInspectionBase.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.serialization;
+
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.util.InheritanceUtil;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.psiutils.SerializationUtils;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class SerializableInspectionBase extends BaseInspection {
+ private static final JComponent[] EMPTY_COMPONENT_ARRAY = {};
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreAnonymousInnerClasses = false;
+ @Deprecated @SuppressWarnings({"PublicField"})
+ public String superClassString = "java.awt.Component";
+ protected List<String> superClassList = new ArrayList<String>();
+
+ @Override
+ public void readSettings(@NotNull Element node) throws InvalidDataException {
+ super.readSettings(node);
+ parseString(superClassString, superClassList);
+ }
+
+ @Override
+ public void writeSettings(@NotNull Element node) throws WriteExternalException {
+ superClassString = formatString(superClassList);
+ super.writeSettings(node);
+ }
+
+ protected JComponent[] createAdditionalOptions() {
+ return EMPTY_COMPONENT_ARRAY;
+ }
+
+ protected boolean isIgnoredSubclass(PsiClass aClass) {
+ if (SerializationUtils.isDirectlySerializable(aClass)) {
+ return false;
+ }
+ for (String superClassName : superClassList) {
+ if (InheritanceUtil.isInheritor(aClass, superClassName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String getAlternativeID() {
+ return "serial";
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/ChainedMethodCallInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/ChainedMethodCallInspectionBase.java
new file mode 100644
index 000000000000..b06cf7e79d69
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/ChainedMethodCallInspectionBase.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.style;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class ChainedMethodCallInspectionBase extends BaseInspection {
+ @SuppressWarnings("PublicField")
+ public boolean m_ignoreFieldInitializations = true;
+ @SuppressWarnings("PublicField")
+ public boolean m_ignoreThisSuperCalls = true;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("chained.method.call.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("chained.method.call.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ChainedMethodCallVisitor();
+ }
+
+ private class ChainedMethodCallVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression reference = expression.getMethodExpression();
+ final PsiExpression qualifier = reference.getQualifierExpression();
+ if (qualifier == null) {
+ return;
+ }
+ if (!isCallExpression(qualifier)) {
+ return;
+ }
+ if (m_ignoreFieldInitializations) {
+ final PsiElement field = PsiTreeUtil.getParentOfType(expression, PsiField.class);
+ if (field != null) {
+ return;
+ }
+ }
+ if (m_ignoreThisSuperCalls) {
+ final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(expression, PsiExpressionList.class);
+ if (expressionList != null) {
+ final PsiElement parent = expressionList.getParent();
+ if (ExpressionUtils.isConstructorInvocation(parent)) {
+ return;
+ }
+ }
+ }
+ registerMethodCallError(expression);
+ }
+
+ private boolean isCallExpression(PsiExpression expression) {
+ expression = ParenthesesUtils.stripParentheses(expression);
+ return expression instanceof PsiMethodCallExpression || expression instanceof PsiNewExpression;
+ }
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java
new file mode 100644
index 000000000000..484c1f8fefe0
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.style;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class NestedMethodCallInspectionBase extends BaseInspection {
+ /**
+ * @noinspection PublicField
+ */
+ public boolean m_ignoreFieldInitializations = true;
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("nested.method.call.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("nested.method.call.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new NestedMethodCallVisitor();
+ }
+
+ @Override
+ protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
+ return true;
+ }
+
+ private class NestedMethodCallVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ PsiExpression outerExpression = expression;
+ while (outerExpression != null && outerExpression.getParent() instanceof PsiExpression) {
+ outerExpression = (PsiExpression)outerExpression.getParent();
+ }
+ if (outerExpression == null) {
+ return;
+ }
+ final PsiElement parent = outerExpression.getParent();
+ if (!(parent instanceof PsiExpressionList)) {
+ return;
+ }
+ final PsiElement grandParent = parent.getParent();
+ if (!(grandParent instanceof PsiCallExpression)) {
+ return;
+ }
+ if (ExpressionUtils.isConstructorInvocation(grandParent)) {
+ //ignore nested method calls at the start of a constructor,
+ //where they can't be extracted
+ return;
+ }
+ if (m_ignoreFieldInitializations) {
+ final PsiElement field = PsiTreeUtil.getParentOfType(expression, PsiField.class);
+ if (field != null) {
+ return;
+ }
+ }
+ registerMethodCallError(expression);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspectionBase.java
new file mode 100644
index 000000000000..f43b9d188bcc
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspectionBase.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.style;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.containers.OrderedSet;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ComparisonUtils;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class SizeReplaceableByIsEmptyInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreNegations = false;
+ @SuppressWarnings("PublicField")
+ public OrderedSet<String> ignoredTypes = new OrderedSet<String>();
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("size.replaceable.by.isempty.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("expression.can.be.replaced.problem.descriptor", infos[0]);
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new SizeReplaceableByIsEmptyVisitor();
+ }
+
+ protected static class SizeReplaceableByIsEmptyFix
+ extends InspectionGadgetsFix {
+ @Override
+ @NotNull
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("size.replaceable.by.isempty.quickfix");
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)descriptor.getPsiElement();
+ PsiExpression operand = binaryExpression.getLOperand();
+ if (!(operand instanceof PsiMethodCallExpression)) {
+ operand = binaryExpression.getROperand();
+ }
+ if (!(operand instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)operand;
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ if (qualifierExpression == null) {
+ return;
+ }
+ @NonNls String newExpression = qualifierExpression.getText();
+ final IElementType tokenType = binaryExpression.getOperationTokenType();
+ if (!JavaTokenType.EQEQ.equals(tokenType)) {
+ newExpression = '!' + newExpression;
+ }
+ newExpression += ".isEmpty()";
+ replaceExpression(binaryExpression, newExpression);
+ }
+ }
+
+ private class SizeReplaceableByIsEmptyVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitBinaryExpression(PsiBinaryExpression expression) {
+ super.visitBinaryExpression(expression);
+ final PsiExpression rhs = expression.getROperand();
+ if (rhs == null) {
+ return;
+ }
+ if (!ComparisonUtils.isComparison(expression)) {
+ return;
+ }
+ final PsiExpression lhs = expression.getLOperand();
+ if (lhs instanceof PsiMethodCallExpression) {
+ final String replacementIsEmptyCall = getReplacementIsEmptyCall(lhs, rhs, false, expression.getOperationTokenType());
+ if (replacementIsEmptyCall != null) {
+ registerError(expression, replacementIsEmptyCall);
+ }
+ }
+ else if (rhs instanceof PsiMethodCallExpression) {
+ final String replacementIsEmptyCall = getReplacementIsEmptyCall(rhs, lhs, true, expression.getOperationTokenType());
+ if (replacementIsEmptyCall != null) {
+ registerError(expression, replacementIsEmptyCall);
+ }
+ }
+ }
+
+ @Nullable
+ private String getReplacementIsEmptyCall(PsiExpression lhs, PsiExpression rhs, boolean flipped, IElementType tokenType) {
+ final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)lhs;
+ final String isEmptyCall = getIsEmptyCall(callExpression);
+ if (isEmptyCall == null) {
+ return null;
+ }
+ final Object object = ExpressionUtils.computeConstantExpression(rhs);
+ if (!(object instanceof Integer)) {
+ return null;
+ }
+ final Integer integer = (Integer)object;
+ final int constant = integer.intValue();
+ if (constant != 0) {
+ return null;
+ }
+ if (JavaTokenType.EQEQ.equals(tokenType)) {
+ return isEmptyCall;
+ }
+ if (ignoreNegations) {
+ return null;
+ }
+ if (JavaTokenType.NE.equals(tokenType)) {
+ return '!' + isEmptyCall;
+ }
+ else if (flipped) {
+ if (JavaTokenType.LT.equals(tokenType)) {
+ return '!' + isEmptyCall;
+ }
+ }
+ else if (JavaTokenType.GT.equals(tokenType)) {
+ return '!' + isEmptyCall;
+ }
+ return null;
+ }
+
+ @Nullable
+ private String getIsEmptyCall(PsiMethodCallExpression callExpression) {
+ final PsiReferenceExpression methodExpression = callExpression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.SIZE.equals(referenceName) &&
+ !HardcodedMethodConstants.LENGTH.equals(referenceName)) {
+ return null;
+ }
+ final PsiExpressionList argumentList = callExpression.getArgumentList();
+ final PsiExpression[] expressions = argumentList.getExpressions();
+ if (expressions.length != 0) {
+ return null;
+ }
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ if (qualifierExpression == null) {
+ return null;
+ }
+ final PsiType type = qualifierExpression.getType();
+ if (!(type instanceof PsiClassType)) {
+ return null;
+ }
+ final PsiClassType classType = (PsiClassType)type;
+ final PsiClass aClass = classType.resolve();
+ if (aClass == null) {
+ return null;
+ }
+ if (PsiTreeUtil.isAncestor(aClass, callExpression, true)) {
+ return null;
+ }
+ for (String ignoredType : ignoredTypes) {
+ if (InheritanceUtil.isInheritor(aClass, ignoredType)) {
+ return null;
+ }
+ }
+ final PsiMethod[] methods = aClass.findMethodsByName("isEmpty", true);
+ for (PsiMethod method : methods) {
+ final PsiParameterList parameterList = method.getParameterList();
+ if (parameterList.getParametersCount() == 0) {
+ return qualifierExpression.getText() + ".isEmpty()";
+ }
+ }
+ return null;
+ }
+ }
+
+ @Override
+ @Nullable
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new SizeReplaceableByIsEmptyFix();
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspectionBase.java
new file mode 100644
index 000000000000..ced77f835ea6
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnqualifiedInnerClassAccessInspectionBase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.style;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+public class UnqualifiedInnerClassAccessInspectionBase extends BaseInspection {
+ @SuppressWarnings({"PublicField"})
+ public boolean ignoreReferencesToLocalInnerClasses = false;
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("unqualified.inner.class.access.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("unqualified.inner.class.access.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UnqualifiedInnerClassAccessVisitor();
+ }
+
+ protected static class ReferenceCollector extends JavaRecursiveElementVisitor {
+
+ private final String name;
+ private final boolean onDemand;
+ private final Set<PsiJavaCodeReferenceElement> references = new HashSet<PsiJavaCodeReferenceElement>();
+
+ ReferenceCollector(String name, boolean onDemand) {
+ this.name = name;
+ this.onDemand = onDemand;
+ }
+
+ @Override
+ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
+ super.visitReferenceElement(reference);
+ if (reference.isQualified()) {
+ return;
+ }
+ final PsiElement target = reference.resolve();
+ if (!(target instanceof PsiClass)) {
+ return;
+ }
+ final PsiClass aClass = (PsiClass)target;
+ if (!onDemand) {
+ final String qualifiedName = aClass.getQualifiedName();
+ if (name.equals(qualifiedName)) {
+ references.add(reference);
+ }
+ return;
+ }
+ final PsiClass containingClass = aClass.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ final String qualifiedName = containingClass.getQualifiedName();
+ if (name.equals(qualifiedName)) {
+ references.add(reference);
+ }
+ }
+
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ visitReferenceElement(expression);
+ }
+
+ public Collection<PsiJavaCodeReferenceElement> getReferences() {
+ return references;
+ }
+ }
+
+ private class UnqualifiedInnerClassAccessVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
+ super.visitReferenceElement(reference);
+ if (reference.isQualified()) {
+ return;
+ }
+ final PsiElement target = reference.resolve();
+ if (!(target instanceof PsiClass)) {
+ return;
+ }
+ final PsiClass aClass = (PsiClass)target;
+ final PsiClass containingClass = aClass.getContainingClass();
+ if (containingClass == null) {
+ return;
+ }
+ if (ignoreReferencesToLocalInnerClasses) {
+ if (PsiTreeUtil.isAncestor(containingClass, reference, true)) {
+ return;
+ }
+ final PsiClass referenceClass = PsiTreeUtil.getParentOfType(reference, PsiClass.class);
+ if (referenceClass != null && referenceClass.isInheritor(containingClass, true)) {
+ return;
+ }
+ }
+ registerError(reference, containingClass.getName());
+ }
+
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ visitReferenceElement(expression);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ExtendsThreadInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ExtendsThreadInspectionBase.java
new file mode 100644
index 000000000000..59d1568c3e00
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ExtendsThreadInspectionBase.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.threading;
+
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiClass;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class ExtendsThreadInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getID() {
+ return "ClassExplicitlyExtendsThread";
+ }
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("extends.thread.display.name");
+ }
+
+ @Override
+ @NotNull
+ protected String buildErrorString(Object... infos) {
+ final PsiClass aClass = (PsiClass)infos[0];
+ if (aClass instanceof PsiAnonymousClass) {
+ return InspectionGadgetsBundle.message("anonymous.extends.thread.problem.descriptor");
+ } else {
+ return InspectionGadgetsBundle.message("extends.thread.problem.descriptor");
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ExtendsThreadVisitor();
+ }
+
+ private static class ExtendsThreadVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitClass(@NotNull PsiClass aClass) {
+ if (aClass.isInterface() || aClass.isAnnotationType() || aClass.isEnum()) {
+ return;
+ }
+ final PsiClass superClass = aClass.getSuperClass();
+ if (superClass == null) {
+ return;
+ }
+ final String superclassName = superClass.getQualifiedName();
+ if (!"java.lang.Thread".equals(superclassName)) {
+ return;
+ }
+ registerClassError(aClass, aClass);
+ }
+ }
+}