diff options
author | Tor Norbye <tnorbye@google.com> | 2013-09-27 10:19:19 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-09-27 10:19:28 -0700 |
commit | f7998d05c40c24ae66d1972abfcb070552b1d7b5 (patch) | |
tree | b0b97491f6e6591e53ea6a8f6c3a79a7dc685771 /java | |
parent | beca9839b2866f90da9dc517c29df2ec25a6f6a8 (diff) | |
download | idea-f7998d05c40c24ae66d1972abfcb070552b1d7b5.tar.gz |
Snapshot cd724ea5e27634f1c84f893f10b646937a677d56 from idea/132.425 of git://git.jetbrains.org/idea/community.git
cd724ea: Code cleanup - Idea's warnings fixed - message moved to .properties file
c84855b: for performance use processNames api for java symbol contributor
334c509: IDEA-114064 Create "From Maven" library dialog doesn't handle full coords correctly (as advertised)
4e10a17: IDEA-109943 Download Library from Maven Repository: artifacts from repository with provider != maven2 are suggested, but repository is filtered off
d4bc48d: IDEA-114037 Code completion should prefer variable names to unimported class names
b7e5e6c: refix RUBY-11716: do not play with fire, always save and load in UTF-8 !
bb7ed8a: cleanup
15bd24e: cleanup
e56b270: ProjectId, don't add project level provider if project is not mapped
a0fb6a5: let IsNullCheck mean null->true, the former !null->false meaning was useless
26402542: test data fixed
f800733: new inference: input/output inference variables
56d872d: NPE: find usage for db element
3ffd6a0: IDEA-114003 XDebuger breakpoint properties: strage selection jumps in breakpoint tree
bbdef54: IDEA-114001 XDebuger Breakpoint Properties: enable in tree is not saved IDEA-114002 XDebuger breakpoint properties: don't close the dialog by double click IDEA-114004 XDebugger breakpoint properties: checkboxes synchronization is broken
f6ff871: IDEA-114001 XDebuger Breakpoint Properties: enable in tree is not saved IDEA-114002 XDebuger breakpoint properties: don't close the dialog by double click IDEA-114004 XDebugger breakpoint properties: checkboxes synchronization is broken
8f3d962: IDEABKL-6897 Enter inserts closing brace in wrong place
6a78643: IDEABKL-6897 Enter inserts closing brace in wrong place
06b899c: IDEA-114001 XDebuger Breakpoint Properties: enable in tree is not saved IDEA-114002 XDebuger breakpoint properties: don't close the dialog by double click IDEA-114004 XDebugger breakpoint properties: checkboxes synchronization is broken
aeda985: don't give focus to ant messages view
f525708: new inference: overload resolution for SAM return type for implicit lambda should be ignored
6692602: cleanup current file from highlighting markup
27c6645: compilation fix
1936bb2: IDEA-107453 Compilation error if overriding methods have different access modifiers
0ddcc36: api
a7f05e1: card layout fixed
b007608: IDEA-110203 IDEA ignores space after comma setting for methods declaration/call [CR-IC-2022]
ae02c17: hiding artifacts
90e6ed2: back to AddModuleWizard
4a029e9: Groovy: Pull-up members
6f9e810: NPE
fc48bab: pull-up
cbf7531: prepare pull-up refactoring for Groovy
6762d5f: cleanup
b26ffb2: spaces around inner classes
41e8e70: IDEA-113333 Java formatter breaks source code: Merges statements into line comments [CR-IC-2245]
ea91b55: IDEA-113815 keep "simple methods in one line" does not keep long methods [CR-IC-2486]
ecd65ad: Import Eclipse code style settings from XML profile (a part of IDEA-104068) [CR-IC-2219]
aacf1e4: IDEA-113844 (handling of core component initialization failures when spoiled by plugins)
8dc3ede: IDEA-112387 Reformat code with rearrange entires on = fail on enum [CR-IC-2205]
72ddb9e: Merge remote-tracking branch 'origin/master'
209340b: Add the description for MavenDuplicatePluginInspection.
de367e1: Merge branch 'svn1_8_new'
1a70497: IdeaTestAssistant: fix test data
d6a2510: svn: Fixed "Import" when path/url contains '@' symbol
94c4223: svn: Implemented "Export" action for command line
8913712: parameter popup: escape for annotation methods (IDEA-113971)
fdf7312: svn: Made event handler for checkout/export utilize passed progress indicator (instead of just current thread progress indicator)
f653713: IDEA-105758: Contradiction between error and fix actions (Java EE artifact)
eac456f: Platform: ability to provide native icons for PsiElements (PsiFile/Directory) AppCode: blue icons for folders
4d5c47a: IDEA-77519: Project fails to open when workspace.xml is empty
c40e732: two classes temporary restored to fix backward compatibility
b6b3bc6: added optional dependencies for framework support providers
a9dae78: IDEA-90661: recognize IBM JDK jars
6b44958: cleanup & javadoc
0c0a6a6: IDEA-108785 Allow applying the same context to many selected live templates
247661b: don't search for unknown path macros in the middle of xml unless asked so by PathMacroFilter (IDEA-102674)
90222d5: hopefully fix control flow building stack inconsistency assertions in case when a PCE is thrown
241e44b: EA-50288 - CCE: RefJavaUtilImpl.getTopLevelClass
22d5c2f: ensure to filter already inserted annotations (IDEA-113785)
27b76b4: inplace introducer: another case to restore expression (IDEA-113352)
603e138: add mnemonics (IDEA-113889)
a8c374c: XSuspendPolicyPanel "Make default" (requires for new JavaBreakpointType) remove unused methods
4f19472: CR-IC-2485 (deprecation policy specified; deprecated API usage upgraded)
7231807: JavaBreakpointType isSuspendThreadSupported true
8637e89: register JavaBreakpointType, but hide under system property java.debugger.xBreakpoint
0b2d5f0: cleanup
5cc1f5e: EA-50289 (CCE: TooBroadScopeInspection$TooBroadScopeInspectionFix.getCommentText)
505b86e: new inference: pertinent to applicability
8ac21fd: cleanup
2c5f39e: cleanup
f6efaa9: simplify DebuggerInvocationUtil
bf8865f: overrides
0d49e5b: JavaBreakpointType canPutAt
33ebea3: extract XLineBreakpointTypeBase
de7d963: extract XDebuggerEditorsProviderBase, init JavaBreakpointType (is not registered, so, not in action now)
ed777e6: remove deprecated canPutAt
9163435: overrides
44af67f8: extract XDebuggerUtil.getInstance().getGroupingByFileRuleAsList()
b93b27c: add missing Overrides
0857036: cleanup
ae791a7: new inference: test preparations
48120ab: IdeaTestAssistant: add resolving and completion inside TestDataPath annotation
971544b: remove empty unused class
c5642d9: hippie completion: split complex tokens by spaces
e1383b1: refix and add test for IDEA-90294 Don't use substring match in word completion
fbae94c: EA-49809 Made client factories final in SvnVcs
2b4b70f: Fix OC-8127: Appcode hangs on reformatting (endless right shift) +review CR-OC @Anton.Makeev, @Rustam.Vishnyakov
b7314cf: fix pycharm detection
5f0bb3c: revert error checking
5f99590: svn: Implemented "Import" action for command line
ad04905: svn: Changed import logic to use common commit event handler (instead of checkout event handler)
1a45be0: custom options
8d278a3: MavenArchetypesPanel extracted
32eeb4c: aggregation panel invisible
9388cc4: new project wizard: project type sorting
2c02a07: svn: Add "Skipped" event processing in commit/import output for command line
d365580: svn: Refactored commit output parsing for command line
b1cc312: immutable dfa offset stack
5c494fb: toolbarIcon is nullable
4304880: dfa: traverse only flushable variables, not all
ed08eab: immutable EqClass
03de519: overrides
f8661d9: return empty collection if list of storage files is empty
81a998c: IDEA-111030: Add Framework Support: Ok is disabled for the only selected Web Application
4ce1cc8: unused class removed
84f7401: svn: Added final status bar message for Import ("Committed revision xxx")
aa1d479: library editor: 'attach javadoc' extracted to separate button so the main '+' button won't show popup
1612198: cleanup
e180456: cleanup
546fffe: Merge remote-tracking branch 'origin/master'
c3caf6c: Merge remote-tracking branch 'origin/master'
5cd2b37: assertion for EA-45385 - NPE: XmlTagImpl.getDescriptor
99563ea: EA-49418 - NPE: InjectLanguageAction.invokeImpl
dc82859: cleanup
f70ef96: EA-50139 - assert: TextRange.<init>
990e410: svn: Removed unused code (from "Ignore" functionality)
6604613: svn: Implemented "Ignore" functionality on subversion level
d544d03: cleanup after notnullification
5330d9e: plugin suggester: suggest plugins from repository by unknown facet
1ccf92a: error which should never happen replaced by assertion
889d3ce: improved dialog for choosing root types of added roots
0eb34fa: hide "use out of process build" option from UI
d79e13e: plugin suggester: suggest plugins from repository by unknown facet
00a127b: Use shell options only if applicable.
b4f21b9: Don't fail to create SSH terminal session if we failed to create local terminal session.
8e5cb57: test for "Unnecessary unicode escape sequence" inspection
dc8acce: temp revert
c7c4431: fix SliceBackwardTest
3e16a04: svn: Implemented "Edit Revision Comment" action for command line
c54948a: 'async' added
e4f7950: svn: Correctly create externals that have '@' in url - add '@' at url end
9b66e1c: svn: Fix line separators duplication for "Create External" action for SVNKit
a98dc14: svn: Implemented "Create External" action for command line
32e30d1: EA-50206 - assert: FileManagerImpl.findFile
4a4c0cc: svn: Unify line separator for multiline properties
4b9422b: Reverted: Semantic highlighting level to avoid conflicts with "unused symbol" annotations [CR-IC-2435]
ad970ef: lambda: propagate wildcards elimination
e78ab51: lambda: check formal params for equality, eliminate wildcards during inference according to 15.27.3
fc9a196: new inference: ignore proper types in mutual eq constraints generation
7bc0048: new inference: void compatible according to return values
939fc45: prepare for test new inference
eef6eb2: new inference: exact method reference
172daec: new inference: eliminate delayed constrains according to 0.6.3
ec93384: postpone type evaluation
e689d68: new inference: make use of ex constraint
7838f8e: Merge branch 'safe-sudo-escaping'
1c22df9: Add grails-app/resources as resources folder, not a source folder.
a7f094d: fix NPE
e1fe819: Added ExecUtil.sudoAndGetOutput() with safe escaping and quoting for Mac and Linux
6bf3a02: fixed EA-48905 - SIOOBE: ParameterInfoComponent$OneLineComponent.buildLabelText
c853c69: system dependent paths in groovy shell
db7d97f: Merge remote-tracking branch 'origin/master'
65426f9: mark as DumbAware
0d1a074: Support active links in GotIt panel
c7297a0: debugging blinking test
755c6b2: IDEA-113938 "Submit feedback" should pre-fill project and affected version
ff45141: dfa: don't go into the same instruction twice with the same state
3361944: a bit more parsimonous DfaMemoryStateImpl.createCopy
028d28b: dfa states should not change while in queue => no need to copy them
1709382: dfa: use UnorderedPair instead of two-element set
e8dbc21: immutable DfaVariableState, for faster copying and less memory usage
666ed52: IDEA-70241 (Replace with '{@code}' inspection doesn't replace all occurrences in file.)
71bd9cf: Merge remote-tracking branch 'origin/master'
c923098: EA-47881 - IOE: GroovyPsiElementFactoryImpl.createGroovyFileChecked
8b97940: cleanup logging
6e4b81e: EA-50137 - assert: TestObject.addClassesListToJavaParameters
5381d51: cleanup
dc2d1b2: notnull
f419fab: "todo" moved out of lang-impl
97cd633: attributes cleanup
75b3eaa: notnull
c7fa9af: cleanup
f5b5bf4: cleanup
776b16b: cleanup
bf3cea4: made fields final
87913f7: cleanup
798e94e: cleanup, get rid of buggy duplicate node renderer
50f13e4: removed deprecated methods from ExternalAnnotator
6d9c887: avoid deprecated methods
4852116: minor
9cd549c: now Searchable. fixes test.
302302a: typo
26d8885: - handle strings with more than one quote used for start / end delimiters - proper retrieving syntax highlighter in case of non languge based syntaxhighlighter (quite often it is bound to file type) - Find: String literals only: Throwable at StringSearcher.scan() on XML with a string (IDEA-113885) - fix for backward search not ending when whole word option used
4dfd0c7: Encapsulate field dialog: explicit value for "Use accessors when field is accessible" when "as is" visibility is selected
e1aff45: typo :(((
6237b9b: test fixed
6c0d31b: test fixed
493cfae: update test data
711bca1: update test data
f1bc615: update test data
8dd18de: update test data
e61a901: update test data
0be96e9: update test data
aac178b: dfa: remove queued state duplication
6a25f5d: dfa: don't reschedule already processed states, cleanup
7559dfc: Semantic highlighting level to avoid conflicts with "unused symbol" annotations [CR-IC-2435], for WI-19396, WI-20126 (cherry picked from commit 56d66dc)
7c27aef: extract collectUsedJars() function
12f59ff: update test data
03df890: update test data
1efd604: update test data
2c1726e: update test data
24bf1d1: Merge remote-tracking branch 'origin/master'
8f26a8b: improved duplicates search in python extract method
9bfcbbe: setup resource roots when project is imported from Maven (IDEA-57398)
64594cd: diagnostics for EA-49831
0d76c32: add support for frameworks step: sorting restored
b510334: IDEA-113294 indentation of brace in a lambda expression corrected [CR-IC-2426]
9651be4: IDEA-113910 Gradle: code insight; dependencies DSL resolving
25595c8: new inference: checked exceptions compatibility constraint
6b8f295: dump highlighting test data without markup
636719b: now that we have dfa state hashing, use it instead of linear lookup
3813120: dfa: don't merge states when there's only one
3fd9ba8: IDEA-113910 Gradle: code insight; dependencies DSL resolving
57a6aeb: IDEA-113910 Gradle: code insight; dependencies resolving
da23b6c: Merge remote-tracking branch 'origin/master'
7ca6ea3: Merge remote branch 'origin/master'
cdc6d6a: show deprecated make implementation warning once on first compilation after project opening
090c4e3: dfa state merging: cache copies
e6ee024: Allows getting Gradle home without having a Project.
0391639: Gradle VM Options are now saved in between sessions.
f5412f0: resource root: show 'New Directory' action instead of 'New Package' under resource roots
1637f6b: notnullification
87f394f: IDEA-113904 (Add New Module from Project Structure dialog wants to create new project)
a7c75f6: IDEA-113865 ('Equals should check class of parameter' shouldn't warn on identity equals)
2486e9e: dfa: merge several states to account for variables with several possible values
4d4f4b0: dfa: some minor things and caching
c14961f: UnorderedPair in platform
5ad442d: Merge remote-tracking branch 'origin/master'
946a281: Scroll to bottom on typing in terminal (PY-10344).
e5a0548: Close all connections on dispose.
f61f6a2: changes from tech-writers
b82b0bb: dfa: state merging interruptibility
3893373: VcsDirtyScopeManagerImpl: log who marks everything dirty
41e5381: Merge remote-tracking branch 'origin/master'
da21efb: JediTerm updated.
beb1d1a: Merge remote-tracking branch 'origin/master'
ed3a2b5: skip the whole document if some component has disabled roaming type (details CR-IU-308)
d66309b: Fix antialiasing.
e55fae1: dfa: abstract out eq class into EqClass class
370d44d: dfa: remove trivial state facts that constant != another constant
4ccfcf7: UsagesStatistic must specify roaming disabled
75894ae: cleanup
784b4e3: DimensionService: cleanup, order of stored data should be stable
36443b6: overrides
b70b1dc: overrides
dfe38fb: simplify some constant conditions and greenify
9a08478: IDEA-85961 (Pattern BACKSLASH_PATTERN = Pattern.compile("\\", Pattern.LITERAL) is always marked red.)
d0bdc3b: simplify load from providers – we don't need to filter again (our save do it, in any case it is absurd to store component with global roaming in the project level file, — should be refine later)
bf85e1b: cleanup
9c30823: remove unused methods
f671c09: overrides
3bd62bc: ComponentRoamingManager should not keep defaults (we use RoamingType.PER_USER by default)
a8f1063: CR-IU-300 remove outdated EP ComponentRoamingType
b182751: CR-IU-300 remove outdated RoamingTypePerPlatform
994389c: another java.util.regex.Pattern.compile() parameter annotation
301710d: IDEA-113866 (this. not suggested for fields of anonymous inner classes)
f5d03c4: dfa: don't consider final getters same as immutable fields
272a6d0: Corresponding parents for console colors.
71298ce: Bright console colors for Monokai.
f39c34b: Console colors for WarmNeon scheme.
7548e47: Black is invisible on dark background (in RegExps for example).
ca6b784: Change bloody red to light pink for numbers (pink is specific to Neon color schemes while red is not, also eyes say thanks).
7f627d9: Console colors for Twilight scheme fixed.
a5eb2fc: Console colors for Monokai scheme fixed.
f7da145: DfaPsiType: add @NotNull
b216102: rebomb test
b349547: diagnostics for inconsistencies during control flow building
6823425: dfa: only perform costly state merging when it has chances - after jumps
fea8871: dfa: fighting too complex methods; join complementary memory states after fork to avoid having too many states
0ac2084: DfaMemoryStateImpl: introduce unwrap; compare variable values with their non-initialized counterparts
e919b8b: dfa: only goto catch on non-trivial method calls and throws
e2ea04f: new inference: initial method reference constraint
a9dde36: new inference: check substituted descriptor return type
3e5b164: new inference: expression inside condition should be poly, target type for conditional expression
ff9f2e9: new inference: emulate fresh variable - do not override vars with captured ones
f415702: new inference: default constructor as poly expression argument
ee56497: new inference: symmetric variable bounds
4a46b24: new inference: init inter call inference
06829c5: Merge remote-tracking branch 'origin/master'
e3f213f: Console colors for Darcula.
f748505: IDEA-57940 Cyclic expand word should take into account all open files
460ef47: StreamProvider.isVersioningRequired
8029f47: Bright yellow made more visible on white background.
96006be: Default console colors as in xterm palette, gray and dark gray from standard vga palette for better readability.
a378414: Bight console colors added to settings.
54e6582: builder-based project types
b0b2cf8: template-based project types?
e741484: CPU hogging fix again
eb22a99: fix todo duplication when several pattern match -> prefer finding match with last pattern (in settings list), thus default TODO pattern is matched last
a4d4371: fix compilation
2f823ba: Difference Groovy Shell & Groovy Console actions
3e876f4: IDEA-113590 annotations as annotation values
732cafd: dead code
a712f87: pull up 'isQualified()' method
4edd102: extract base class from PullUpDialog
10d89d6: remove obsolete test
a0750e4: delete envFile manually
114cbb2: IDEA-113861 Gradle: it could be possible to hide 'Gradle: download' progress to the background
ca416b8: 'More' element for classes, files, action, and settings. Better renderer.
b2a550c: test framework: drop temp directory on light project close
8aaf53b: greenify ActionsTreeUtil a bit
922d41a: layout
2cd7326: adding frameworks support
2bd8fb0: cleanup
4ea6442: ProjectSummaryStep
9fdcdcd: commit project name
bd39918: new project wizard: first test
630fc14: External system: use URLs in compile output paths
85dbe5f: IDEA-65114 "Add Maven projects" cannot be undone
5041ae5: test framework: returning of the data provider
16e2072: @Nullable XBreakpoint.getProperties reverted +review CR-IC-2418
df4da38: dump shell environment to a temporary file to reduce probability of malformed lines occurrence
280d52a: let event log warning color be orange (IDEA-113802)
a30b2ae: IDEA-113836 Console folding: add TestNG related patterns
cbeb0f1: don't change mouse cursor during goto name population (IDEA-113800)
fb5ad5b: IDEA-113638 ChooseByName restart on write action spawns a new thread
89b3767: disable autopopup in groovy shell if selection by chars is enabled (IDEA-112820)
9fa36be: CompletionConfidence: don't force API users to implement unused method
34cf7eb: Console Folding: proper capitalization
5e8aa44: IDEA-113855 Search Everywhere looks scrambled at first start
71723cb: svn: Refactored executable validation - use separate version client
1114cfe: javadoc
0738800: jps model: simplification, source roots always have default properties
b1d5062: jps model: JpsElementType converted to interface to allow reusing common base class
229deb0: test framework: ok, put light project file into ephemeral directory, but keep it for a project's life
6e8b950: ensure "thread" suspend policy for logging breakpoints
d67c04e: EA-49809 Move client factories creation to SvnVcs constructor (instead of active() method)
935cdba: new inference: initial tests
970a180: encapsulate read access to USE_COMPILE_SERVER option
b9b3fc8: remote agents - extract to remote servers
cfe8e2b: WEB-9335 Bad insert pair brace in CSS
2815c22: WEB-9334 Incremental selection works bad with negative CSS values
d023471: new "Unnecessary unicode escape sequence" inspection
945b069: unicode escape needs at least one 'u'
8e7797b: chrome still crashed, revert to old, not-recursive speed search
1917d86: Merge remote-tracking branch 'origin/master'
c18e6bd: Lense mode "internal" preview
db88427: Merge branch 'svn1_8_new'
7c64e8b: test framework: do not put light project file into ephemeral directory
af09e11: remove @Nullable from key.get as it's too generic
d49df32: svn: Refactored prompting for working copy format - make return not null format
d6086ae: dfa: types with wildcard parameters are not equal
3d28aa5: Optimization: check exiting of griffon-app first
b016c04: correct ephemeral state copy (IDEA-113143 Calling method with contract shouldn't result in nullability suspicion)
189573f: svn: Refactored upgrade working copy format dialog - use list of available formats (instead of separate fields for each format)
60c471b: Rename test
1a42f59: Remove using of unnecessary StringBuilder
a56db90: Use MultiMap
340cf22: Calling method with contract shouldn't result in nullability suspicion (IDEA-113763, IDEA-113699, almost IDEA-113143)
f2a563b: dfa: unify nullability violation processing
709af86: dfa: expand contract test
1cddfb4: dfa cleanup: skipping reports on method calls is now done via unknown variable mechanism
2765dab: dfa: spare some minor cpu cycles
8bc7465: svn: Added "1.8" option to upgrade/checkout dialogs
c266bd2: IDEA-66603 Maven3: provide inspection that checks duplicate declarations of plugins
af32923: SpellChecker: "cyclomatic"
5f4f98f: svn: Refactored working copy format selection dialog to use WorkingCopyFormat instances instead of just strings
e33b58b: MismatchedCollectionQueryUpdateInspection -- added "compute" prefix (from j.u.Map in JDK8)
7d54b2e: new inference: accept nonProper eq bounds
457d95b: new inference: distinguish different captures
5b5f52e: new inference: assertions caused by raw types
3848de4: new inference: open top level captured wildcards
35d59c0: new inference: extend usage of already inferred variables
4f7b572: new inference: inference of calls in arguments during outer call inference
bfa7879: new inference: captured variables from outer calls to be included
ed95269: new inference: eq bound for S<=T constraint reduction
12a0faf: better positioning
13029b7: different position layout algorithms
39e6e21: EA-49923 - Fixed working copy format detection for default project
d521e9d: JDK combobox should show JDK home
17fe05e: Fix typo
7ab769b: IDEA-16077 Maven embedder runs in the 'wrong' JDK add "embedder JDK" option
418ddc0: Inline string constant
6a8f1e2: IDEA-16077 Maven embedder runs in the 'wrong' JDK extract MavenJdkCombobox
46078c4: svn: Refactored detection if command line implementation should be used (use utility method)
24106fc: XDebugger: @Nullable XBreakpoint.getProperties()
3dc6f07: extract util method
476dac4: Reinit checkbox state on create
39cf1fd: Structure viewer for simple editors support fixed
a38a251: Show filters only for table editor + a few model and UI fixes
cbd5630: Initial dynamic filters model + columns header improved
281c008: svn: Support nullable SVNStatusClient in status implementation for SVNKit
1840d42: simplification
fbcba0f: svn: Make command line clients (info, status) use vcs instead of project instances
ae8b41b: Merge remote-tracking branch 'origin/master'
a97397c: Extract method.
3b9eca4: new project wizard: preparing test infrastructure
327ddb0: Lense mode "internal" preview
0ede5e1: new project wizard: AbstractProjectWizard extracted
a94b556: IDEA-111335 Gradle: task tree is incorrectly displayed if tasks are added to sub-projects via 'subprojects' method
bfd366f: Merge remote-tracking branch 'origin/master'
0ef2a82: calls to obsolete method removed from build scripts
2df016f: AntLoggerFactory inner class made static to fix NoSuchMethodException in Logger.setFactory
fe876e2: svn: Clients for update command renamed and moved to corresponding package
a38d90e: Terminal color settings.
bd285b8: svn: Refactored update logic to common ClientFactory model
9cc13da: platform: ignore hidden Windows files
d87664c: test framework: relic property dropped
5f6ef06: svn: Removed unused "common ancestor" behavior from command line update client
3667fe1: Find in strings with reg exp with start / end match markers doesn't work without string delimiters (IDEA-113788)
94a079f: svn: Refactored "update" command - explicitly create new SVNKit update client for each update/switch operation
0344e91: new project wizard: added option to use framework libraries from an app server
2882ac0: svn: Removed unused methods from "update" client
17ea275: svn: Removed unused SvnProxies class
c926181: WEB-9342 External Tool fails on OSX if an executable file basename specified
a3433f9: svn: Removed unused methods from "info" client
ec3112d: Optimize SassExtensionFunctionsIndex
9f1abf7: nosplash shouldn't prevent from plugin update
4c7154d: dfa: use cached nullability
b81e9c3: dfa: less frequent "too long" check
0b0eba9: DfaValueFactory: use List instead of TIntObjectHashMap for sequential keys
95d5433: introduce DfaPsiType without nullability, to quickly check assignability/convertibility in DfaVariableState
b901d90: IDEA-96713 Incorrect options shown for 'implements'
e02e2c4: IDEA-113780 "Annotate" from history fixed for renamed/moved files
fe00f73: test framework: stability improvements
76d664d: platform: suspicious event logging
b204bdf: Cleanup (de-duplication)
7ba9ff0: spelling
ece939c: make public for Upsource
496db4d: xdebugger: rebuild standalone variables view on EDT
eae27cb: xdebugger: supported rebuilding of standalone variables view
8bf5204: xdebugger api: added convenient method
43dbb6f: Terminal options.
3db1f5c: Blink period and antialiasing settings.
88264bd: IDEA-108147 Use "merge sources" wrapper object instead of just string representation as data model for "Merge Sources" column (to correctly get file revision object and show details panel)
111e6ba: IDEA-108147 While building history for element make check "if element parent or child was changed in given revision" only be performed for non-"merge source" revisions
e07828d: svn: Implemented support for "merged revisions" parsing in history logic for command line
1586c4a: svn: history logic refactored for command line - get and parse history data in xml format
0ac1dd2: IDEA-94942 Refactored "Annotate" implementation for command line - use utility method for parsing
ba1e5e0: IDEA-94942 Implemented merge history support for "Annotate" action
4c3b0a8: IDEA-94942 Implemented "Switch" logic (during update)
Change-Id: I7092ae66ff47d353a5b9770d1d91f77369bb7734
Diffstat (limited to 'java')
470 files changed, 12788 insertions, 2309 deletions
diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index d03ec5b52402..167cd7da66e7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -787,7 +787,12 @@ public class CompileDriver { }); } + private static final Key<Boolean> OLD_IMPLEMENTATION_WARNING_SHOWN = Key.create("_old_make_implementation_warning_shown_"); private void notifyDeprecatedImplementation() { + if (OLD_IMPLEMENTATION_WARNING_SHOWN.get(myProject, Boolean.FALSE).booleanValue()) { + return; + } + OLD_IMPLEMENTATION_WARNING_SHOWN.set(myProject, Boolean.TRUE); final NotificationListener hyperlinkHandler = new NotificationListener.Adapter() { @Override protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index 8ba9de95c06f..d36a3b0aded2 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -1759,7 +1759,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { } public boolean isMarkedForCompilation(Project project, VirtualFile file) { - if (CompilerWorkspaceConfiguration.getInstance(project).USE_COMPILE_SERVER) { + if (CompilerWorkspaceConfiguration.getInstance(project).useOutOfProcessBuild()) { final CompilerManager compilerManager = CompilerManager.getInstance(project); return !compilerManager.isUpToDate(compilerManager.createFilesCompileScope(new VirtualFile[]{file})); } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.form b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.form index 36f3b457dc41..5e6fdda72d37 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.form +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.form @@ -38,7 +38,7 @@ <text resource-bundle="messages/CompilerBundle" key="java.compiler.option.generate.no.warnings"/> </properties> </component> - <grid id="d7ddf" layout-manager="GridLayoutManager" row-count="2" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="d7ddf" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="10" left="8" bottom="0" right="0"/> <constraints> <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> @@ -62,33 +62,6 @@ </constraints> <properties/> </component> - <component id="327dc" class="javax.swing.JLabel"> - <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text resource-bundle="messages/CompilerBundle" key="javac.option.max.heap.size"/> - </properties> - </component> - <component id="15c16" class="javax.swing.JTextField" binding="myJavacMaximumHeapField"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <columns value="4"/> - <margin top="0" left="2" bottom="0" right="0"/> - <text value="128"/> - </properties> - </component> - <component id="6f8c2" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="1" column="2" row-span="1" col-span="2" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <enabled value="false"/> - <text value="(ineffective when "Use external build" is on)"/> - </properties> - </component> </children> </grid> <vspacer id="af30"> diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.java index ad9cb1d86638..5227dfcfc216 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompilerConfigurable.java @@ -35,7 +35,6 @@ public class EclipseCompilerConfigurable implements Configurable { private JCheckBox myCbDebuggingInfo; private JCheckBox myCbGenerateNoWarnings; private RawCommandLineEditor myAdditionalOptionsField; - private JTextField myJavacMaximumHeapField; private JCheckBox myCbProceedOnErrors; private final EclipseCompilerOptions myCompilerSettings; @@ -59,7 +58,7 @@ public class EclipseCompilerConfigurable implements Configurable { } public boolean isModified() { - boolean isModified = ComparingUtils.isModified(myJavacMaximumHeapField, myCompilerSettings.MAXIMUM_HEAP_SIZE); + boolean isModified = false; isModified |= ComparingUtils.isModified(myCbDeprecation, myCompilerSettings.DEPRECATION); isModified |= ComparingUtils.isModified(myCbDebuggingInfo, myCompilerSettings.DEBUGGING_INFO); @@ -70,17 +69,6 @@ public class EclipseCompilerConfigurable implements Configurable { } public void apply() throws ConfigurationException { - - try { - myCompilerSettings.MAXIMUM_HEAP_SIZE = Integer.parseInt(myJavacMaximumHeapField.getText()); - if(myCompilerSettings.MAXIMUM_HEAP_SIZE < 1) { - myCompilerSettings.MAXIMUM_HEAP_SIZE = 128; - } - } - catch(NumberFormatException exception) { - myCompilerSettings.MAXIMUM_HEAP_SIZE = 128; - } - myCompilerSettings.DEPRECATION = myCbDeprecation.isSelected(); myCompilerSettings.DEBUGGING_INFO = myCbDebuggingInfo.isSelected(); myCompilerSettings.GENERATE_NO_WARNINGS = myCbGenerateNoWarnings.isSelected(); @@ -89,7 +77,6 @@ public class EclipseCompilerConfigurable implements Configurable { } public void reset() { - myJavacMaximumHeapField.setText(Integer.toString(myCompilerSettings.MAXIMUM_HEAP_SIZE)); myCbDeprecation.setSelected(myCompilerSettings.DEPRECATION); myCbDebuggingInfo.setSelected(myCompilerSettings.DEBUGGING_INFO); myCbGenerateNoWarnings.setSelected(myCompilerSettings.GENERATE_NO_WARNINGS); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacConfigurable.java index c51f5f30d0e4..1c8910a4f6e9 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacConfigurable.java @@ -34,7 +34,6 @@ public class JavacConfigurable implements Configurable{ private JCheckBox myCbDeprecation; private JCheckBox myCbGenerateNoWarnings; private RawCommandLineEditor myAdditionalOptionsField; - private JTextField myJavacMaximumHeapField; private final JpsJavaCompilerOptions myJavacSettings; public JavacConfigurable(final JpsJavaCompilerOptions javacSettings) { @@ -56,8 +55,6 @@ public class JavacConfigurable implements Configurable{ public boolean isModified() { boolean isModified = false; - isModified |= ComparingUtils.isModified(myJavacMaximumHeapField, myJavacSettings.MAXIMUM_HEAP_SIZE); - isModified |= ComparingUtils.isModified(myCbDeprecation, myJavacSettings.DEPRECATION); isModified |= ComparingUtils.isModified(myCbDebuggingInfo, myJavacSettings.DEBUGGING_INFO); isModified |= ComparingUtils.isModified(myCbGenerateNoWarnings, myJavacSettings.GENERATE_NO_WARNINGS); @@ -66,17 +63,6 @@ public class JavacConfigurable implements Configurable{ } public void apply() throws ConfigurationException { - - try { - myJavacSettings.MAXIMUM_HEAP_SIZE = Integer.parseInt(myJavacMaximumHeapField.getText()); - if(myJavacSettings.MAXIMUM_HEAP_SIZE < 1) { - myJavacSettings.MAXIMUM_HEAP_SIZE = 128; - } - } - catch(NumberFormatException exception) { - myJavacSettings.MAXIMUM_HEAP_SIZE = 128; - } - myJavacSettings.DEPRECATION = myCbDeprecation.isSelected(); myJavacSettings.DEBUGGING_INFO = myCbDebuggingInfo.isSelected(); myJavacSettings.GENERATE_NO_WARNINGS = myCbGenerateNoWarnings.isSelected(); @@ -84,7 +70,6 @@ public class JavacConfigurable implements Configurable{ } public void reset() { - myJavacMaximumHeapField.setText(Integer.toString(myJavacSettings.MAXIMUM_HEAP_SIZE)); myCbDeprecation.setSelected(myJavacSettings.DEPRECATION); myCbDebuggingInfo.setSelected(myJavacSettings.DEBUGGING_INFO); myCbGenerateNoWarnings.setSelected(myJavacSettings.GENERATE_NO_WARNINGS); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacOptionsPanel.form b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacOptionsPanel.form index bf4baec64dc1..3dc8e990f392 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacOptionsPanel.form +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacOptionsPanel.form @@ -3,7 +3,7 @@ <grid id="280f7" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="79" y="160" width="574" height="210"/> + <xy x="79" y="160" width="577" height="210"/> </constraints> <properties/> <clientProperties> @@ -37,7 +37,7 @@ <text resource-bundle="messages/CompilerBundle" key="java.compiler.option.generate.no.warnings"/> </properties> </component> - <grid id="d7ddf" layout-manager="GridLayoutManager" row-count="2" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="d7ddf" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="10" left="8" bottom="0" right="0"/> <constraints> <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> @@ -61,33 +61,6 @@ </constraints> <properties/> </component> - <component id="327dc" class="javax.swing.JLabel"> - <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text resource-bundle="messages/CompilerBundle" key="javac.option.max.heap.size"/> - </properties> - </component> - <component id="15c16" class="javax.swing.JTextField" binding="myJavacMaximumHeapField"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <columns value="4"/> - <margin top="0" left="2" bottom="0" right="0"/> - <text value="128"/> - </properties> - </component> - <component id="9ae23" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="1" column="2" row-span="1" col-span="2" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <enabled value="false"/> - <text value="(ineffective when "Use external build" is on)"/> - </properties> - </component> </children> </grid> <vspacer id="72a3c"> diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form b/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form index 179dbe28409b..c89fdca67c77 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form +++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.compiler.options.CompilerUIConfigurable"> - <grid id="1663f" binding="myPanel" layout-manager="GridLayoutManager" row-count="11" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="1663f" binding="myPanel" layout-manager="GridLayoutManager" row-count="10" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <xy x="28" y="24" width="883" height="379"/> @@ -10,7 +10,7 @@ <children> <vspacer id="67edf"> <constraints> - <grid row="10" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="9" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <grid id="b341d" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="1"> @@ -76,17 +76,9 @@ <text resource-bundle="messages/CompilerBundle" key="label.option.autoshow.first.error"/> </properties> </component> - <component id="ce617" class="javax.swing.JCheckBox" binding="myCbUseExternalBuild" default-binding="true"> - <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Use external build"/> - </properties> - </component> <component id="b9b2d" class="javax.swing.JCheckBox" binding="myCbEnableAutomake"> <constraints> - <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="2" use-parent-layout="false"/> + <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Make project automatically"/> @@ -94,7 +86,7 @@ </component> <component id="17126" class="javax.swing.JLabel" binding="myHeapSizeLabel"> <constraints> - <grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/> + <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Compiler process heap size (Mbytes):"/> @@ -102,7 +94,7 @@ </component> <component id="a28b8" class="javax.swing.JTextField" binding="myHeapSizeField"> <constraints> - <grid row="8" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"> + <grid row="7" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"> <preferred-size width="50" height="-1"/> </grid> </constraints> @@ -110,7 +102,7 @@ </component> <component id="5b86a" class="javax.swing.JLabel" binding="myVMOptionsLabel"> <constraints> - <grid row="9" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/> + <grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Additional compiler process VM options:"/> @@ -118,7 +110,7 @@ </component> <component id="b5547" class="javax.swing.JTextField" binding="myVMOptionsField"> <constraints> - <grid row="9" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <grid row="8" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> @@ -126,7 +118,7 @@ </component> <component id="ba694" class="javax.swing.JCheckBox" binding="myCbParallelCompilation"> <constraints> - <grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="2" use-parent-layout="false"/> + <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Compile independent modules in parallel"/> @@ -134,7 +126,7 @@ </component> <component id="91979" class="javax.swing.JLabel" binding="myParallelCompilationLegendLabel"> <constraints> - <grid row="6" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="5" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="(may require larger heap size)"/> @@ -142,7 +134,7 @@ </component> <component id="732b1" class="javax.swing.JLabel" binding="myEnableAutomakeLegendLabel"> <constraints> - <grid row="5" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="4" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="(only works while not running / debugging)"/> @@ -150,7 +142,7 @@ </component> <component id="4b44" class="javax.swing.JCheckBox" binding="myCbRebuildOnDependencyChange" default-binding="true"> <constraints> - <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="2" use-parent-layout="false"/> + <grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Rebuild module on dependency change"/> diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java index 38769dcec587..b97a10386568 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java @@ -36,11 +36,9 @@ import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.util.*; -import static com.intellij.compiler.options.CompilerOptionsFilter.*; +import static com.intellij.compiler.options.CompilerOptionsFilter.Setting; public class CompilerUIConfigurable implements SearchableConfigurable, Configurable.NoScroll { private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.options.CompilerUIConfigurable"); @@ -77,7 +75,6 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura private JCheckBox myCbAssertNotNull; private JBLabel myPatternLegendLabel; private JCheckBox myCbAutoShowFirstError; - private JCheckBox myCbUseExternalBuild; private JCheckBox myCbEnableAutomake; private JCheckBox myCbParallelCompilation; private JTextField myHeapSizeField; @@ -93,19 +90,12 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura myProject = project; myPatternLegendLabel.setText("<html><body>" + - "Use <b>;</b> to separate patterns and <b>!</b> to negate a pattern. " + - "Accepted wildcards: <b>?</b> — exactly one symbol; <b>*</b> — zero or more symbols; " + - "<b>/</b> — path separator; <b>/**/</b> — any number of directories; " + - "<i><dir_name></i>:<i><pattern></i> — restrict to source roots with the specified name" + - "</body></html>"); + "Use <b>;</b> to separate patterns and <b>!</b> to negate a pattern. " + + "Accepted wildcards: <b>?</b> — exactly one symbol; <b>*</b> — zero or more symbols; " + + "<b>/</b> — path separator; <b>/**/</b> — any number of directories; " + + "<i><dir_name></i>:<i><pattern></i> — restrict to source roots with the specified name" + + "</body></html>"); myPatternLegendLabel.setForeground(new JBColor(Gray._50, Gray._130)); - myCbUseExternalBuild.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - updateExternalMakeOptionControls(myCbUseExternalBuild.isSelected()); - } - }); - tweakControls(project); } @@ -141,7 +131,6 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura controls.put(Setting.CLEAR_OUTPUT_DIR_ON_REBUILD, Collections.<JComponent>singleton(myCbClearOutputDirectory)); controls.put(Setting.ADD_NOT_NULL_ASSERTIONS, Collections.<JComponent>singleton(myCbAssertNotNull)); controls.put(Setting.AUTO_SHOW_FIRST_ERROR_IN_EDITOR, Collections.<JComponent>singleton(myCbAutoShowFirstError)); - controls.put(Setting.EXTERNAL_BUILD, ContainerUtilRt.<JComponent>newArrayList(myCbUseExternalBuild)); controls.put(Setting.AUTO_MAKE, ContainerUtilRt.<JComponent>newArrayList(myCbEnableAutomake, myEnableAutomakeLegendLabel)); controls.put(Setting.PARALLEL_COMPILATION, ContainerUtilRt.<JComponent>newArrayList(myCbParallelCompilation, myParallelCompilationLegendLabel)); @@ -166,14 +155,12 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura myCbAutoShowFirstError.setSelected(workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR); myCbClearOutputDirectory.setSelected(workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY); myCbAssertNotNull.setSelected(configuration.isAddNotNullAssertions()); - myCbUseExternalBuild.setSelected(workspaceConfiguration.USE_COMPILE_SERVER); myCbEnableAutomake.setSelected(workspaceConfiguration.MAKE_PROJECT_ON_SAVE); myCbParallelCompilation.setSelected(workspaceConfiguration.PARALLEL_COMPILATION); myCbRebuildOnDependencyChange.setSelected(workspaceConfiguration.REBUILD_ON_DEPENDENCY_CHANGE); myHeapSizeField.setText(String.valueOf(workspaceConfiguration.COMPILER_PROCESS_HEAP_SIZE)); final String options = workspaceConfiguration.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS; myVMOptionsField.setText(options == null ? "" : options.trim()); - updateExternalMakeOptionControls(myCbUseExternalBuild.isSelected()); configuration.convertPatterns(); @@ -201,9 +188,7 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura if (!myDisabledSettings.contains(Setting.CLEAR_OUTPUT_DIR_ON_REBUILD)) { workspaceConfiguration.CLEAR_OUTPUT_DIRECTORY = myCbClearOutputDirectory.isSelected(); } - boolean wasUsingExternalMake = workspaceConfiguration.USE_COMPILE_SERVER; if (!myDisabledSettings.contains(Setting.EXTERNAL_BUILD)) { - workspaceConfiguration.USE_COMPILE_SERVER = myCbUseExternalBuild.isSelected(); if (!myDisabledSettings.contains(Setting.AUTO_MAKE)) { workspaceConfiguration.MAKE_PROJECT_ON_SAVE = myCbEnableAutomake.isSelected(); } @@ -234,12 +219,8 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura String extensionString = myResourcePatternsField.getText().trim(); applyResourcePatterns(extensionString, (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)); } - if (wasUsingExternalMake != workspaceConfiguration.USE_COMPILE_SERVER) { - myProject.getMessageBus().syncPublisher(ExternalBuildOptionListener.TOPIC).externalBuildOptionChanged(workspaceConfiguration.USE_COMPILE_SERVER); - } - if (workspaceConfiguration.USE_COMPILE_SERVER) { - BuildManager.getInstance().clearState(myProject); - } + + BuildManager.getInstance().clearState(myProject); } private static void applyResourcePatterns(String extensionString, final CompilerConfigurationImpl configuration) @@ -277,8 +258,6 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura final CompilerWorkspaceConfiguration workspaceConfiguration = CompilerWorkspaceConfiguration.getInstance(myProject); boolean isModified = !myDisabledSettings.contains(Setting.AUTO_SHOW_FIRST_ERROR_IN_EDITOR) && ComparingUtils.isModified(myCbAutoShowFirstError, workspaceConfiguration.AUTO_SHOW_ERRORS_IN_EDITOR); - isModified |= !myDisabledSettings.contains(Setting.EXTERNAL_BUILD) - && ComparingUtils.isModified(myCbUseExternalBuild, workspaceConfiguration.USE_COMPILE_SERVER); isModified |= !myDisabledSettings.contains(Setting.AUTO_MAKE) && ComparingUtils.isModified(myCbEnableAutomake, workspaceConfiguration.MAKE_PROJECT_ON_SAVE); isModified |= !myDisabledSettings.contains(Setting.PARALLEL_COMPILATION) @@ -325,16 +304,6 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura public void disposeUIResources() { } - private void updateExternalMakeOptionControls(boolean enabled) { - myCbEnableAutomake.setEnabled(enabled); - myCbParallelCompilation.setEnabled(enabled); - myCbRebuildOnDependencyChange.setEnabled(enabled); - myHeapSizeField.setEnabled(enabled); - myVMOptionsField.setEnabled(enabled); - myHeapSizeLabel.setEnabled(enabled); - myVMOptionsLabel.setEnabled(enabled); - } - private void createUIComponents() { myResourcePatternsField = new RawCommandLineEditor(LINE_PARSER, LINE_JOINER); myResourcePatternsField.setDialogCaption("Resource patterns"); diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java b/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java index 88fe95c643cb..cadbc0fa5267 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java @@ -58,6 +58,7 @@ public class InspectionValidatorWrapper implements Validator { private final InspectionProjectProfileManager myProfileManager; private final PsiDocumentManager myPsiDocumentManager; private static final ThreadLocal<Boolean> ourCompilationThreads = new ThreadLocal<Boolean>() { + @Override protected Boolean initialValue() { return Boolean.FALSE; } @@ -95,11 +96,13 @@ public class InspectionValidatorWrapper implements Validator { myVirtualFile = psiFile.getVirtualFile(); } + @Override @NotNull public VirtualFile getFile() { return myVirtualFile; } + @Override @Nullable public ValidityState getValidityState() { if (myValidityState == null) { @@ -121,6 +124,7 @@ public class InspectionValidatorWrapper implements Validator { } } + @Override @NotNull public ProcessingItem[] getProcessingItems(final CompileContext context) { final Project project = context.getProject(); @@ -129,6 +133,7 @@ public class InspectionValidatorWrapper implements Validator { } final ExcludedEntriesConfiguration excludedEntriesConfiguration = ValidationConfiguration.getExcludedEntriesConfiguration(project); final List<ProcessingItem> items = new ReadAction<List<ProcessingItem>>() { + @Override protected void run(final Result<List<ProcessingItem>> result) { final CompileScope compileScope = context.getCompileScope(); if (!myValidator.isAvailableOnScope(compileScope)) return; @@ -167,6 +172,7 @@ public class InspectionValidatorWrapper implements Validator { return items.toArray(new ProcessingItem[items.size()]); } + @Override public ProcessingItem[] process(final CompileContext context, final ProcessingItem[] items) { context.getProgressIndicator().setText(myValidator.getProgressIndicatorText()); @@ -307,7 +313,13 @@ public class InspectionValidatorWrapper implements Validator { final List<ExternalAnnotator> annotators = ExternalLanguageAnnotators.allForFile(StdLanguages.XML, xmlFile); for (ExternalAnnotator annotator : annotators) { - annotator.annotate(xmlFile, holder); + Object initial = annotator.collectInformation(xmlFile); + if (initial != null) { + Object result = annotator.doAnnotate(initial); + if (result != null) { + annotator.apply(xmlFile, result, holder); + } + } } if (!holder.hasAnnotations()) return Collections.emptyMap(); @@ -331,15 +343,18 @@ public class InspectionValidatorWrapper implements Validator { } + @Override @NotNull public String getDescription() { return myValidator.getDescription(); } + @Override public boolean validateConfiguration(final CompileScope scope) { return true; } + @Override public ValidityState createValidityState(final DataInput in) throws IOException { return PsiElementsValidityState.load(in); } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/FacetBasedPackagingElementType.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/FacetBasedPackagingElementType.java index dc0383ff4811..e82f277e52b7 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/FacetBasedPackagingElementType.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/FacetBasedPackagingElementType.java @@ -28,7 +28,6 @@ import com.intellij.packaging.elements.PackagingElementType; import com.intellij.packaging.ui.ArtifactEditorContext; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; @@ -89,11 +88,6 @@ public abstract class FacetBasedPackagingElementType<E extends PackagingElement< protected abstract String getItemText(F item); - @Nullable - protected Icon getIcon(F item) { - return FacetTypeRegistry.getInstance().findFacetType(myFacetType).getIcon(); - } - private class ChooseFacetsDialog extends ChooseElementsDialog<F> { private ChooseFacetsDialog(Project project, List<? extends F> items, String title, String description) { super(project, items, title, description, true); @@ -106,7 +100,7 @@ public abstract class FacetBasedPackagingElementType<E extends PackagingElement< @Override protected Icon getItemIcon(F item) { - return FacetBasedPackagingElementType.this.getIcon(item); + return FacetTypeRegistry.getInstance().findFacetType(myFacetType).getIcon(); } } } diff --git a/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java b/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java index 629a4884b4cd..57ca44098216 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java +++ b/java/compiler/openapi/src/com/intellij/compiler/CompilerWorkspaceConfiguration.java @@ -43,7 +43,7 @@ public class CompilerWorkspaceConfiguration implements PersistentStateComponent< public boolean AUTO_SHOW_ERRORS_IN_EDITOR = true; @Deprecated public boolean CLOSE_MESSAGE_VIEW_IF_SUCCESS = true; public boolean CLEAR_OUTPUT_DIRECTORY = true; - public boolean USE_COMPILE_SERVER = true; + public boolean USE_OUT_OF_PROCESS_BUILD = true; public boolean MAKE_PROJECT_ON_SAVE = false; // until we fix problems with several open projects (IDEA-104064), daemon slowness (IDEA-104666) public boolean PARALLEL_COMPILATION = false; public int COMPILER_PROCESS_HEAP_SIZE = DEFAULT_COMPILE_PROCESS_HEAP_SIZE; @@ -63,7 +63,7 @@ public class CompilerWorkspaceConfiguration implements PersistentStateComponent< } public boolean useOutOfProcessBuild() { - return USE_COMPILE_SERVER; + return USE_OUT_OF_PROCESS_BUILD; } public boolean allowAutoMakeWhileRunningApplication() { diff --git a/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java b/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java index c0dfbb9fd386..ebb5bef81ece 100644 --- a/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java @@ -22,76 +22,79 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiDocumentManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; public class DebuggerInvocationUtil { - public static void swingInvokeLater(final Project project, @NotNull final Runnable runnable) { + public static void swingInvokeLater(@Nullable final Project project, @NotNull final Runnable runnable) { + if (project == null) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - if (project != null && !project.isDisposed()) { - runnable.run(); - } - } - }); - } - public static void invokeLater(final Project project, @NotNull final Runnable runnable) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - if (project != null && !project.isDisposed()) { + if (!project.isDisposed()) { runnable.run(); } } }); } - public static void invokeLater(final Project project, @NotNull final Runnable runnable, ModalityState state) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - if(project == null || project.isDisposed()) return; + public static void invokeLater(@Nullable Project project, @NotNull Runnable runnable) { + if (project != null) { + ApplicationManager.getApplication().invokeLater(runnable, project.getDisposed()); + } + } - runnable.run(); - } - }, state); + public static void invokeLater(@Nullable Project project, @NotNull Runnable runnable, ModalityState state) { + if (project != null) { + ApplicationManager.getApplication().invokeLater(runnable, state, project.getDisposed()); + } } public static void invokeAndWait(final Project project, @NotNull final Runnable runnable, ModalityState state) { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - public void run() { - if(project == null || project.isDisposed()) return; - - runnable.run(); - } - }, state); + if (project != null) { + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + if (!project.isDisposed()) { + runnable.run(); + } + } + }, state); + } } - public static <T> T commitAndRunReadAction(Project project, final EvaluatingComputable<T> computable) throws EvaluateException { - final Throwable[] ex = new Throwable[] { null }; + public static <T> T commitAndRunReadAction(Project project, final EvaluatingComputable<T> computable) throws EvaluateException { + final Throwable[] ex = new Throwable[]{null}; T result = PsiDocumentManager.getInstance(project).commitAndRunReadAction(new Computable<T>() { - public T compute() { - try { - return computable.compute(); - } - catch (RuntimeException e) { - ex[0] = e; - } - catch (Exception th) { - ex[0] = th; - } + @Override + public T compute() { + try { + return computable.compute(); + } + catch (RuntimeException e) { + ex[0] = e; + } + catch (Exception th) { + ex[0] = th; + } - return null; - } - }); + return null; + } + }); - if(ex[0] != null) { - if(ex[0] instanceof RuntimeException) { + if (ex[0] != null) { + if (ex[0] instanceof RuntimeException) { throw (RuntimeException)ex[0]; } else { - throw (EvaluateException) ex[0]; + throw (EvaluateException)ex[0]; } } return result; } -} +}
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java index deb575205157..54cef880be0f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java @@ -19,8 +19,8 @@ import com.intellij.debugger.ui.breakpoints.BreakpointFactory; import com.intellij.debugger.ui.breakpoints.BreakpointPropertiesPanel; import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.markup.GutterIconRenderer; @@ -28,7 +28,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupListener; import com.intellij.openapi.ui.popup.LightweightWindowEvent; -import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.util.ui.UIUtil; @@ -41,48 +41,31 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -/** - * Created with IntelliJ IDEA. - * User: zajac - * Date: 04.05.12 - * Time: 4:10 - * To change this template use File | Settings | File Templates. - */ public class JavaEditBreakpointActionHandler extends EditBreakpointActionHandler { @Override protected void doShowPopup(final Project project, final JComponent component, final Point whereToShow, final Object breakpoint) { - if (!(breakpoint instanceof BreakpointWithHighlighter)) return; + if (!(breakpoint instanceof BreakpointWithHighlighter)) { + return; + } final BreakpointWithHighlighter javaBreakpoint = (BreakpointWithHighlighter)breakpoint; - Key<? extends BreakpointWithHighlighter> category = javaBreakpoint.getCategory(); - - final BreakpointFactory[] allFactories = ApplicationManager.getApplication().getExtensions(BreakpointFactory.EXTENSION_POINT_NAME); BreakpointFactory breakpointFactory = null; - for (BreakpointFactory factory : allFactories) { - if (factory.getBreakpointCategory().equals(category)) { + for (BreakpointFactory factory : BreakpointFactory.EXTENSION_POINT_NAME.getExtensions()) { + if (factory.getBreakpointCategory().equals(javaBreakpoint.getCategory())) { breakpointFactory = factory; } } assert breakpointFactory != null : "can't find factory for breakpoint " + javaBreakpoint; final BreakpointPropertiesPanel propertiesPanel = breakpointFactory.createBreakpointPropertiesPanel(project, true); + assert propertiesPanel != null; propertiesPanel.initFrom(javaBreakpoint, false); final JComponent mainPanel = propertiesPanel.getPanel(); - final String displayName = javaBreakpoint.getDisplayName(); - - final JBPopupListener saveOnClose = new JBPopupListener() { - @Override - public void beforeShown(LightweightWindowEvent event) { - } - + final JBPopupListener saveOnClose = new JBPopupListener.Adapter() { @Override public void onClosed(LightweightWindowEvent event) { - propertiesPanel.saveTo(javaBreakpoint, new Runnable() { - @Override - public void run() { - } - }); + propertiesPanel.saveTo(javaBreakpoint, EmptyRunnable.getInstance()); } }; @@ -93,13 +76,12 @@ public class JavaEditBreakpointActionHandler extends EditBreakpointActionHandler @Override public void run() { BreakpointsDialogFactory.getInstance(project).showDialog(javaBreakpoint); - } }); } }; - final Balloon balloon = DebuggerUIUtil.showBreakpointEditor(project, mainPanel, displayName, whereToShow, component, showMoreOptions, - breakpoint); + + final Balloon balloon = DebuggerUIUtil.showBreakpointEditor(project, mainPanel, whereToShow, component, showMoreOptions, breakpoint); balloon.addListener(saveOnClose); propertiesPanel.setDelegate(new BreakpointPropertiesPanel.Delegate() { @@ -107,9 +89,7 @@ public class JavaEditBreakpointActionHandler extends EditBreakpointActionHandler public void showActionsPanel() { propertiesPanel.setActionsPanelVisible(true); balloon.hide(); - final Balloon newBalloon = - DebuggerUIUtil.showBreakpointEditor(project, mainPanel, displayName, whereToShow, component, showMoreOptions, breakpoint); - newBalloon.addListener(saveOnClose); + DebuggerUIUtil.showBreakpointEditor(project, mainPanel, whereToShow, component, showMoreOptions, breakpoint).addListener(saveOnClose); } }); @@ -124,7 +104,7 @@ public class JavaEditBreakpointActionHandler extends EditBreakpointActionHandler @Override public boolean isEnabled(@NotNull Project project, AnActionEvent event) { DataContext dataContext = event.getDataContext(); - Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); if (editor == null) { return false; } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java index 02477905ec49..54d1545f74f6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java @@ -19,9 +19,9 @@ import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.InstanceFilter; import com.intellij.debugger.SourcePosition; +import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerSession; -import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.debugger.ui.breakpoints.FieldBreakpoint; @@ -33,7 +33,6 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -50,8 +49,9 @@ import org.jetbrains.annotations.Nullable; */ public class ToggleFieldBreakpointAction extends AnAction { + @Override public void actionPerformed(AnActionEvent e) { - Project project = e.getData(PlatformDataKeys.PROJECT); + Project project = e.getData(CommonDataKeys.PROJECT); if (project == null) { return; } @@ -83,7 +83,7 @@ public class ToggleFieldBreakpointAction extends AnAction { RequestManagerImpl.createRequests(fieldBreakpoint); - manager.editBreakpoint(fieldBreakpoint, PlatformDataKeys.EDITOR.getData(e.getDataContext())); + manager.editBreakpoint(fieldBreakpoint, CommonDataKeys.EDITOR.getData(e.getDataContext())); } } else { @@ -93,6 +93,7 @@ public class ToggleFieldBreakpointAction extends AnAction { } } + @Override public void update(AnActionEvent event){ SourcePosition place = getPlace(event); boolean toEnable = place != null; @@ -105,7 +106,7 @@ public class ToggleFieldBreakpointAction extends AnAction { } else if(DebuggerAction.isContextView(event)) { presentation.setText(DebuggerBundle.message("action.add.field.watchpoint.text")); - Project project = event.getData(PlatformDataKeys.PROJECT); + Project project = event.getData(CommonDataKeys.PROJECT); if(project != null && place != null) { Document document = PsiDocumentManager.getInstance(project).getDocument(place.getFile()); if (document != null) { @@ -125,14 +126,14 @@ public class ToggleFieldBreakpointAction extends AnAction { @Nullable public static SourcePosition getPlace(AnActionEvent event) { final DataContext dataContext = event.getDataContext(); - Project project = event.getData(PlatformDataKeys.PROJECT); + Project project = event.getData(CommonDataKeys.PROJECT); if(project == null) { return null; } if (ActionPlaces.PROJECT_VIEW_POPUP.equals(event.getPlace()) || ActionPlaces.STRUCTURE_VIEW_POPUP.equals(event.getPlace()) || ActionPlaces.FAVORITES_VIEW_POPUP.equals(event.getPlace())) { - final PsiElement psiElement = event.getData(LangDataKeys.PSI_ELEMENT); + final PsiElement psiElement = event.getData(CommonDataKeys.PSI_ELEMENT); if(psiElement instanceof PsiField) { return SourcePosition.createFromElement(psiElement); } @@ -152,7 +153,7 @@ public class ToggleFieldBreakpointAction extends AnAction { if(node != null && node.getDescriptor() instanceof FieldDescriptorImpl) { Field field = ((FieldDescriptorImpl)node.getDescriptor()).getField(); DebuggerSession session = tree.getDebuggerContext().getDebuggerSession(); - PsiClass psiClass = DebuggerUtilsEx.findClass(field.declaringType().name(), project, (session != null) ? session.getSearchScope(): GlobalSearchScope.allScope(project)); + PsiClass psiClass = DebuggerUtils.findClass(field.declaringType().name(), project, (session != null) ? session.getSearchScope() : GlobalSearchScope.allScope(project)); if(psiClass != null) { psiClass = (PsiClass) psiClass.getNavigationElement(); final PsiField psiField = psiClass.findFieldByName(field.name(), true); @@ -165,7 +166,7 @@ public class ToggleFieldBreakpointAction extends AnAction { return null; } - Editor editor = event.getData(PlatformDataKeys.EDITOR); + Editor editor = event.getData(CommonDataKeys.EDITOR); if(editor == null) { editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); } @@ -173,7 +174,6 @@ public class ToggleFieldBreakpointAction extends AnAction { final Document document = editor.getDocument(); PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); if (file != null) { - FileTypeManager fileTypeManager = FileTypeManager.getInstance(); final VirtualFile virtualFile = file.getVirtualFile(); FileType fileType = virtualFile != null ? virtualFile.getFileType() : null; if (StdFileTypes.JAVA == fileType || StdFileTypes.CLASS == fileType) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java index 9d10487564ae..63a2ce8b7f77 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java @@ -142,7 +142,7 @@ public class RequestManagerImpl extends DebugProcessAdapterImpl implements Reque } private void addLocatableRequest(FilteredRequestor requestor, EventRequest request) { - if(DebuggerSettings.SUSPEND_ALL.equals(requestor.SUSPEND_POLICY)) { + if(DebuggerSettings.SUSPEND_ALL.equals(requestor.getSuspendPolicy())) { request.setSuspendPolicy(EventRequest.SUSPEND_ALL); } else { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java index 79398de4991e..f595c1d81c65 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java @@ -15,13 +15,10 @@ */ package com.intellij.debugger.ui.breakpoints; -import com.intellij.debugger.ui.breakpoints.actions.BreakpointPanelAction; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import org.jdom.Element; -import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -58,19 +55,10 @@ public class AnyExceptionBreakpointFactory extends BreakpointFactory{ } @Override - protected BreakpointPanelAction[] createBreakpointPanelActions(Project project, DialogWrapper parentDialog) { - return new BreakpointPanelAction[0]; //To change body of implemented methods use File | Settings | File Templates. - } - - @Override public boolean breakpointCanBeRemoved(Breakpoint breakpoint) { return false; } - public @Nullable BreakpointPanel createBreakpointPanel(Project project, DialogWrapper parentDialog) { - return null; - } - public Key<AnyExceptionBreakpoint> getBreakpointCategory() { return AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java index 6389fdd1693e..2077b56dc34e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java @@ -15,11 +15,9 @@ */ package com.intellij.debugger.ui.breakpoints; -import com.intellij.debugger.ui.breakpoints.actions.BreakpointPanelAction; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem; import org.jdom.Element; @@ -42,14 +40,6 @@ public abstract class BreakpointFactory { public abstract Key<? extends Breakpoint> getBreakpointCategory(); - public BreakpointPanel createBreakpointPanel(final Project project, final DialogWrapper parentDialog) { - BreakpointPanel panel = - new BreakpointPanel(project, createBreakpointPropertiesPanel(project, false), createBreakpointPanelActions(project, parentDialog), - getBreakpointCategory(), getDisplayName(), getHelpID()); - configureBreakpointPanel(panel); - return panel; - } - public abstract Icon getIcon(); public abstract Icon getDisabledIcon(); @@ -75,8 +65,6 @@ public abstract class BreakpointFactory { @Nullable public abstract BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact); - protected abstract BreakpointPanelAction[] createBreakpointPanelActions(Project project, DialogWrapper parentDialog); - @Nullable public Breakpoint addBreakpoint(Project project) { return null; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java index dd52bcf0a849..686965f03626 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java @@ -25,7 +25,6 @@ import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerInvocationUtil; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.evaluation.CodeFragmentKind; import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; @@ -47,12 +46,12 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; -import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.*; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; @@ -73,6 +72,7 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.breakpoints.JavaBreakpointType; import javax.swing.*; import java.awt.event.MouseEvent; @@ -182,14 +182,10 @@ public class BreakpointManager implements JDOMExternalizable { } final Document document = editor.getDocument(); final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); - if (psiFile == null) { - return null; - } - final FileType fileType = psiFile.getFileType(); - boolean isInsideCompiledClass = StdFileTypes.CLASS.equals(fileType); - if (!isInsideCompiledClass && !(DebuggerUtils.supportsJVMDebugging(fileType) || DebuggerUtils.supportsJVMDebugging(psiFile))) { + if (!JavaBreakpointType.doCanPutAt(psiFile)) { return null; } + PsiDocumentManager.getInstance(myProject).commitDocument(document); int offset = editor.getCaretModel().getOffset(); @@ -205,6 +201,7 @@ public class BreakpointManager implements JDOMExternalizable { Breakpoint breakpoint = findBreakpoint(document, offset, null); if (breakpoint == null) { + boolean isInsideCompiledClass = StdFileTypes.CLASS.equals(psiFile.getFileType()); if (mostSuitingBreakpoint || isInsideCompiledClass) { breakpoint = addFieldBreakpoint(document, offset); if (breakpoint == null) { @@ -298,7 +295,8 @@ public class BreakpointManager implements JDOMExternalizable { return; } - if (XDebuggerUtil.getInstance().canPutBreakpointAt(myProject, FileDocumentManager.getInstance().getFile(document), line)) { + VirtualFile file = FileDocumentManager.getInstance().getFile(document); + if (file != null && XDebuggerUtil.getInstance().canPutBreakpointAt(myProject, file, line)) { return; } e.consume(); @@ -346,6 +344,7 @@ public class BreakpointManager implements JDOMExternalizable { @Override public void documentChanged(@NotNull final DocumentEvent e) { final Document document = e.getDocument(); + //noinspection SynchronizeOnThis synchronized (BreakpointManager.this) { List<BreakpointWithHighlighter> breakpoints = myDocumentBreakpoints.get(document); @@ -374,8 +373,7 @@ public class BreakpointManager implements JDOMExternalizable { DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() { @Override public void run() { - final GutterIconRenderer renderer = - (GutterIconRenderer)((BreakpointWithHighlighter)breakpoint).getHighlighter().getGutterIconRenderer(); + final GutterIconRenderer renderer = ((BreakpointWithHighlighter)breakpoint).getHighlighter().getGutterIconRenderer(); if (renderer != null) { DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class).getEditBreakpointAction() .editBreakpoint(myProject, editor, breakpoint, renderer); @@ -539,6 +537,7 @@ public class BreakpointManager implements JDOMExternalizable { for (final Breakpoint breakpoint : getBreakpoints()) { if (breakpoint instanceof BreakpointWithHighlighter && ((BreakpointWithHighlighter)breakpoint).isAt(document, offset)) { if (category == null || category.equals(breakpoint.getCategory())) { + //noinspection CastConflictsWithInstanceof,unchecked return (T)breakpoint; } } @@ -662,18 +661,15 @@ public class BreakpointManager implements JDOMExternalizable { public synchronized void addBreakpoint(Breakpoint breakpoint) { myBreakpoints.add(breakpoint); myBreakpointsListForIteration = null; - if(breakpoint instanceof BreakpointWithHighlighter) { + if (breakpoint instanceof BreakpointWithHighlighter) { BreakpointWithHighlighter breakpointWithHighlighter = (BreakpointWithHighlighter)breakpoint; Document document = breakpointWithHighlighter.getDocument(); - if(document != null) { - List<BreakpointWithHighlighter> breakpoints = myDocumentBreakpoints.get(document); - - if(breakpoints == null) { - breakpoints = new ArrayList<BreakpointWithHighlighter>(); - myDocumentBreakpoints.put(document, breakpoints); - } - breakpoints.add(breakpointWithHighlighter); + List<BreakpointWithHighlighter> breakpoints = myDocumentBreakpoints.get(document); + if (breakpoints == null) { + breakpoints = new ArrayList<BreakpointWithHighlighter>(); + myDocumentBreakpoints.put(document, breakpoints); } + breakpoints.add(breakpointWithHighlighter); } myDispatcher.getMulticaster().breakpointsChanged(); } @@ -812,7 +808,7 @@ public class BreakpointManager implements JDOMExternalizable { /** * @return breakpoints of one of the category: - * LINE_BREAKPOINTS, EXCEPTION_BREKPOINTS, FIELD_BREAKPOINTS, METHOD_BREAKPOINTS + * LINE_BREAKPOINTS, EXCEPTION_BREAKPOINTS, FIELD_BREAKPOINTS, METHOD_BREAKPOINTS */ public <T extends Breakpoint> Breakpoint[] getBreakpoints(@NotNull final Key<T> category) { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -977,7 +973,6 @@ public class BreakpointManager implements JDOMExternalizable { public void removeBreakpointManagerListener(@NotNull BreakpointManagerListener listener) { myDispatcher.removeListener(listener); } - private boolean myAllowMulticasting = true; private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java index 1217e166a4ea..5ed3c1034bc5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java @@ -196,6 +196,7 @@ public abstract class BreakpointPropertiesPanel { public MyTextField() { } + @Override public String getToolTipText(MouseEvent event) { reloadClassFilters(); updateClassFilterEditor(false); @@ -205,6 +206,7 @@ public abstract class BreakpointPropertiesPanel { return getToolTipText().length() == 0 ? null : toolTipText; } + @Override public JToolTip createToolTip() { JToolTip toolTip = new JToolTip(){{ setUI(new MultiLineTooltipUI()); @@ -230,6 +232,7 @@ public abstract class BreakpointPropertiesPanel { updateSuspendPolicyRbFont(); final ItemListener suspendPolicyChangeListener = new ItemListener() { + @Override public void itemStateChanged(final ItemEvent e) { final BreakpointDefaults defaults = getBreakpointManager(myProject).getBreakpointDefaults(breakpointCategory); myMakeDefaultButton.setEnabled(!defaults.getSuspendPolicy().equals(getSelectedSuspendPolicy()) || defaults.isConditionEnabled() != myConditionCheckbox.isSelected()); @@ -251,6 +254,7 @@ public abstract class BreakpointPropertiesPanel { myConditionCheckbox.addItemListener(suspendPolicyChangeListener); myMakeDefaultButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(final ActionEvent e) { final BreakpointManager breakpointManager = getBreakpointManager(myProject); final String suspendPolicy = getSelectedSuspendPolicy(); @@ -306,6 +310,7 @@ public abstract class BreakpointPropertiesPanel { myInstanceFiltersField = new FieldPanel(new MyTextField(), "", null, new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { reloadInstanceFilters(); EditInstanceFiltersDialog _dialog = new EditInstanceFiltersDialog(myProject); @@ -322,6 +327,7 @@ public abstract class BreakpointPropertiesPanel { myClassFiltersField = new FieldPanel(new MyTextField(), "", null, new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { reloadClassFilters(); @@ -365,6 +371,7 @@ public abstract class BreakpointPropertiesPanel { DebuggerUIUtil.enableEditorOnCheck(myLogExpressionCheckBox, myLogExpressionCombo); ActionListener updateListener = new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { updateCheckboxes(); } @@ -458,6 +465,7 @@ public abstract class BreakpointPropertiesPanel { ClassFilter classFilter; if(myBreakpointPsiClass != null) { classFilter = new ClassFilter() { + @Override public boolean isAccepted(PsiClass aClass) { return myBreakpointPsiClass == aClass || aClass.isInheritor(myBreakpointPsiClass, true); } @@ -641,7 +649,7 @@ public abstract class BreakpointPropertiesPanel { } } - private TextWithImportsImpl emptyText() { + private static TextWithImportsImpl emptyText() { return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); } @@ -653,14 +661,14 @@ public abstract class BreakpointPropertiesPanel { saveMasterBreakpoint(); try { String text = myPassCountField.getText().trim(); - int count = !"".equals(text)? Integer.parseInt(text) : 0; - breakpoint.COUNT_FILTER = count; + breakpoint.COUNT_FILTER = !text.isEmpty() ? Integer.parseInt(text) : 0; if (breakpoint.COUNT_FILTER < 0) { breakpoint.COUNT_FILTER = 0; } } - catch (Exception e) { + catch (Exception ignored) { } + breakpoint.COUNT_FILTER_ENABLED = breakpoint.COUNT_FILTER > 0 && myPassCountCheckbox.isSelected(); breakpoint.setCondition(myConditionCombo.getText()); breakpoint.CONDITION_ENABLED = myConditionCheckbox.isSelected(); @@ -867,8 +875,10 @@ public abstract class BreakpointPropertiesPanel { myDialogTitle = dialogTitle; } + @Override public void actionPerformed(final ActionEvent e) { new DialogWrapper(myTargetEditor, true){ + @Override public void show() { setTitle(myDialogTitle); setModal(true); @@ -876,10 +886,12 @@ public abstract class BreakpointPropertiesPanel { super.show(); } + @Override public JComponent getPreferredFocusedComponent() { return myEditor; } + @Override @Nullable protected JComponent createCenterPanel() { final JPanel panel = new JPanel(new BorderLayout()); @@ -890,6 +902,7 @@ public abstract class BreakpointPropertiesPanel { return panel; } + @Override protected void doOKAction() { myTargetEditor.setText(myEditor.getText()); super.doOKAction(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java index f1742f00ad89..465a96828347 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java @@ -19,12 +19,10 @@ import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.HelpID; import com.intellij.debugger.engine.JVMNameUtil; -import com.intellij.debugger.ui.breakpoints.actions.*; import com.intellij.icons.AllIcons; import com.intellij.ide.util.TreeClassChooser; import com.intellij.ide.util.TreeClassChooserFactory; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; @@ -72,51 +70,6 @@ public class ExceptionBreakpointFactory extends BreakpointFactory { return new ExceptionBreakpointPropertiesPanel(project, compact); } - @Override - protected BreakpointPanelAction[] createBreakpointPanelActions(final Project project, DialogWrapper parentDialog) { - return new BreakpointPanelAction[]{ - new SwitchViewAction(), - new AddAction(this, project), - new RemoveAction(project) { - public void update() { - super.update(); - if (getButton().isEnabled()) { - Breakpoint[] selectedBreakpoints = getPanel().getSelectedBreakpoints(); - for (Breakpoint bp : selectedBreakpoints) { - if (bp instanceof AnyExceptionBreakpoint) { - getButton().setEnabled(false); - } - } - } - } - }, new ToggleGroupByClassesAction(), new ToggleFlattenPackagesAction(),}; - } - - public BreakpointPanel createBreakpointPanel(final Project project, final DialogWrapper parentDialog) { - BreakpointPanel panel = - new BreakpointPanel(project, createBreakpointPropertiesPanel(project, false), createBreakpointPanelActions(project, parentDialog), - getBreakpointCategory(), getDisplayName(), getHelpID()) { - public void resetBreakpoints() { - super.resetBreakpoints(); - Breakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getBreakpointCategory()); - final AnyExceptionBreakpoint anyExceptionBreakpoint = - DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getAnyExceptionBreakpoint(); - boolean found = false; - for (Breakpoint breakpoint : breakpoints) { - if (breakpoint.equals(anyExceptionBreakpoint)) { - found = true; - break; - } - } - if (!found) { - insertBreakpointAt(anyExceptionBreakpoint, 0); - } - } - }; - configureBreakpointPanel(panel); - return panel; - } - public Key<ExceptionBreakpoint> getBreakpointCategory() { return ExceptionBreakpoint.CATEGORY; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java index 496e01313621..18d30f74b2d1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java @@ -19,11 +19,9 @@ import com.intellij.CommonBundle; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.HelpID; -import com.intellij.debugger.ui.breakpoints.actions.*; import com.intellij.icons.AllIcons; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; @@ -32,7 +30,6 @@ import com.intellij.psi.search.GlobalSearchScope; import org.jdom.Element; import javax.swing.*; -import java.awt.event.ActionEvent; /** * @author Eugene Zhuravlev @@ -71,24 +68,6 @@ public class FieldBreakpointFactory extends BreakpointFactory{ return new FieldBreakpointPropertiesPanel(project, compact); } - @Override - protected BreakpointPanelAction[] createBreakpointPanelActions(final Project project, final DialogWrapper parentDialog) { - return new BreakpointPanelAction[] { - new SwitchViewAction(), - new AddAction(this, project), - new GotoSourceAction(project) { - public void actionPerformed(ActionEvent e) { - super.actionPerformed(e); - parentDialog.close(DialogWrapper.OK_EXIT_CODE); - } - }, - new ViewSourceAction(project), - new RemoveAction(project), - new ToggleGroupByClassesAction(), - new ToggleFlattenPackagesAction(), - }; - } - public Key<FieldBreakpoint> getBreakpointCategory() { return FieldBreakpoint.CATEGORY; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java index 052cfd7f950a..65cbf2d9ee94 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java @@ -18,6 +18,7 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.SourcePosition; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.SimpleColoredComponent; @@ -31,6 +32,7 @@ import javax.swing.*; class JavaBreakpointItem extends BreakpointItem { private final Breakpoint myBreakpoint; private BreakpointFactory myBreakpointFactory; + private BreakpointPropertiesPanel myBreakpointPropertiesPanel; public JavaBreakpointItem(@Nullable BreakpointFactory breakpointFactory, Breakpoint breakpoint) { myBreakpointFactory = breakpointFactory; @@ -68,17 +70,19 @@ class JavaBreakpointItem extends BreakpointItem { @Override protected void doUpdateDetailView(DetailView panel, boolean editorOnly) { - BreakpointPropertiesPanel breakpointPropertiesPanel = null; + saveState(); + myBreakpointPropertiesPanel = null; + if (!editorOnly) { - breakpointPropertiesPanel = myBreakpointFactory != null ? myBreakpointFactory + myBreakpointPropertiesPanel = myBreakpointFactory != null ? myBreakpointFactory .createBreakpointPropertiesPanel(myBreakpoint.getProject(), false) : null; - if (breakpointPropertiesPanel != null) { - breakpointPropertiesPanel.initFrom(myBreakpoint, true); + if (myBreakpointPropertiesPanel != null) { + myBreakpointPropertiesPanel.initFrom(myBreakpoint, true); - breakpointPropertiesPanel.setSaveOnRemove(true); + myBreakpointPropertiesPanel.setSaveOnRemove(true); - final JPanel mainPanel = breakpointPropertiesPanel.getPanel(); + final JPanel mainPanel = myBreakpointPropertiesPanel.getPanel(); panel.setPropertiesPanel(mainPanel); } else { @@ -93,8 +97,8 @@ class JavaBreakpointItem extends BreakpointItem { } else { panel.clearEditor(); } - if (breakpointPropertiesPanel != null) { - breakpointPropertiesPanel.setDetailView(panel); + if (myBreakpointPropertiesPanel != null) { + myBreakpointPropertiesPanel.setDetailView(panel); } } @@ -127,6 +131,11 @@ class JavaBreakpointItem extends BreakpointItem { } @Override + public void saveState() { + myBreakpointPropertiesPanel.saveTo(myBreakpoint, EmptyRunnable.INSTANCE); + } + + @Override public Object getBreakpoint() { return myBreakpoint; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java index ae21b113df88..beacd1996b5f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java @@ -24,11 +24,11 @@ import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.actions.ThreadDumpAction; +import com.intellij.debugger.engine.ContextUtil; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.impl.PositionUtil; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; @@ -82,6 +82,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { super(project, highlighter); } + @Override protected Icon getDisabledIcon(boolean isMuted) { final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this); if (isMuted) { @@ -92,6 +93,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { } } + @Override protected Icon getSetIcon(boolean isMuted) { if (REMOVE_AFTER_HIT) { return isMuted ? AllIcons.Debugger.Db_muted_temporary_breakpoint : AllIcons.Debugger.Db_temporary_breakpoint; @@ -99,10 +101,12 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return isMuted? AllIcons.Debugger.Db_muted_breakpoint : AllIcons.Debugger.Db_set_breakpoint; } + @Override protected Icon getInvalidIcon(boolean isMuted) { return isMuted? AllIcons.Debugger.Db_muted_invalid_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint; } + @Override protected Icon getVerifiedIcon(boolean isMuted) { if (REMOVE_AFTER_HIT) { return isMuted ? AllIcons.Debugger.Db_muted_temporary_breakpoint : AllIcons.Debugger.Db_temporary_breakpoint; @@ -110,25 +114,30 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return isMuted? AllIcons.Debugger.Db_muted_verified_breakpoint : AllIcons.Debugger.Db_verified_breakpoint; } + @Override protected Icon getVerifiedWarningsIcon(boolean isMuted) { return isMuted? AllIcons.Debugger.Db_muted_verified_warning_breakpoint : AllIcons.Debugger.Db_verified_warning_breakpoint; } + @Override public Key<LineBreakpoint> getCategory() { return CATEGORY; } + @Override protected void reload(PsiFile file) { super.reload(file); myMethodName = findMethodName(file, getHighlighter().getStartOffset()); } + @Override protected void createOrWaitPrepare(DebugProcessImpl debugProcess, String classToBeLoaded) { if (isInScopeOf(debugProcess, classToBeLoaded)) { super.createOrWaitPrepare(debugProcess, classToBeLoaded); } } + @Override protected void createRequestForPreparedClass(final DebugProcessImpl debugProcess, final ReferenceType classType) { if (!isInScopeOf(debugProcess, classType.name())) { if (LOG.isDebugEnabled()) { @@ -137,13 +146,13 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return; } try { - List<Location> locs = debugProcess.getPositionManager().locationsOfLine(classType, getSourcePosition()); - if (!locs.isEmpty()) { - for (Location loc : locs) { + List<Location> locations = debugProcess.getPositionManager().locationsOfLine(classType, getSourcePosition()); + if (!locations.isEmpty()) { + for (Location loc : locations) { if (LOG.isDebugEnabled()) { LOG.debug("Found location [codeIndex=" + loc.codeIndex() +"] for reference type " + classType.name() + " at line " + getLineIndex() + "; isObsolete: " + (debugProcess.getVirtualMachineProxy().versionHigher("1.4") && loc.method().isObsolete())); } - BreakpointRequest request = debugProcess.getRequestsManager().createBreakpointRequest(LineBreakpoint.this, loc); + BreakpointRequest request = debugProcess.getRequestsManager().createBreakpointRequest(this, loc); debugProcess.getRequestsManager().enableRequest(request); if (LOG.isDebugEnabled()) { LOG.debug("Created breakpoint request for reference type " + classType.name() + " at line " + getLineIndex() + "; codeIndex=" + loc.codeIndex()); @@ -152,7 +161,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { } else { // there's no executable code in this class - debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message( + debugProcess.getRequestsManager().setInvalid(this, DebuggerBundle.message( "error.invalid.breakpoint.no.executable.code", (getLineIndex() + 1), classType.name()) ); if (LOG.isDebugEnabled()) { @@ -176,7 +185,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { if (LOG.isDebugEnabled()) { LOG.debug("InvalidLineNumberException: " + ex.getMessage()); } - debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message("error.invalid.breakpoint.bad.line.number")); + debugProcess.getRequestsManager().setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.bad.line.number")); } catch (InternalException ex) { LOG.info(ex); @@ -251,6 +260,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { final int dollarIndex = className.indexOf("$"); final String topLevelClassName = dollarIndex >= 0? className.substring(0, dollarIndex) : className; return ApplicationManager.getApplication().runReadAction(new Computable<Collection<VirtualFile>>() { + @Override @Nullable public Collection<VirtualFile> compute() { final PsiClass[] classes = JavaPsiFacade.getInstance(myProject).findClasses(topLevelClassName, scope); @@ -292,6 +302,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { }); } + @Override public boolean evaluateCondition(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { if(CLASS_FILTERS_ENABLED){ String className = null; @@ -335,6 +346,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return getDisplayInfoInternal(false, 30); } + @Override public String getDisplayName() { return getDisplayInfoInternal(true, -1); } @@ -399,6 +411,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { } if (file instanceof PsiClassOwner) { return ApplicationManager.getApplication().runReadAction(new Computable<String>() { + @Override public String compute() { final PsiMethod method = DebuggerUtilsEx.findPsiMethod(file, offset); return method != null? method.getName() + "()" : null; @@ -408,9 +421,10 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return null; } + @Override public String getEventMessage(LocatableEvent event) { final Location location = event.location(); - String sourceName = "Unknown Source"; + String sourceName; try { sourceName = location.sourceName(); } @@ -452,8 +466,9 @@ public class LineBreakpoint extends BreakpointWithHighlighter { } } + @Override public PsiElement getEvaluationElement() { - return PositionUtil.getContextElement(getSourcePosition()); + return ContextUtil.getContextElement(getSourcePosition()); } protected static LineBreakpoint create(Project project, Document document, int lineIndex) { @@ -471,6 +486,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { return (LineBreakpoint)breakpoint.init(); } + @Override public boolean canMoveTo(SourcePosition position) { if (!super.canMoveTo(position)) { return false; @@ -493,6 +509,7 @@ public class LineBreakpoint extends BreakpointWithHighlighter { final boolean[] canAdd = new boolean[]{false}; XDebuggerUtil.getInstance().iterateLine(project, document, lineIndex, new Processor<PsiElement>() { + @Override public boolean process(PsiElement element) { if ((element instanceof PsiWhiteSpace) || (PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null)) { return true; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java index dede7de736de..0042074dc798 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java @@ -17,29 +17,29 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.HelpID; -import com.intellij.debugger.ui.breakpoints.actions.*; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import org.jdom.Element; import javax.swing.*; -import java.awt.event.ActionEvent; /** * @author Eugene Zhuravlev * Date: Apr 26, 2005 */ public class LineBreakpointFactory extends BreakpointFactory { + @Override public Breakpoint createBreakpoint(Project project, final Element element) { return new LineBreakpoint(project); } + @Override public Icon getIcon() { return AllIcons.Debugger.Db_set_breakpoint; } + @Override public Icon getDisabledIcon() { return AllIcons.Debugger.Db_disabled_breakpoint; } @@ -60,22 +60,6 @@ public class LineBreakpointFactory extends BreakpointFactory { } @Override - protected BreakpointPanelAction[] createBreakpointPanelActions(Project project, final DialogWrapper parentDialog) { - return new BreakpointPanelAction[]{new SwitchViewAction(), - new GotoSourceAction(project) { - public void actionPerformed(ActionEvent e) { - super.actionPerformed(e); - parentDialog.close(DialogWrapper.OK_EXIT_CODE); - } - }, - new ViewSourceAction(project), - new RemoveAction(project), - new ToggleGroupByMethodsAction(), - new ToggleGroupByClassesAction(), - new ToggleFlattenPackagesAction(), - }; - } - public Key<LineBreakpoint> getBreakpointCategory() { return LineBreakpoint.CATEGORY; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java index c2ad3dc3f1be..2574e224efbd 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java @@ -18,29 +18,29 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.HelpID; -import com.intellij.debugger.ui.breakpoints.actions.*; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import org.jdom.Element; import javax.swing.*; -import java.awt.event.ActionEvent; /** * @author Eugene Zhuravlev * Date: Apr 26, 2005 */ public class MethodBreakpointFactory extends BreakpointFactory{ + @Override public Breakpoint createBreakpoint(Project project, final Element element) { return element.getAttributeValue(WildcardMethodBreakpoint.JDOM_LABEL) != null? new WildcardMethodBreakpoint(project) : new MethodBreakpoint(project); } + @Override public Icon getIcon() { return AllIcons.Debugger.Db_method_breakpoint; } + @Override public Icon getDisabledIcon() { return AllIcons.Debugger.Db_disabled_method_breakpoint; } @@ -61,29 +61,12 @@ public class MethodBreakpointFactory extends BreakpointFactory{ } @Override - protected BreakpointPanelAction[] createBreakpointPanelActions(Project project, final DialogWrapper parentDialog) { - return new BreakpointPanelAction[]{ - new SwitchViewAction(), - new AddAction(this, project), - new GotoSourceAction(project) { - public void actionPerformed(ActionEvent e) { - super.actionPerformed(e); - parentDialog.close(DialogWrapper.OK_EXIT_CODE); - } - }, - new ViewSourceAction(project), - new RemoveAction(project), - new ToggleGroupByClassesAction(), - new ToggleFlattenPackagesAction(), - }; - } - - @Override protected void configureBreakpointPanel(BreakpointPanel panel) { super.configureBreakpointPanel(panel); panel.getTree().setGroupByMethods(false); } + @Override public Key<MethodBreakpoint> getBreakpointCategory() { return MethodBreakpoint.CATEGORY; } @@ -93,6 +76,7 @@ public class MethodBreakpointFactory extends BreakpointFactory{ return true; } + @Override public WildcardMethodBreakpoint addBreakpoint(Project project) { AddWildcardBreakpointDialog dialog = new AddWildcardBreakpointDialog(project); dialog.show(); diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java new file mode 100644 index 000000000000..21cdb36a3a4e --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java @@ -0,0 +1,24 @@ +package org.jetbrains.java.debugger; + +import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.psi.JavaCodeFragmentFactory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.xdebugger.evaluation.XDebuggerEditorsProviderBase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase { + @NotNull + @Override + public FileType getFileType() { + return JavaFileType.INSTANCE; + } + + @Override + protected PsiFile createExpressionCodeFragment(@NotNull Project project, @NotNull String text, @Nullable PsiElement context, boolean isPhysical) { + return JavaCodeFragmentFactory.getInstance(project).createExpressionCodeFragment(text, context, null, isPhysical); + } +}
\ No newline at end of file diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointType.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointType.java new file mode 100644 index 000000000000..d3e6545cced1 --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointType.java @@ -0,0 +1,67 @@ +package org.jetbrains.java.debugger.breakpoints; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.DebuggerUtils; +import com.intellij.facet.FacetManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.util.SystemProperties; +import com.intellij.xdebugger.XDebuggerUtil; +import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.breakpoints.XLineBreakpointTypeBase; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.debugger.JavaDebuggerEditorsProvider; + +import java.util.List; + +public class JavaBreakpointType extends XLineBreakpointTypeBase { + public JavaBreakpointType() { + super("java", DebuggerBundle.message("java.breakpoint.title"), new JavaDebuggerEditorsProvider()); + } + + @Override + public boolean canPutAt(@NotNull final VirtualFile file, final int line, @NotNull Project project) { + if (SystemProperties.getBooleanProperty("java.debugger.xBreakpoint", false)) { + boolean result = doCanPutAt(PsiManager.getInstance(project).findFile(file)); + + // todo now applicable only if modules has facets, remove this check when java xbreakpoint will work + if (result && SystemProperties.getBooleanProperty("java.debugger.xBreakpoint.onlyIfHasFacets", false)) { + Module module = ModuleUtilCore.findModuleForFile(file, project); + return module != null && FacetManager.getInstance(module).getAllFacets().length > 0; + } + + return result; + } + return false; + } + + @Override + public boolean isSuspendThreadSupported() { + return true; + } + + @Override + public List<XBreakpointGroupingRule<XLineBreakpoint<XBreakpointProperties>, ?>> getGroupingRules() { + return XDebuggerUtil.getInstance().getGroupingByFileRuleAsList(); + } + + @Contract("null -> false") + public static boolean doCanPutAt(@Nullable PsiFile psiFile) { + if (psiFile == null) { + return false; + } + + FileType fileType = psiFile.getFileType(); + return StdFileTypes.CLASS.equals(fileType) || DebuggerUtils.supportsJVMDebugging(fileType) || DebuggerUtils.supportsJVMDebugging(psiFile); + } +}
\ No newline at end of file diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index ae4ea8819b25..74524ca8ae14 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -99,6 +99,7 @@ public class JUnitUtil { } public static boolean isTestClass(@NotNull PsiClass psiClass, boolean checkAbstract, boolean checkForTestCaseInheritance) { + if (psiClass.getQualifiedName() == null) return false; if (!PsiClassUtil.isRunnableClass(psiClass, true, checkAbstract)) return false; if (checkForTestCaseInheritance && isTestCaseInheritor(psiClass)) return true; final PsiModifierList modifierList = psiClass.getModifierList(); diff --git a/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java b/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java index de8cd68e464a..1137273c69d0 100644 --- a/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java +++ b/java/execution/impl/src/com/intellij/execution/stacktrace/StackTraceLine.java @@ -114,10 +114,9 @@ public class StackTraceLine { } } - private PsiClass findClass(final Project project, final String className, final int lineNumber) { + private static PsiClass findClass(final Project project, final String className, final int lineNumber) { if (project == null) return null; final PsiManager psiManager = PsiManager.getInstance(project); - if (psiManager == null) return null; PsiClass psiClass = JavaPsiFacade.getInstance(psiManager.getProject()).findClass(className, GlobalSearchScope.allScope(project)); if (psiClass == null || (psiClass.getNavigationElement() instanceof PsiCompiledElement)) return null; psiClass = (PsiClass)psiClass.getNavigationElement(); @@ -132,8 +131,7 @@ public class StackTraceLine { if (methods.length == 0) return null; final PsiFile psiFile = methods[0].getContainingFile(); final int offset = offsetOfLine(psiFile, lineNumber); - for (int i = 0; i < methods.length; i++) { - final PsiMethod method = methods[i]; + for (final PsiMethod method : methods) { if (method.getTextRange().contains(offset)) return method; } //if (!methods.hasNext() || location == null) return null; @@ -152,7 +150,6 @@ public class StackTraceLine { private static int offsetOfLine(final PsiFile psiFile, final int lineNumber) { final LineTokenizer lineTokenizer = new LineTokenizer(psiFile.getViewProvider().getContents()); for (int i = 0; i < lineNumber; i++) lineTokenizer.advance(); - final int offset = lineTokenizer.getOffset(); - return offset; + return lineTokenizer.getOffset(); } } diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/CommonJavaProjectCategory.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/FrameworkLibraryProvider.java index bac30cbd8732..fe014270cdd3 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/CommonJavaProjectCategory.java +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/FrameworkLibraryProvider.java @@ -13,36 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ide.projectWizard; +package com.intellij.facet.impl.ui.libraries; -import com.intellij.ide.util.projectWizard.ModuleBuilder; -import com.intellij.openapi.module.JavaModuleType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryKind; import org.jetbrains.annotations.NotNull; +import java.util.Set; + /** - * @author Dmitry Avdeev - * Date: 04.09.13 + * @author nik */ -public class CommonJavaProjectCategory extends ProjectCategory { - +public abstract class FrameworkLibraryProvider { @NotNull - @Override - public ModuleBuilder createModuleBuilder() { - return JavaModuleType.getModuleType().createModuleBuilder(); - } + public abstract String getPresentableName(); - @Override - public String getId() { - return "Java"; - } + public abstract Set<LibraryKind> getAvailableLibraryKinds(); - @Override - public String getDisplayName() { - return "Common Java"; - } - - @Override - public String getDescription() { - return "Common Java Project"; - } + @NotNull + public abstract Library createLibrary(@NotNull Set<? extends LibraryKind> suitableLibraryKinds); } diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryCompositionSettings.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryCompositionSettings.java index b9dd0cb330a5..52d5358f985a 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryCompositionSettings.java +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryCompositionSettings.java @@ -53,6 +53,7 @@ public class LibraryCompositionSettings implements Disposable { private LibraryDownloadSettings myDownloadSettings; private Map<Library, ExistingLibraryEditor> myExistingLibraryEditors = ContainerUtil.newIdentityTroveMap(); + private FrameworkLibraryProvider myLibraryProvider; public LibraryCompositionSettings(final @NotNull CustomLibraryDescription libraryDescription, final @NotNull String baseDirectoryPath, @@ -182,16 +183,16 @@ public class LibraryCompositionSettings implements Disposable { @Nullable public Library addLibraries(final @NotNull ModifiableRootModel rootModel, final @NotNull List<Library> addedLibraries, final @Nullable LibrariesContainer librariesContainer) { - Library library = createLibrary(rootModel, librariesContainer); + Library newLibrary = createLibrary(rootModel, librariesContainer); - if (library != null) { - addedLibraries.add(library); - DependencyScope scope = LibraryDependencyScopeSuggester.getDefaultScope(library); + if (newLibrary != null) { + addedLibraries.add(newLibrary); + DependencyScope scope = LibraryDependencyScopeSuggester.getDefaultScope(newLibrary); if (getLibraryLevel() != LibrariesContainer.LibraryLevel.MODULE) { - rootModel.addLibraryEntry(library).setScope(scope); + rootModel.addLibraryEntry(newLibrary).setScope(scope); } else { - LibraryOrderEntry orderEntry = rootModel.findLibraryOrderEntry(library); + LibraryOrderEntry orderEntry = rootModel.findLibraryOrderEntry(newLibrary); assert orderEntry != null; orderEntry.setScope(scope); } @@ -200,13 +201,22 @@ public class LibraryCompositionSettings implements Disposable { addedLibraries.add(mySelectedLibrary); rootModel.addLibraryEntry(mySelectedLibrary).setScope(LibraryDependencyScopeSuggester.getDefaultScope(mySelectedLibrary)); } - return library; + if (myLibraryProvider != null) { + Library library = myLibraryProvider.createLibrary(myLibraryDescription.getSuitableLibraryKinds()); + addedLibraries.add(library); + rootModel.addLibraryEntry(library).setScope(LibraryDependencyScopeSuggester.getDefaultScope(library)); + } + return newLibrary; } public void setNewLibraryEditor(@Nullable NewLibraryEditor libraryEditor) { myNewLibraryEditor = libraryEditor; } + public void setLibraryProvider(FrameworkLibraryProvider libraryProvider) { + myLibraryProvider = libraryProvider; + } + @Override public void dispose() { } diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java index b3584169acfc..e9e86d69b592 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java @@ -42,7 +42,7 @@ import java.util.Map; * @author nik */ public class LibraryDownloadSettings { - private FrameworkLibraryVersion myVersion; + private final FrameworkLibraryVersion myVersion; private final DownloadableLibraryType myLibraryType; private String myDirectoryForDownloadedLibrariesPath; private final String myLibraryName; @@ -116,10 +116,6 @@ public class LibraryDownloadSettings { return myLibraryType; } - public void setVersion(FrameworkLibraryVersion version) { - myVersion = version; - } - public void setDirectoryForDownloadedLibrariesPath(String directoryForDownloadedLibrariesPath) { myDirectoryForDownloadedLibrariesPath = directoryForDownloadedLibrariesPath; } diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form index afaac4ee2c18..d4a8a2b36603 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form @@ -15,7 +15,7 @@ <properties/> <border type="none"/> <children> - <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="6" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <card name="editing"/> @@ -27,7 +27,7 @@ <children> <component id="a5b73" class="javax.swing.JRadioButton" binding="myDownloadRadioButton"> <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"> <preferred-size width="207" height="22"/> </grid> </constraints> @@ -38,7 +38,7 @@ </component> <component id="f63e3" class="javax.swing.JRadioButton" binding="myDoNotCreateRadioButton"> <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Set up library &later"/> @@ -46,7 +46,7 @@ </component> <vspacer id="79970"> <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> </constraints> </vspacer> <grid id="71da4" layout-manager="GridLayoutManager" row-count="1" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> @@ -98,7 +98,7 @@ </grid> <grid id="7ea1" binding="myConfigurationPanel" layout-manager="CardLayout" hgap="0" vgap="0"> <constraints> - <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> <border type="none"/> @@ -165,6 +165,14 @@ </grid> </children> </grid> + <component id="9e8d3" class="javax.swing.JRadioButton" binding="myUseFromProviderRadioButton"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Use from provider"/> + </properties> + </component> </children> </grid> <grid id="b8ccc" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> @@ -199,6 +207,7 @@ <member id="4dbad"/> <member id="a5b73"/> <member id="f63e3"/> + <member id="9e8d3"/> </group> </buttonGroups> </form> diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java index e96687310423..f11e89daa470 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java @@ -39,6 +39,7 @@ import com.intellij.openapi.roots.ui.configuration.libraryEditor.ExistingLibrary import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor; import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor; import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -49,6 +50,7 @@ import com.intellij.ui.SortedComboBoxModel; import com.intellij.ui.components.JBLabel; import com.intellij.util.PathUtil; import com.intellij.util.PlatformIcons; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.download.DownloadableFileSetVersions; import com.intellij.util.ui.RadioButtonEnumModel; import com.intellij.xml.util.XmlStringUtil; @@ -84,17 +86,21 @@ public class LibraryOptionsPanel implements Disposable { private JLabel myUseLibraryLabel; private JLabel myHiddenLabel; private JPanel myRootPanel; + private JRadioButton myUseFromProviderRadioButton; private ButtonGroup myButtonGroup; private LibraryCompositionSettings mySettings; + private final CustomLibraryDescription myLibraryDescription; private final LibrariesContainer myLibrariesContainer; private SortedComboBoxModel<LibraryEditor> myLibraryComboBoxModel; + private FrameworkLibraryProvider myLibraryProvider; private boolean myDisposed; private enum Choice { USE_LIBRARY, DOWNLOAD, - SETUP_LIBRARY_LATER + SETUP_LIBRARY_LATER, + USE_FROM_PROVIDER } private RadioButtonEnumModel<Choice> myButtonEnumModel; @@ -104,6 +110,7 @@ public class LibraryOptionsPanel implements Disposable { @NotNull final FrameworkLibraryVersionFilter versionFilter, @NotNull final LibrariesContainer librariesContainer, final boolean showDoNotCreateOption) { + myLibraryDescription = libraryDescription; myLibrariesContainer = librariesContainer; final DownloadableLibraryDescription description = getDownloadableDescription(libraryDescription); if (description != null) { @@ -211,10 +218,22 @@ public class LibraryOptionsPanel implements Disposable { }); boolean canDownload = mySettings.getDownloadSettings() != null; + boolean canUseFromProvider = myLibraryProvider != null; myDownloadRadioButton.setVisible(canDownload); - myButtonEnumModel.setSelected(libraries.isEmpty() && canDownload ? Choice.DOWNLOAD : Choice.USE_LIBRARY); + myUseFromProviderRadioButton.setVisible(canUseFromProvider); + Choice selectedOption; + if (canUseFromProvider) { + selectedOption = Choice.USE_FROM_PROVIDER; + } + else if (libraries.isEmpty() && canDownload) { + selectedOption = Choice.DOWNLOAD; + } + else { + selectedOption = Choice.USE_LIBRARY; + } + myButtonEnumModel.setSelected(selectedOption); - if (!canDownload && !showDoNotCreateOption) { + if (!canDownload && !canUseFromProvider && !showDoNotCreateOption) { myUseLibraryRadioButton.setVisible(false); myUseLibraryLabel.setVisible(true); } @@ -272,12 +291,31 @@ public class LibraryOptionsPanel implements Disposable { } break; + case USE_FROM_PROVIDER: case SETUP_LIBRARY_LATER: break; } updateState(); } + public void setLibraryProvider(@Nullable FrameworkLibraryProvider provider) { + if (provider != null && !ContainerUtil.intersects(provider.getAvailableLibraryKinds(), myLibraryDescription.getSuitableLibraryKinds())) { + provider = null; + } + + if (!Comparing.equal(myLibraryProvider, provider)) { + myLibraryProvider = provider; + + if (mySettings != null) { + if (provider != null && !myUseFromProviderRadioButton.isVisible()) { + myUseFromProviderRadioButton.setSelected(true); + } + myUseFromProviderRadioButton.setVisible(provider != null); + updateState(); + } + } + } + public void changeBaseDirectoryPath(@NotNull String directoryForLibrariesPath) { if (mySettings != null) { mySettings.changeBaseDirectoryPath(directoryForLibrariesPath); @@ -293,7 +331,7 @@ public class LibraryOptionsPanel implements Disposable { } private void doCreate() { - final NewLibraryConfiguration libraryConfiguration = mySettings.getLibraryDescription().createNewLibrary(myPanel, getBaseDirectory()); + final NewLibraryConfiguration libraryConfiguration = myLibraryDescription.createNewLibrary(myPanel, getBaseDirectory()); if (libraryConfiguration != null) { final NewLibraryEditor libraryEditor = new NewLibraryEditor(libraryConfiguration.getLibraryType(), libraryConfiguration.getProperties()); libraryEditor.setName(myLibrariesContainer.suggestUniqueLibraryName(libraryConfiguration.getDefaultLibraryName())); @@ -308,12 +346,11 @@ public class LibraryOptionsPanel implements Disposable { } private List<Library> calculateSuitableLibraries() { - final CustomLibraryDescription description = mySettings.getLibraryDescription(); List<Library> suitableLibraries = new ArrayList<Library>(); for (Library library : myLibrariesContainer.getAllLibraries()) { - if (description instanceof OldCustomLibraryDescription && - ((OldCustomLibraryDescription)description).isSuitableLibrary(library, myLibrariesContainer) - || LibraryPresentationManager.getInstance().isLibraryOfKind(library, myLibrariesContainer, description.getSuitableLibraryKinds())) { + if (myLibraryDescription instanceof OldCustomLibraryDescription && + ((OldCustomLibraryDescription)myLibraryDescription).isSuitableLibrary(library, myLibrariesContainer) + || LibraryPresentationManager.getInstance().isLibraryOfKind(library, myLibrariesContainer, myLibraryDescription.getSuitableLibraryKinds())) { suitableLibraries.add(library); } } @@ -335,9 +372,17 @@ public class LibraryOptionsPanel implements Disposable { myMessageLabel.setIcon(null); myConfigureButton.setVisible(true); final LibraryDownloadSettings settings = mySettings.getDownloadSettings(); - myDownloadRadioButton.setEnabled(settings != null); myDownloadRadioButton.setVisible(settings != null); - if (!myDownloadRadioButton.isEnabled() && myDownloadRadioButton.isSelected() && myUseLibraryRadioButton.isVisible()) { + myUseFromProviderRadioButton.setVisible(myLibraryProvider != null); + if (!myUseFromProviderRadioButton.isVisible() && myUseFromProviderRadioButton.isSelected()) { + if (myDownloadRadioButton.isVisible()) { + myDownloadRadioButton.setSelected(true); + } + else { + myUseLibraryRadioButton.setSelected(true); + } + } + if (!myDownloadRadioButton.isVisible() && myDownloadRadioButton.isSelected() && myUseLibraryRadioButton.isVisible()) { myUseLibraryRadioButton.setSelected(true); } String message = ""; @@ -346,6 +391,12 @@ public class LibraryOptionsPanel implements Disposable { case DOWNLOAD: message = getDownloadFilesMessage(); break; + case USE_FROM_PROVIDER: + if (myLibraryProvider != null) { + message = "Library from " + myLibraryProvider.getPresentableName() + " will be used"; + } + myConfigureButton.setVisible(false); + break; case USE_LIBRARY: final Object item = myExistingLibraryComboBox.getSelectedItem(); if (item == null) { @@ -366,6 +417,10 @@ public class LibraryOptionsPanel implements Disposable { showConfigurePanel = false; } + if (myLibraryProvider != null) { + myUseFromProviderRadioButton.setText("Use library from " + myLibraryProvider.getPresentableName()); + } + //show the longest message on the hidden card to ensure that dialog won't jump if user selects another option if (mySettings.getDownloadSettings() != null) { myHiddenLabel.setText(getDownloadFilesMessage()); @@ -424,6 +479,8 @@ public class LibraryOptionsPanel implements Disposable { else { mySettings.setNewLibraryEditor(null); } + + mySettings.setLibraryProvider(option == Choice.USE_FROM_PROVIDER ? myLibraryProvider : null); return mySettings; } diff --git a/java/idea-ui/src/com/intellij/framework/addSupport/FrameworkSupportInModuleProvider.java b/java/idea-ui/src/com/intellij/framework/addSupport/FrameworkSupportInModuleProvider.java index 2dafb463cfb0..744922c69991 100644 --- a/java/idea-ui/src/com/intellij/framework/addSupport/FrameworkSupportInModuleProvider.java +++ b/java/idea-ui/src/com/intellij/framework/addSupport/FrameworkSupportInModuleProvider.java @@ -23,6 +23,9 @@ import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.roots.ui.configuration.FacetsProvider; import org.jetbrains.annotations.NotNull; +import java.util.Collections; +import java.util.List; + /** * @author nik */ @@ -60,6 +63,10 @@ public abstract class FrameworkSupportInModuleProvider { return "Version:"; } + public List<String> getOptionalDependenciesFrameworkIds() { + return Collections.emptyList(); + } + @Override public String toString() { return getPresentableName(); diff --git a/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryTypeBase.java b/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryTypeBase.java new file mode 100644 index 000000000000..5764efad5a2d --- /dev/null +++ b/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryTypeBase.java @@ -0,0 +1,34 @@ +/* + * 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.framework.library; + +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.net.URL; + +/** + * @deprecated use {@link DownloadableLibraryType} instead + */ +public abstract class DownloadableLibraryTypeBase extends DownloadableLibraryType { + protected DownloadableLibraryTypeBase(@NotNull String libraryCategoryName, + @NotNull String libraryTypeId, + @NotNull String groupId, + @NotNull Icon icon, + @NotNull URL... localUrls) { + super(libraryCategoryName, libraryTypeId, groupId, icon, localUrls); + } +} diff --git a/java/idea-ui/src/com/intellij/framework/library/LibraryBasedFrameworkType.java b/java/idea-ui/src/com/intellij/framework/library/LibraryBasedFrameworkType.java index 56d5c13b488b..ca6c47b0fbd9 100644 --- a/java/idea-ui/src/com/intellij/framework/library/LibraryBasedFrameworkType.java +++ b/java/idea-ui/src/com/intellij/framework/library/LibraryBasedFrameworkType.java @@ -48,8 +48,14 @@ public abstract class LibraryBasedFrameworkType extends FrameworkTypeEx { @NotNull @Override public Icon getIcon() { + DownloadableLibraryType libraryType = getLibraryType(); + return libraryType.getIcon(); + } + + @NotNull + public DownloadableLibraryType getLibraryType() { DownloadableLibraryType libraryType = LibraryType.EP_NAME.findExtension(myLibraryTypeClass); LOG.assertTrue(libraryType != null, myLibraryTypeClass); - return libraryType.getIcon(); + return libraryType; } } diff --git a/java/idea-ui/src/com/intellij/framework/library/UnderlyingFrameworkSupportProviderBase.java b/java/idea-ui/src/com/intellij/framework/library/UnderlyingFrameworkSupportProviderBase.java new file mode 100644 index 000000000000..70748d69d84c --- /dev/null +++ b/java/idea-ui/src/com/intellij/framework/library/UnderlyingFrameworkSupportProviderBase.java @@ -0,0 +1,30 @@ +/* + * 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.framework.library; + +import com.intellij.framework.FrameworkTypeEx; + +/** + * @author nik + * + * @deprecated use {@link #LibraryBasedFrameworkSupportProvider} instead + */ +public class UnderlyingFrameworkSupportProviderBase extends LibraryBasedFrameworkSupportProvider { + public UnderlyingFrameworkSupportProviderBase(FrameworkTypeEx frameworkType, + Class<? extends DownloadableLibraryType> libraryTypeClass) { + super(frameworkType, libraryTypeClass); + } +} diff --git a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java index e7ec1b050bc5..2faa20bc412d 100644 --- a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java +++ b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java @@ -17,6 +17,7 @@ package com.intellij.ide.actions; import com.intellij.ide.impl.NewProjectUtil; import com.intellij.ide.util.PropertiesComponent; +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; import com.intellij.ide.util.projectWizard.ProjectBuilder; import com.intellij.openapi.actionSystem.AnAction; @@ -68,9 +69,9 @@ public class ImportModuleAction extends AnAction { return createFromWizard(project, wizard); } - public static List<Module> createFromWizard(Project project, AddModuleWizard wizard) { + public static List<Module> createFromWizard(Project project, AbstractProjectWizard wizard) { if (project == null && wizard.getStepCount() > 0) { - Project newProject = NewProjectUtil.createFromWizard(wizard, project); + Project newProject = NewProjectUtil.createFromWizard(wizard, null); return newProject == null ? Collections.<Module>emptyList() : Arrays.asList(ModuleManager.getInstance(newProject).getModules()); } diff --git a/java/idea-ui/src/com/intellij/ide/actions/NewProjectAction.java b/java/idea-ui/src/com/intellij/ide/actions/NewProjectAction.java index 7deeeced372d..048bda9f70c3 100644 --- a/java/idea-ui/src/com/intellij/ide/actions/NewProjectAction.java +++ b/java/idea-ui/src/com/intellij/ide/actions/NewProjectAction.java @@ -16,13 +16,19 @@ package com.intellij.ide.actions; import com.intellij.ide.impl.NewProjectUtil; +import com.intellij.ide.util.newProjectWizard.AddModuleWizard; +import com.intellij.ide.util.newProjectWizard.AddModuleWizardPro; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.util.registry.Registry; public class NewProjectAction extends AnAction implements DumbAware { public void actionPerformed(AnActionEvent e) { - NewProjectUtil.createNewProject(PlatformDataKeys.PROJECT.getData(e.getDataContext()), null); + NewProjectUtil.createNewProject(CommonDataKeys.PROJECT.getData(e.getDataContext()), Registry.is("new.project.wizard") + ? new AddModuleWizardPro(null, ModulesProvider.EMPTY_MODULES_PROVIDER, null) + : new AddModuleWizard(null, ModulesProvider.EMPTY_MODULES_PROVIDER, null)); } } diff --git a/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java b/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java index f5ef7aff7563..4cf1663c14aa 100644 --- a/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java +++ b/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java @@ -20,8 +20,7 @@ package com.intellij.ide.impl; import com.intellij.ide.GeneralSettings; -import com.intellij.ide.util.newProjectWizard.AddModuleWizard; -import com.intellij.ide.util.newProjectWizard.AddModuleWizardPro; +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; import com.intellij.ide.util.projectWizard.ProjectBuilder; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -44,7 +43,6 @@ import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.wm.*; import com.intellij.openapi.wm.ex.IdeFrameEx; @@ -62,25 +60,22 @@ public class NewProjectUtil { private NewProjectUtil() { } - public static void createNewProject(Project projectToClose, @Nullable final String defaultPath) { + public static void createNewProject(Project projectToClose, AbstractProjectWizard wizard) { final boolean proceed = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { public void run() { ProjectManager.getInstance().getDefaultProject(); //warm up components } }, ProjectBundle.message("project.new.wizard.progress.title"), true, null); if (!proceed) return; - final AddModuleWizard dialog = Registry.is("new.project.wizard") - ? new AddModuleWizardPro(null, ModulesProvider.EMPTY_MODULES_PROVIDER, defaultPath) - : new AddModuleWizard(null, ModulesProvider.EMPTY_MODULES_PROVIDER, defaultPath); - dialog.show(); - if (!dialog.isOK()) { + wizard.show(); + if (!wizard.isOK()) { return; } - createFromWizard(dialog, projectToClose); + createFromWizard(wizard, projectToClose); } - public static Project createFromWizard(AddModuleWizard dialog, Project projectToClose) { + public static Project createFromWizard(AbstractProjectWizard dialog, Project projectToClose) { try { return doCreate(dialog, projectToClose); } @@ -95,7 +90,7 @@ public class NewProjectUtil { } } - private static Project doCreate(final AddModuleWizard dialog, @Nullable Project projectToClose) throws IOException { + private static Project doCreate(final AbstractProjectWizard dialog, @Nullable Project projectToClose) throws IOException { final ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx(); final String projectFilePath = dialog.getNewProjectFilePath(); final ProjectBuilder projectBuilder = dialog.getProjectBuilder(); diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/BuilderBasedProjectType.java b/java/idea-ui/src/com/intellij/ide/projectWizard/BuilderBasedProjectType.java new file mode 100644 index 000000000000..23379f6147ee --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/BuilderBasedProjectType.java @@ -0,0 +1,35 @@ +package com.intellij.ide.projectWizard; + +import com.intellij.ide.util.projectWizard.ModuleBuilder; +import com.intellij.openapi.module.JavaModuleType; +import org.jetbrains.annotations.NotNull; + +/** + * @author Dmitry Avdeev + * Date: 20.09.13 + */ +public class BuilderBasedProjectType extends ProjectCategory { + + private final ModuleBuilder myBuilder; + + public BuilderBasedProjectType(ModuleBuilder builder) { + myBuilder = builder; + } + + @NotNull + @Override + public ModuleBuilder createModuleBuilder() { + return myBuilder; + } + + /** + * @author Dmitry Avdeev + * Date: 04.09.13 + */ + public static class Java extends BuilderBasedProjectType { + + public Java() { + super(JavaModuleType.getModuleType().createModuleBuilder()); + } + } +} diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java index f76462bf2e1d..5ecda308c122 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java @@ -15,36 +15,43 @@ */ package com.intellij.ide.projectWizard; -import com.intellij.ide.util.projectWizard.WizardContext; -import com.intellij.ide.wizard.AbstractWizard; -import com.intellij.ide.wizard.Step; +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; +import com.intellij.ide.util.newProjectWizard.StepSequence; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author Dmitry Avdeev * Date: 04.09.13 */ -public class NewProjectWizard extends AbstractWizard<Step> { +public class NewProjectWizard extends AbstractProjectWizard { - private final WizardContext myContext; + private final StepSequence mySequence; - public NewProjectWizard(String title, @Nullable Project project) { - super(title, project); - myContext = new WizardContext(project); - addStep(new ProjectTypeStep(project, getDisposable())); + public NewProjectWizard(@Nullable Project project, @NotNull ModulesProvider modulesProvider, @Nullable String defaultPath) { + super("New Project", project, defaultPath); +// addStep(); +// addStep(new ProjectSummaryStep(myWizardContext)); + mySequence = new StepSequence(); + mySequence.addCommonStep(new ProjectTypeStep(myWizardContext, this, modulesProvider)); + mySequence.addCommonFinishingStep(new ProjectSettingsStep(myWizardContext), null); + for (ModuleWizardStep step : mySequence.getAllSteps()) { + addStep(step); + } init(); } @Nullable @Override - protected String getHelpID() { - return null; + protected String getDimensionServiceKey() { + return "new project wizard"; } - @Nullable @Override - protected String getDimensionServiceKey() { - return "new project wizard"; + public StepSequence getSequence() { + return mySequence; } } diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizardAction.java b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizardAction.java index 676c8b106289..29226b6613ce 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizardAction.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizardAction.java @@ -15,8 +15,10 @@ */ package com.intellij.ide.projectWizard; +import com.intellij.ide.impl.NewProjectUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; /** * @author Dmitry Avdeev @@ -25,6 +27,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; public class NewProjectWizardAction extends AnAction { @Override public void actionPerformed(AnActionEvent e) { - new NewProjectWizard("New Project", getEventProject(e)).show(); + NewProjectWizard wizard = new NewProjectWizard(null, ModulesProvider.EMPTY_MODULES_PROVIDER, null); + NewProjectUtil.createNewProject(getEventProject(e), wizard); } } diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectCategory.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectCategory.java index 0553895d269f..2d7f32bcb268 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectCategory.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectCategory.java @@ -24,6 +24,7 @@ import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.Arrays; import java.util.Map; @@ -46,10 +47,18 @@ public abstract class ProjectCategory { return createModuleBuilder().getPresentableName(); } + public Icon getIcon() { + return createModuleBuilder().getNodeIcon(); + } + public String getDescription() { return createModuleBuilder().getDescription(); } + public String getGroupName() { + return createModuleBuilder().getGroupName(); + } + @Nullable public String getParentId() { return null; diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSettingsStep.form b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSettingsStep.form new file mode 100644 index 000000000000..625a1ea93530 --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSettingsStep.form @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.ide.projectWizard.ProjectSettingsStep"> + <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <xy x="20" y="20" width="608" height="215"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <grid id="e5cc3" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <grid id="5d4a2" binding="myExpertPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0"> + <constraints> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <grid id="a59bf" binding="myExpertPanel" layout-manager="GridBagLayout"> + <constraints border-constraint="Center"/> + <properties/> + <border type="none"/> + <children/> + </grid> + </children> + </grid> + <grid id="fb50c" binding="myModulePanel" layout-manager="GridBagLayout"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="40abf" class="javax.swing.JLabel"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <gridbag weightx="0.0" weighty="1.0"/> + </constraints> + <properties> + <labelFor value="edb8a"/> + <text resource-bundle="messages/ProjectBundle" key="project.new.wizard.module.name.title"/> + </properties> + </component> + <component id="edb8a" class="javax.swing.JTextField" binding="myModuleName"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + <gridbag top="0" left="0" bottom="5" right="0" weightx="1.0" weighty="1.0"/> + </constraints> + <properties/> + </component> + <component id="7afef" class="javax.swing.JLabel"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <gridbag weightx="0.0" weighty="1.0"/> + </constraints> + <properties> + <labelFor value="d2d6b"/> + <text resource-bundle="messages/ProjectBundle" key="project.new.wizard.module.root.title"/> + </properties> + </component> + <component id="d2d6b" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myModuleContentRoot"> + <constraints> + <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <gridbag top="0" left="0" bottom="5" right="0" weightx="1.0" weighty="1.0"/> + </constraints> + <properties/> + </component> + <component id="2ac4e" class="javax.swing.JLabel"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <gridbag weightx="0.0" weighty="1.0"/> + </constraints> + <properties> + <labelFor value="9e1b8"/> + <text resource-bundle="messages/ProjectBundle" key="project.new.wizard.module.file.title"/> + </properties> + </component> + <component id="9e1b8" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myModuleFileLocation"> + <constraints> + <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + <gridbag top="0" left="0" bottom="5" right="0" weightx="1.0" weighty="1.0"/> + </constraints> + <properties/> + </component> + </children> + </grid> + <grid id="caf4" binding="mySettingsPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="empty"> + <size top="0" left="0" bottom="10" right="0"/> + </border> + <children/> + </grid> + <vspacer id="44e0b"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + </constraints> + </vspacer> + </children> + </grid> + </children> + </grid> +</form> diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSettingsStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSettingsStep.java new file mode 100644 index 000000000000..3db63ca3945d --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSettingsStep.java @@ -0,0 +1,463 @@ +/* + * 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.ide.projectWizard; + +import com.intellij.ide.IdeBundle; +import com.intellij.ide.highlighter.ModuleFileType; +import com.intellij.ide.util.BrowseFilesListener; +import com.intellij.ide.util.newProjectWizard.SelectTemplateSettings; +import com.intellij.ide.util.projectWizard.*; +import com.intellij.openapi.components.StorageScheme; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.platform.templates.TemplateModuleBuilder; +import com.intellij.projectImport.ProjectFormatPanel; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.HideableDecorator; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.components.JBLabel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.io.File; + +/** + * @author Dmitry Avdeev + * Date: 9/26/12 + */ +public class ProjectSettingsStep extends ModuleWizardStep implements SettingsStep { + + private JPanel mySettingsPanel; + + private JPanel myExpertPlaceholder; + private JPanel myExpertPanel; + private final HideableDecorator myExpertDecorator; + + private final NamePathComponent myNamePathComponent; + private final ProjectFormatPanel myFormatPanel; + + private JTextField myModuleName; + private TextFieldWithBrowseButton myModuleContentRoot; + private TextFieldWithBrowseButton myModuleFileLocation; + private JPanel myModulePanel; + + private JPanel myPanel; + + private boolean myModuleNameChangedByUser = false; + private boolean myModuleNameDocListenerEnabled = true; + + private boolean myContentRootChangedByUser = false; + private boolean myContentRootDocListenerEnabled = true; + + private boolean myImlLocationChangedByUser = false; + private boolean myImlLocationDocListenerEnabled = true; + + private final WizardContext myWizardContext; + @Nullable + private ModuleWizardStep mySettingsStep; + + public ProjectSettingsStep(WizardContext context) { + + myWizardContext = context; + + myFormatPanel = new ProjectFormatPanel(); + myNamePathComponent = NamePathComponent.initNamePathComponent(context); + if (context.isCreatingNewProject()) { + mySettingsPanel.add(myNamePathComponent, BorderLayout.NORTH); + addExpertPanel(myModulePanel); + } + else { + mySettingsPanel.add(myModulePanel, BorderLayout.NORTH); + } + bindModuleSettings(); + + myExpertDecorator = new HideableDecorator(myExpertPlaceholder, "Mor&e Settings", false); + myExpertPanel.setBorder(IdeBorderFactory.createEmptyBorder(0, IdeBorderFactory.TITLED_BORDER_INDENT, 5, 0)); + myExpertDecorator.setContentComponent(myExpertPanel); + + if (myWizardContext.isCreatingNewProject()) { + addProjectFormat(myModulePanel); + } + } + + private JTextField getNameComponent() { + return myWizardContext.isCreatingNewProject() ? myNamePathComponent.getNameComponent() : myModuleName; + } + + private void addProjectFormat(JPanel panel) { + addField("Project \u001bformat:", myFormatPanel.getStorageFormatComboBox(), panel); + } + + @Override + public String getHelpId() { + return myWizardContext.isCreatingNewProject() ? "New_Project_Main_Settings" : "Add_Module_Main_Settings"; + } + + private void setupPanels() { + + ModuleBuilder moduleBuilder = (ModuleBuilder)myWizardContext.getProjectBuilder(); + restorePanel(myNamePathComponent, 4); + restorePanel(myModulePanel, myWizardContext.isCreatingNewProject() ? 8 : 6); + restorePanel(myExpertPanel, myWizardContext.isCreatingNewProject() ? 1 : 0); + mySettingsStep = moduleBuilder == null ? null : moduleBuilder.modifySettingsStep(this); + + myExpertPlaceholder.setVisible(!(moduleBuilder instanceof TemplateModuleBuilder) && myExpertPanel.getComponentCount() > 0); + for (int i = 0; i < 6; i++) { + myModulePanel.getComponent(i).setVisible(!(moduleBuilder instanceof EmptyModuleBuilder)); + } + mySettingsPanel.revalidate(); + mySettingsPanel.repaint(); + } + + private static int restorePanel(JPanel component, int i) { + int removed = 0; + while (component.getComponentCount() > i) { + component.remove(component.getComponentCount() - 1); + removed++; + } + return removed; + } + + @Override + public void updateStep() { + myExpertDecorator.setOn(SelectTemplateSettings.getInstance().EXPERT_MODE); + setupPanels(); + } + + @Override + public void onStepLeaving() { + SelectTemplateSettings settings = SelectTemplateSettings.getInstance(); + settings.EXPERT_MODE = myExpertDecorator.isExpanded(); + } + + @Override + public boolean validate() throws ConfigurationException { + + if (myWizardContext.isCreatingNewProject()) { + if (!myNamePathComponent.validateNameAndPath(myWizardContext, myFormatPanel.isDefault())) return false; + } + + if (!validateModulePaths()) return false; + if (!myWizardContext.isCreatingNewProject()) { + validateExistingModuleName(); + } + + if (mySettingsStep != null) { + return mySettingsStep.validate(); + } + return true; + } + + @Override + public JComponent getComponent() { + return myPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return getNameComponent(); + } + + @Override + public void updateDataModel() { + + myWizardContext.setProjectName(myNamePathComponent.getNameValue()); + myWizardContext.setProjectFileDirectory(myNamePathComponent.getPath()); + myFormatPanel.updateData(myWizardContext); + + ModuleBuilder moduleBuilder = (ModuleBuilder)myWizardContext.getProjectBuilder(); + if (moduleBuilder != null) { + final String moduleName = getModuleName(); + moduleBuilder.setName(moduleName); + moduleBuilder.setModuleFilePath( + FileUtil.toSystemIndependentName(myModuleFileLocation.getText()) + "/" + moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION); + moduleBuilder.setContentEntryPath(FileUtil.toSystemIndependentName(getModuleContentRoot())); + if (moduleBuilder instanceof TemplateModuleBuilder) { + myWizardContext.setProjectStorageFormat(StorageScheme.DIRECTORY_BASED); + } + } + + if (mySettingsStep != null) { + mySettingsStep.updateDataModel(); + } + } + + @Override + public String getName() { + return "Project Settings"; + } + + @Override + public WizardContext getContext() { + return myWizardContext; + } + + @Override + public void addSettingsField(@NotNull String label, @NotNull JComponent field) { + JPanel panel = myWizardContext.isCreatingNewProject() ? myNamePathComponent : myModulePanel; + addField(label, field, panel); + } + + private static void addField(String label, JComponent field, JPanel panel) { + JLabel jLabel = new JBLabel(label); + jLabel.setLabelFor(field); + panel.add(jLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.WEST, + GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0)); + panel.add(field, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0, GridBagConstraints.NORTHWEST, + GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0)); + } + + @Override + public void addSettingsComponent(@NotNull JComponent component) { + JPanel panel = myWizardContext.isCreatingNewProject() ? myNamePathComponent : myModulePanel; + panel.add(component, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0, GridBagConstraints.NORTHWEST, + GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + } + + @Override + public void addExpertPanel(@NotNull JComponent panel) { + myExpertPanel.add(panel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0, GridBagConstraints.NORTHWEST, + GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + } + + @Override + public void addExpertField(@NotNull String label, @NotNull JComponent field) { + JPanel panel = myWizardContext.isCreatingNewProject() ? myModulePanel : myExpertPanel; + addField(label, field, panel); + } + + public void bindModuleSettings() { + + myNamePathComponent.getNameComponent().getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + if (!myModuleNameChangedByUser) { + setModuleName(myNamePathComponent.getNameValue()); + } + } + }); + + myModuleContentRoot.addBrowseFolderListener(ProjectBundle.message("project.new.wizard.module.content.root.chooser.title"), ProjectBundle.message("project.new.wizard.module.content.root.chooser.description"), + myWizardContext.getProject(), BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR); + + myNamePathComponent.getPathComponent().getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + if (!myContentRootChangedByUser) { + setModuleContentRoot(myNamePathComponent.getPath()); + } + } + }); + myModuleName.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + if (myModuleNameDocListenerEnabled) { + myModuleNameChangedByUser = true; + } + String path = getDefaultBaseDir(myWizardContext); + final String moduleName = getModuleName(); + if (path.length() > 0 && !Comparing.strEqual(moduleName, myNamePathComponent.getNameValue())) { + path += "/" + moduleName; + } + if (!myContentRootChangedByUser) { + final boolean f = myModuleNameChangedByUser; + myModuleNameChangedByUser = true; + setModuleContentRoot(path); + myModuleNameChangedByUser = f; + } + if (!myImlLocationChangedByUser) { + setImlFileLocation(path); + } + } + }); + myModuleContentRoot.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + if (myContentRootDocListenerEnabled) { + myContentRootChangedByUser = true; + } + if (!myImlLocationChangedByUser) { + setImlFileLocation(getModuleContentRoot()); + } + if (!myModuleNameChangedByUser) { + final String path = FileUtil.toSystemIndependentName(getModuleContentRoot()); + final int idx = path.lastIndexOf("/"); + + boolean f = myContentRootChangedByUser; + myContentRootChangedByUser = true; + + boolean i = myImlLocationChangedByUser; + myImlLocationChangedByUser = true; + + setModuleName(idx >= 0 ? path.substring(idx + 1) : ""); + + myContentRootChangedByUser = f; + myImlLocationChangedByUser = i; + } + } + }); + + myModuleFileLocation.addBrowseFolderListener(ProjectBundle.message("project.new.wizard.module.file.chooser.title"), ProjectBundle.message("project.new.wizard.module.file.description"), + myWizardContext.getProject(), BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR); + myModuleFileLocation.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + if (myImlLocationDocListenerEnabled) { + myImlLocationChangedByUser = true; + } + } + }); + myNamePathComponent.getPathComponent().getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + if (!myImlLocationChangedByUser) { + setImlFileLocation(myNamePathComponent.getPath()); + } + } + }); + if (myWizardContext.isCreatingNewProject()) { + setModuleName(myNamePathComponent.getNameValue()); + setModuleContentRoot(myNamePathComponent.getPath()); + setImlFileLocation(myNamePathComponent.getPath()); + } else { + final Project project = myWizardContext.getProject(); + assert project != null; + VirtualFile baseDir = project.getBaseDir(); + if (baseDir != null) { //e.g. was deleted + final String baseDirPath = baseDir.getPath(); + String moduleName = ProjectWizardUtil.findNonExistingFileName(baseDirPath, "untitled", ""); + String contentRoot = baseDirPath + "/" + moduleName; + if (!Comparing.strEqual(project.getName(), myWizardContext.getProjectName()) && !myWizardContext.isCreatingNewProject() && myWizardContext.getProjectName() != null) { + moduleName = ProjectWizardUtil.findNonExistingFileName(myWizardContext.getProjectFileDirectory(), myWizardContext.getProjectName(), ""); + contentRoot = myWizardContext.getProjectFileDirectory(); + } + setModuleName(moduleName); + setModuleContentRoot(contentRoot); + setImlFileLocation(contentRoot); + myModuleName.select(0, moduleName.length()); + } + } + } + + private void validateExistingModuleName() throws ConfigurationException { + final String moduleName = getModuleName(); + final Module module; + final ProjectStructureConfigurable fromConfigurable = ProjectStructureConfigurable.getInstance(myWizardContext.getProject()); + if (fromConfigurable != null) { + module = fromConfigurable.getModulesConfig().getModule(moduleName); + } + else { + module = ModuleManager.getInstance(myWizardContext.getProject()).findModuleByName(moduleName); + } + if (module != null) { + throw new ConfigurationException("Module \'" + moduleName + "\' already exist in project. Please, specify another name."); + } + } + + private boolean validateModulePaths() throws ConfigurationException { + final String moduleName = getModuleName(); + final String moduleFileDirectory = myModuleFileLocation.getText(); + if (moduleFileDirectory.length() == 0) { + throw new ConfigurationException("Enter module file location"); + } + if (moduleName.length() == 0) { + throw new ConfigurationException("Enter a module name"); + } + + if (!ProjectWizardUtil.createDirectoryIfNotExists(IdeBundle.message("directory.module.file"), moduleFileDirectory, + myImlLocationChangedByUser)) { + return false; + } + if (!ProjectWizardUtil.createDirectoryIfNotExists(IdeBundle.message("directory.module.content.root"), myModuleContentRoot.getText(), + myContentRootChangedByUser)) { + return false; + } + + File moduleFile = new File(moduleFileDirectory, moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION); + if (moduleFile.exists()) { + int answer = Messages.showYesNoDialog(IdeBundle.message("prompt.overwrite.project.file", moduleFile.getAbsolutePath(), + IdeBundle.message("project.new.wizard.module.identification")), + IdeBundle.message("title.file.already.exists"), Messages.getQuestionIcon()); + if (answer != 0) { + return false; + } + } + return true; + } + + protected String getModuleContentRoot() { + return myModuleContentRoot.getText(); + } + + private String getDefaultBaseDir(WizardContext wizardContext) { + if (wizardContext.isCreatingNewProject()) { + return myNamePathComponent.getPath(); + } else { + final Project project = wizardContext.getProject(); + assert project != null; + final VirtualFile baseDir = project.getBaseDir(); + if (baseDir != null) { + return baseDir.getPath(); + } + return ""; + } + } + + private void setImlFileLocation(final String path) { + myImlLocationDocListenerEnabled = false; + myModuleFileLocation.setText(FileUtil.toSystemDependentName(path)); + myImlLocationDocListenerEnabled = true; + } + + private void setModuleContentRoot(final String path) { + myContentRootDocListenerEnabled = false; + myModuleContentRoot.setText(FileUtil.toSystemDependentName(path)); + myContentRootDocListenerEnabled = true; + } + + public void setModuleName(String moduleName) { + myModuleNameDocListenerEnabled = false; + myModuleName.setText(moduleName); + myModuleNameDocListenerEnabled = true; + } + + @NotNull + public JTextField getModuleNameField() { + return myModuleName; + } + + protected String getModuleName() { + return myModuleName.getText().trim(); + } + + @TestOnly + @Nullable + public ModuleWizardStep getSettingsStep() { + return mySettingsStep; + } + + @Override + public Icon getIcon() { + return null; + } +} diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSummaryStep.form b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSummaryStep.form new file mode 100644 index 000000000000..a0f1f25df0ec --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSummaryStep.form @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.ide.projectWizard.ProjectSummaryStep"> + <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <xy x="20" y="20" width="500" height="400"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <grid id="15993" binding="myNameAndLocationPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children/> + </grid> + <vspacer id="c6894"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + </constraints> + </vspacer> + </children> + </grid> +</form> diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSummaryStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSummaryStep.java new file mode 100644 index 000000000000..28e9cec7dee9 --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectSummaryStep.java @@ -0,0 +1,58 @@ +/* + * 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.ide.projectWizard; + +import com.intellij.ide.util.projectWizard.NamePathComponent; +import com.intellij.ide.util.projectWizard.WizardContext; +import com.intellij.ide.wizard.CommitStepException; +import com.intellij.ide.wizard.StepAdapter; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Dmitry Avdeev + * Date: 20.09.13 + */ +public class ProjectSummaryStep extends StepAdapter { + + private final WizardContext myWizardContext; + private JPanel myRootPanel; + private JPanel myNameAndLocationPanel; + private final NamePathComponent myNamePathComponent; + + public ProjectSummaryStep(WizardContext context) { + myWizardContext = context; + myNamePathComponent = NamePathComponent.initNamePathComponent(myWizardContext); + myNameAndLocationPanel.add(myNamePathComponent, BorderLayout.CENTER); + } + + @Override + public void _commit(boolean finishChosen) throws CommitStepException { + myWizardContext.setProjectName(myNamePathComponent.getNameValue()); + myWizardContext.setProjectFileDirectory(myNamePathComponent.getPath()); + } + + @Override + public JComponent getComponent() { + return myRootPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myNamePathComponent.getNameComponent(); + } +} diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form index 85e5a7596aaa..513c11a16c88 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form @@ -39,7 +39,7 @@ </scrollpane> </children> </grid> - <grid id="ad16" binding="myOptionsPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> + <grid id="ad16" binding="myOptionsPanel" layout-manager="CardLayout" hgap="0" vgap="0"> <constraints> <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java index 07a1e2cf8d08..fc9b0f930a16 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java @@ -18,72 +18,171 @@ package com.intellij.ide.projectWizard; import com.intellij.framework.FrameworkGroup; import com.intellij.framework.FrameworkTypeEx; import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider; -import com.intellij.ide.util.frameworkSupport.FrameworkSupportModelImpl; import com.intellij.ide.util.frameworkSupport.FrameworkSupportUtil; import com.intellij.ide.util.newProjectWizard.AddSupportForFrameworksPanel; import com.intellij.ide.util.newProjectWizard.impl.FrameworkSupportModelBase; -import com.intellij.ide.wizard.StepAdapter; -import com.intellij.openapi.Disposable; +import com.intellij.ide.util.projectWizard.ModuleBuilder; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.util.projectWizard.WizardContext; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer; import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.CollectionListModel; +import com.intellij.ui.ColoredListCellRenderer; import com.intellij.ui.components.JBList; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FactoryMap; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.util.*; import java.util.List; /** * @author Dmitry Avdeev * Date: 04.09.13 */ -public class ProjectTypeStep extends StepAdapter { +public class ProjectTypeStep extends ModuleWizardStep { + private static final String FRAMEWORKS_CARD = "frameworks card"; + private final WizardContext myContext; + private final NewProjectWizard myWizard; + private final ModulesProvider myModulesProvider; private JPanel myPanel; private JBList myProjectTypeList; private JPanel myOptionsPanel; - private final AddSupportForFrameworksPanel myFrameworksPanel; - private final FrameworkSupportModelBase myModel; + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private final FactoryMap<ProjectCategory, ModuleBuilder> myBuilders = new FactoryMap<ProjectCategory, ModuleBuilder>() { + @Nullable + @Override + protected ModuleBuilder create(ProjectCategory key) { + return key.createModuleBuilder(); + } + }; + private final Set<String> myCards = new HashSet<String>(); - public ProjectTypeStep(Project project, Disposable disposable) { + private final AddSupportForFrameworksPanel myFrameworksPanel; + private final ModuleBuilder.ModuleConfigurationUpdater myConfigurationUpdater; + public ProjectTypeStep(WizardContext context, NewProjectWizard wizard, ModulesProvider modulesProvider) { + myContext = context; + myWizard = wizard; + myModulesProvider = modulesProvider; + Project project = context.getProject(); final LibrariesContainer container = LibrariesContainerFactory.createContainer(project); - myModel = new FrameworkSupportModelImpl(project, "", container); - ProjectCategory[] projectCategories = ProjectCategory.EXTENSION_POINT_NAME.getExtensions(); - myProjectTypeList.setModel(new CollectionListModel<ProjectCategory>(Arrays.asList(projectCategories))); + FrameworkSupportModelBase model = new FrameworkSupportModelBase(project, null, container) { + @NotNull + @Override + public String getBaseDirectoryForLibrariesPath() { + return StringUtil.notNullize(getSelectedBuilder().getContentEntryPath()); + } + }; + myConfigurationUpdater = new ModuleBuilder.ModuleConfigurationUpdater() { + @Override + public void update(@NotNull Module module, @NotNull ModifiableRootModel rootModel) { + myFrameworksPanel.addSupport(module, rootModel); + } + }; + + myProjectTypeList.setCellRenderer(new ColoredListCellRenderer() { + @Override + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + ProjectCategory category = (ProjectCategory)value; + append(category.getDisplayName()); + setIcon(category.getIcon()); + } + }); + + List<ProjectCategory> categories = new ArrayList<ProjectCategory>(); + categories.addAll(ContainerUtil.map(ModuleBuilder.getAllBuilders(), new Function<ModuleBuilder, ProjectCategory>() { + @Override + public ProjectCategory fun(ModuleBuilder builder) { + return new BuilderBasedProjectType(builder); + } + })); + categories.addAll(Arrays.asList(ProjectCategory.EXTENSION_POINT_NAME.getExtensions())); + + final MultiMap<String, ProjectCategory> map = new MultiMap<String, ProjectCategory>(); + for (ProjectCategory category : categories) { + map.putValue(category.getGroupName(), category); + } + Collections.sort(categories, new Comparator<ProjectCategory>() { + @Override + public int compare(ProjectCategory o1, ProjectCategory o2) { + return map.get(o2.getGroupName()).size() - map.get(o1.getGroupName()).size(); + } + }); + + myProjectTypeList.setModel(new CollectionListModel<ProjectCategory>(categories)); myProjectTypeList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { - updateFrameworks((ProjectCategory)myProjectTypeList.getSelectedValue()); + ModuleBuilder builder = getSelectedBuilder(); + myContext.setProjectBuilder(builder); + myWizard.getSequence().setType(builder.getBuilderId()); + builder.addModuleConfigurationUpdater(myConfigurationUpdater); + updateOptionsPanel((ProjectCategory)myProjectTypeList.getSelectedValue()); } }); - myFrameworksPanel = new AddSupportForFrameworksPanel(Collections.<FrameworkSupportInModuleProvider>emptyList(), myModel, true); - Disposer.register(disposable, myFrameworksPanel); + for (ProjectCategory category : categories) { + myWizard.getSequence().addStepsForBuilder(myBuilders.get(category), context, modulesProvider, true); + } + + myFrameworksPanel = new AddSupportForFrameworksPanel(Collections.<FrameworkSupportInModuleProvider>emptyList(), model, true); + Disposer.register(wizard.getDisposable(), myFrameworksPanel); - myOptionsPanel.add(myFrameworksPanel.getMainPanel(), BorderLayout.CENTER); + myOptionsPanel.add(myFrameworksPanel.getMainPanel(), FRAMEWORKS_CARD); myProjectTypeList.setSelectedIndex(0); } - private void updateFrameworks(ProjectCategory projectCategory) { - List<FrameworkSupportInModuleProvider> providers = new ArrayList<FrameworkSupportInModuleProvider>(); - if (projectCategory != null) { + private ModuleBuilder getSelectedBuilder() { + ProjectCategory projectCategory = (ProjectCategory)myProjectTypeList.getSelectedValue(); + return myBuilders.get(projectCategory); + } + + private void updateOptionsPanel(ProjectCategory projectCategory) { + if (projectCategory == null) return; + ModuleBuilder builder = myBuilders.get(projectCategory); + JComponent panel = builder.getCustomOptionsPanel(this); + String card; + if (panel != null) { + card = builder.getBuilderId(); + if (myCards.add(card)) { + myOptionsPanel.add(panel, card); + } + } + else { + card = FRAMEWORKS_CARD; + List<FrameworkSupportInModuleProvider> providers = new ArrayList<FrameworkSupportInModuleProvider>(); for (FrameworkSupportInModuleProvider framework : FrameworkSupportUtil.getAllProviders()) { if (matchFramework(projectCategory, framework)) { providers.add(framework); } } + myFrameworksPanel.setProviders(providers); + for (FrameworkSupportInModuleProvider provider : providers) { + if (ArrayUtil.contains(provider.getFrameworkType().getId(), projectCategory.getAssociatedFrameworkIds())) { + CheckedTreeNode treeNode = myFrameworksPanel.findNodeFor(provider); + treeNode.setChecked(true); + } + } } - myFrameworksPanel.setProviders(providers); + ((CardLayout)myOptionsPanel.getLayout()).show(myOptionsPanel, card); } private static boolean matchFramework(ProjectCategory projectCategory, FrameworkSupportInModuleProvider framework) { @@ -120,6 +219,11 @@ public class ProjectTypeStep extends StepAdapter { } @Override + public void updateDataModel() { + myWizard.getSequence().addStepsForBuilder(getSelectedBuilder(), myContext, myModulesProvider, true); + } + + @Override public JComponent getPreferredFocusedComponent() { return myProjectTypeList; } diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.java b/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.java new file mode 100644 index 000000000000..b6d8cf70c6f3 --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.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.intellij.ide.projectWizard; + +import com.intellij.ide.util.projectWizard.ModuleBuilder; +import com.intellij.platform.templates.ArchivedTemplatesFactory; +import com.intellij.platform.templates.LocalArchivedTemplate; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.io.File; +import java.net.URL; + +/** + * @author Dmitry Avdeev + * Date: 20.09.13 + */ +public abstract class TemplateBasedProjectType extends ProjectCategory { + + private final LocalArchivedTemplate myTemplate; + + public TemplateBasedProjectType(String templatePath) { + ClassLoader loader = getClass().getClassLoader(); + URL resource = loader.getResource(templatePath); + assert resource != null : templatePath; + String name = ArchivedTemplatesFactory.getTemplateName(new File(templatePath).getName()); + myTemplate = new LocalArchivedTemplate(name, resource, loader); + } + + @NotNull + @Override + public ModuleBuilder createModuleBuilder() { + return myTemplate.createModuleBuilder(); + } + + @Override + public String getId() { + return getDisplayName(); + } + + @Override + public String getDisplayName() { + return myTemplate.getName(); + } + + @Override + public String getDescription() { + return myTemplate.getDescription(); + } + + @Override + public Icon getIcon() { + return myTemplate.getIcon(); + } +} diff --git a/java/idea-ui/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportUtil.java b/java/idea-ui/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportUtil.java index 78c9c686394d..b2b81ee4a516 100644 --- a/java/idea-ui/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportUtil.java +++ b/java/idea-ui/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportUtil.java @@ -123,6 +123,12 @@ public class FrameworkSupportUtil { dependencies.add(underlyingProvider); } } + for (String frameworkId : provider.getOptionalDependenciesFrameworkIds()) { + FrameworkSupportInModuleProvider dep = findProvider(frameworkId, myFrameworkSupportProviders); + if (dep != null) { + dependencies.add(dep); + } + } if (provider instanceof OldFrameworkSupportProviderWrapper) { String[] ids = ((OldFrameworkSupportProviderWrapper)provider).getProvider().getPrecedingFrameworkProviderIds(); for (String id : ids) { diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java new file mode 100644 index 000000000000..deca30051b71 --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AbstractProjectWizard.java @@ -0,0 +1,263 @@ +/* + * 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.ide.util.newProjectWizard; + +import com.intellij.ide.highlighter.ModuleFileType; +import com.intellij.ide.highlighter.ProjectFileType; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.util.projectWizard.ProjectBuilder; +import com.intellij.ide.util.projectWizard.WizardContext; +import com.intellij.ide.wizard.AbstractWizard; +import com.intellij.ide.wizard.CommitStepException; +import com.intellij.openapi.components.StorageScheme; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import java.awt.*; +import java.io.File; + +/** + * @author Dmitry Avdeev + * Date: 19.09.13 + */ +public abstract class AbstractProjectWizard extends AbstractWizard<ModuleWizardStep> { + protected final WizardContext myWizardContext; + + public AbstractProjectWizard(String title, Project project, String defaultPath) { + super(title, project); + myWizardContext = initContext(project, defaultPath); + } + + public AbstractProjectWizard(String title, Project project, Component dialogParent) { + super(title, dialogParent); + myWizardContext = initContext(project, null); + } + + public abstract StepSequence getSequence(); + + private static WizardContext initContext(@Nullable Project project, @Nullable String defaultPath) { + WizardContext context = new WizardContext(project); + if (defaultPath != null) { + context.setProjectFileDirectory(defaultPath); + context.setProjectName(defaultPath.substring(FileUtil.toSystemIndependentName(defaultPath).lastIndexOf("/") + 1)); + } + return context; + } + + @Nullable + public static Sdk getNewProjectJdk(WizardContext context) { + if (context.getProjectJdk() != null) { + return context.getProjectJdk(); + } + return getProjectSdkByDefault(context); + } + + public static Sdk getProjectSdkByDefault(WizardContext context) { + final Project project = context.getProject() == null ? ProjectManager.getInstance().getDefaultProject() : context.getProject(); + final Sdk projectJdk = ProjectRootManager.getInstance(project).getProjectSdk(); + if (projectJdk != null) { + return projectJdk; + } + return null; + } + + @NotNull + public String getNewProjectFilePath() { + if (myWizardContext.getProjectStorageFormat() == StorageScheme.DEFAULT) { + return myWizardContext.getProjectFileDirectory() + File.separator + myWizardContext.getProjectName() + ProjectFileType.DOT_DEFAULT_EXTENSION; + } + else { + return myWizardContext.getProjectFileDirectory(); + } + } + + @NotNull + public StorageScheme getStorageScheme() { + return myWizardContext.getProjectStorageFormat(); + } + + public ProjectBuilder getProjectBuilder() { + return myWizardContext.getProjectBuilder(); + } + + public String getProjectName() { + return myWizardContext.getProjectName(); + } + + @Nullable + public Sdk getNewProjectJdk() { + return getNewProjectJdk(myWizardContext); + } + + @NotNull + public String getNewCompileOutput() { + final String projectFilePath = myWizardContext.getProjectFileDirectory(); + @NonNls String path = myWizardContext.getCompilerOutputDirectory(); + if (path == null) { + path = StringUtil.endsWithChar(projectFilePath, '/') ? projectFilePath + "out" : projectFilePath + "/out"; + } + return path; + } + + protected void updateStep() { + if (!mySteps.isEmpty()) { + getCurrentStepObject().updateStep(); + } + super.updateStep(); + myIcon.setIcon(null); + } + + protected void dispose() { + for (ModuleWizardStep step : mySteps) { + step.disposeUIResources(); + } + super.dispose(); + } + + protected final void doOKAction() { + int idx = getCurrentStep(); + try { + do { + final ModuleWizardStep step = mySteps.get(idx); + if (step != getCurrentStepObject()) { + step.updateStep(); + } + if (!commitStepData(step)) { + return; + } + step.onStepLeaving(); + try { + step._commit(true); + } + catch (CommitStepException e) { + String message = e.getMessage(); + if (message != null) { + Messages.showErrorDialog(getCurrentStepComponent(), message); + } + return; + } + if (!isLastStep(idx)) { + idx = getNextStep(idx); + } else { + break; + } + } while (true); + } + finally { + myCurrentStep = idx; + updateStep(); + } + super.doOKAction(); + } + + protected boolean commitStepData(final ModuleWizardStep step) { + try { + if (!step.validate()) { + return false; + } + } + catch (ConfigurationException e) { + Messages.showErrorDialog(myContentPanel, e.getMessage(), e.getTitle()); + return false; + } + step.updateDataModel(); + return true; + } + + public void doNextAction() { + final ModuleWizardStep step = getCurrentStepObject(); + if (!commitStepData(step)) { + return; + } + step.onStepLeaving(); + super.doNextAction(); + } + + + protected String getHelpID() { + ModuleWizardStep step = getCurrentStepObject(); + if (step != null) { + return step.getHelpId(); + } + return null; + } + + @TestOnly + public void doOk() { + doOKAction(); + } + + @TestOnly + public boolean isLast() { + return isLastStep(); + } + + @NonNls + public String getModuleFilePath() { + return myWizardContext.getProjectFileDirectory() + File.separator + myWizardContext.getProjectName() + ModuleFileType.DOT_DEFAULT_EXTENSION; + } + + protected void doPreviousAction() { + final ModuleWizardStep step = getCurrentStepObject(); + step.onStepLeaving(); + super.doPreviousAction(); + } + + public void doCancelAction() { + final ModuleWizardStep step = getCurrentStepObject(); + step.onStepLeaving(); + super.doCancelAction(); + } + + private boolean isLastStep(int step) { + return getNextStep(step) == step; + } + + protected final int getNextStep(final int step) { + ModuleWizardStep nextStep = null; + final StepSequence stepSequence = getSequence(); + if (stepSequence != null) { + ModuleWizardStep current = mySteps.get(step); + nextStep = stepSequence.getNextStep(current); + while (nextStep != null && !nextStep.isStepVisible()) { + nextStep = stepSequence.getNextStep(nextStep); + } + } + return nextStep == null ? step : mySteps.indexOf(nextStep); + } + + protected final int getPreviousStep(final int step) { + ModuleWizardStep previousStep = null; + final StepSequence stepSequence = getSequence(); + if (stepSequence != null) { + previousStep = stepSequence.getPreviousStep(mySteps.get(step)); + while (previousStep != null && !previousStep.isStepVisible()) { + previousStep = stepSequence.getPreviousStep(previousStep); + } + } + return previousStep == null ? 0 : mySteps.indexOf(previousStep); + } +} diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddModuleWizard.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddModuleWizard.java index 2cb74deb03a5..31af15d98b09 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddModuleWizard.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddModuleWizard.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -21,77 +21,58 @@ package com.intellij.ide.util.newProjectWizard; import com.intellij.ide.IdeBundle; -import com.intellij.ide.highlighter.ModuleFileType; -import com.intellij.ide.highlighter.ProjectFileType; import com.intellij.ide.util.newProjectWizard.modes.CreateFromTemplateMode; import com.intellij.ide.util.newProjectWizard.modes.ImportMode; import com.intellij.ide.util.newProjectWizard.modes.WizardMode; import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.ide.util.projectWizard.ProjectBuilder; import com.intellij.ide.util.projectWizard.WizardContext; -import com.intellij.ide.wizard.AbstractWizard; -import com.intellij.ide.wizard.CommitStepException; import com.intellij.ide.wizard.Step; -import com.intellij.openapi.components.StorageScheme; -import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.projectImport.ProjectImportBuilder; import com.intellij.projectImport.ProjectImportProvider; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.Function; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.awt.*; -import java.io.File; -public class AddModuleWizard extends AbstractWizard<ModuleWizardStep> -{ +public class AddModuleWizard extends AbstractProjectWizard { private static final String ADD_MODULE_TITLE = IdeBundle.message("title.add.module"); private static final String NEW_PROJECT_TITLE = IdeBundle.message("title.new.project"); - private final Project myCurrentProject; private ProjectImportProvider[] myImportProviders; private final ModulesProvider myModulesProvider; - private WizardContext myWizardContext; private WizardMode myWizardMode; /** * @param project if null, the wizard will start creating new project, otherwise will add a new module to the existing project. */ public AddModuleWizard(@Nullable final Project project, final @NotNull ModulesProvider modulesProvider, @Nullable String defaultPath) { - super(project == null ? NEW_PROJECT_TITLE : ADD_MODULE_TITLE, project); - myCurrentProject = project; + super(project == null ? NEW_PROJECT_TITLE : ADD_MODULE_TITLE, project, defaultPath); myModulesProvider = modulesProvider; initModuleWizard(project, defaultPath); } /** - * @param project if null, the wizard will start creating new project, otherwise will add a new module to the existing proj. + * @param project if null, the wizard will start creating new project, otherwise will add a new module to the existing project. */ public AddModuleWizard(Component parent, final Project project, @NotNull ModulesProvider modulesProvider) { - super(project == null ? NEW_PROJECT_TITLE : ADD_MODULE_TITLE, parent); - myCurrentProject = project; + super(project == null ? NEW_PROJECT_TITLE : ADD_MODULE_TITLE, project, parent); myModulesProvider = modulesProvider; initModuleWizard(project, null); } /** Import mode */ public AddModuleWizard(@Nullable Project project, String filePath, ProjectImportProvider... importProviders) { - super(getImportWizardTitle(project, importProviders), project); - myCurrentProject = project; + super(getImportWizardTitle(project, importProviders), project, filePath); myImportProviders = importProviders; myModulesProvider = DefaultModulesProvider.createForProject(project); initModuleWizard(project, filePath); @@ -99,8 +80,7 @@ public class AddModuleWizard extends AbstractWizard<ModuleWizardStep> /** Import mode */ public AddModuleWizard(Project project, Component dialogParent, String filePath, ProjectImportProvider... importProviders) { - super(getImportWizardTitle(project, importProviders), dialogParent); - myCurrentProject = project; + super(getImportWizardTitle(project, importProviders), project, dialogParent); myImportProviders = importProviders; myModulesProvider = DefaultModulesProvider.createForProject(project); initModuleWizard(project, filePath); @@ -116,11 +96,6 @@ public class AddModuleWizard extends AbstractWizard<ModuleWizardStep> } private void initModuleWizard(@Nullable final Project project, @Nullable final String defaultPath) { - myWizardContext = new WizardContext(project); - if (defaultPath != null) { - myWizardContext.setProjectFileDirectory(defaultPath); - myWizardContext.setProjectName(defaultPath.substring(FileUtil.toSystemIndependentName(defaultPath).lastIndexOf("/") + 1)); - } myWizardContext.addContextListener(new WizardContext.Listener() { public void buttonsUpdateRequested() { updateButtons(); @@ -167,168 +142,9 @@ public class AddModuleWizard extends AbstractWizard<ModuleWizardStep> return super.addStepComponent(component); } - protected void updateStep() { - if (!mySteps.isEmpty()) { - getCurrentStepObject().updateStep(); - } - super.updateStep(); - myIcon.setIcon(null); - } - - protected void dispose() { - for (ModuleWizardStep step : mySteps) { - step.disposeUIResources(); - } - super.dispose(); - } - - protected final void doOKAction() { - int idx = getCurrentStep(); - try { - do { - final ModuleWizardStep step = mySteps.get(idx); - if (step != getCurrentStepObject()) { - step.updateStep(); - } - if (!commitStepData(step)) { - return; - } - step.onStepLeaving(); - try { - step._commit(true); - } - catch (CommitStepException e) { - String message = e.getMessage(); - if (message != null) { - Messages.showErrorDialog(getCurrentStepComponent(), message); - } - return; - } - if (!isLastStep(idx)) { - idx = getNextStep(idx); - } else { - break; - } - } while (true); - } - finally { - myCurrentStep = idx; - updateStep(); - } - super.doOKAction(); - } - - protected boolean commitStepData(final ModuleWizardStep step) { - try { - if (!step.validate()) { - return false; - } - } - catch (ConfigurationException e) { - Messages.showErrorDialog(myCurrentProject, e.getMessage(), e.getTitle()); - return false; - } - step.updateDataModel(); - return true; - } - - public void doNextAction() { - final ModuleWizardStep step = getCurrentStepObject(); - if (!commitStepData(step)) { - return; - } - step.onStepLeaving(); - super.doNextAction(); - } - - protected void doPreviousAction() { - final ModuleWizardStep step = getCurrentStepObject(); - step.onStepLeaving(); - super.doPreviousAction(); - } - - public void doCancelAction() { - final ModuleWizardStep step = getCurrentStepObject(); - step.onStepLeaving(); - super.doCancelAction(); - } - - private boolean isLastStep(int step) { - return getNextStep(step) == step; - } - - - protected String getHelpID() { - ModuleWizardStep step = getCurrentStepObject(); - if (step != null) { - return step.getHelpId(); - } - return null; - } - - protected final int getNextStep(final int step) { - ModuleWizardStep nextStep = null; - final StepSequence stepSequence = getSequence(); - if (stepSequence != null) { - ModuleWizardStep current = mySteps.get(step); - nextStep = stepSequence.getNextStep(current); - while (nextStep != null && !nextStep.isStepVisible()) { - nextStep = stepSequence.getNextStep(nextStep); - } - } - return nextStep == null ? step : mySteps.indexOf(nextStep); - } - + @Override public StepSequence getSequence() { - return getMode().getSteps(myWizardContext, myModulesProvider); - } - - protected final int getPreviousStep(final int step) { - ModuleWizardStep previousStep = null; - final StepSequence stepSequence = getSequence(); - if (stepSequence != null) { - previousStep = stepSequence.getPreviousStep(mySteps.get(step)); - while (previousStep != null && !previousStep.isStepVisible()) { - previousStep = stepSequence.getPreviousStep(previousStep); - } - } - return previousStep == null ? 0 : mySteps.indexOf(previousStep); - } - - private WizardMode getMode() { - return myWizardMode; - } - - @NotNull - public String getNewProjectFilePath() { - if (myWizardContext.getProjectStorageFormat() == StorageScheme.DEFAULT) { - return myWizardContext.getProjectFileDirectory() + File.separator + myWizardContext.getProjectName() + ProjectFileType.DOT_DEFAULT_EXTENSION; - } - else { - return myWizardContext.getProjectFileDirectory(); - } - } - - @NotNull - public StorageScheme getStorageScheme() { - return myWizardContext.getProjectStorageFormat(); - } - - @Nullable - public static Sdk getNewProjectJdk(WizardContext context) { - if (context.getProjectJdk() != null) { - return context.getProjectJdk(); - } - return getProjectSdkByDefault(context); - } - - public static Sdk getProjectSdkByDefault(WizardContext context) { - final Project project = context.getProject() == null ? ProjectManager.getInstance().getDefaultProject() : context.getProject(); - final Sdk projectJdk = ProjectRootManager.getInstance(project).getProjectSdk(); - if (projectJdk != null) { - return projectJdk; - } - return null; + return myWizardMode.getSteps(myWizardContext, myModulesProvider); } @Nullable @@ -349,34 +165,6 @@ public class AddModuleWizard extends AbstractWizard<ModuleWizardStep> return myWizardContext; } - @Nullable - public Sdk getNewProjectJdk() { - return getNewProjectJdk(myWizardContext); - } - - @NotNull - public String getNewCompileOutput() { - final String projectFilePath = myWizardContext.getProjectFileDirectory(); - @NonNls String path = myWizardContext.getCompilerOutputDirectory(); - if (path == null) { - path = StringUtil.endsWithChar(projectFilePath, '/') ? projectFilePath + "out" : projectFilePath + "/out"; - } - return path; - } - - @NonNls - public String getModuleFilePath() { - return myWizardContext.getProjectFileDirectory() + File.separator + myWizardContext.getProjectName() + ModuleFileType.DOT_DEFAULT_EXTENSION; - } - - public ProjectBuilder getProjectBuilder() { - return myWizardContext.getProjectBuilder(); - } - - public String getProjectName() { - return myWizardContext.getProjectName(); - } - @Override protected String getDimensionServiceKey() { return "NewModule_or_Project.wizard"; @@ -404,20 +192,6 @@ public class AddModuleWizard extends AbstractWizard<ModuleWizardStep> return false; } - public ProjectImportProvider[] getImportProviders() { - return myImportProviders; - } - - @TestOnly - public void doOk() { - doOKAction(); - } - - @TestOnly - public boolean isLast() { - return isLastStep(); - } - @TestOnly public void commit() { commitStepData(getCurrentStepObject()); diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddSupportForFrameworksPanel.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddSupportForFrameworksPanel.java index 6a8fef813567..7e324c2054b3 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddSupportForFrameworksPanel.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/AddSupportForFrameworksPanel.java @@ -40,6 +40,7 @@ import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.ScrollPaneFactory; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,6 +48,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; import java.awt.*; import java.util.*; import java.util.List; @@ -78,7 +80,7 @@ public class AddSupportForFrameworksPanel implements Disposable { myLibrariesContainer = model.getLibrariesContainer(); myLabel.setVisible(!vertical); - Splitter splitter = vertical ? new Splitter(true, 0.6f, 0.3f, 0.9f) : new Splitter(false, 0.3f, 0.1f, 0.7f); + Splitter splitter = vertical ? new Splitter(true, 0.6f) : new Splitter(false, 0.3f, 0.1f, 0.7f); myFrameworksTree = new FrameworksTree() { @Override protected void onNodeStateChanged(CheckedTreeNode node) { @@ -109,13 +111,13 @@ public class AddSupportForFrameworksPanel implements Disposable { splitter.setSecondComponent(myOptionsPanel); myFrameworksPanel.add(splitter, BorderLayout.CENTER); - myFrameworksTree.setSelectionRow(0); } public void setProviders(List<FrameworkSupportInModuleProvider> providers) { myProviders = providers; createNodes(); myFrameworksTree.setRoots(myRoots); + myFrameworksTree.setSelectionRow(0); } protected void onFrameworkStateChanged() {} @@ -299,7 +301,7 @@ public class AddSupportForFrameworksPanel implements Disposable { private static void addChildFrameworks(final List<FrameworkSupportNodeBase> list, final List<FrameworkSupportNode> result, final boolean selectedOnly) { for (FrameworkSupportNodeBase node : list) { - if (!selectedOnly || node.isChecked()) { + if (!selectedOnly || node.isChecked() || node instanceof FrameworkGroupNode) { if (node instanceof FrameworkSupportNode) { result.add((FrameworkSupportNode)node); } @@ -351,4 +353,8 @@ public class AddSupportForFrameworksPanel implements Disposable { } }); } + + public CheckedTreeNode findNodeFor(FrameworkSupportInModuleProvider provider) { + return (CheckedTreeNode)TreeUtil.findNodeWithObject((DefaultMutableTreeNode)myFrameworksTree.getModel().getRoot(), provider); + } } diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/FrameworkSupportOptionsComponent.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/FrameworkSupportOptionsComponent.java index 9239c96c6b8b..6dabfa41b171 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/FrameworkSupportOptionsComponent.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/FrameworkSupportOptionsComponent.java @@ -96,6 +96,7 @@ public class FrameworkSupportOptionsComponent { if (description != null) { myLibraryOptionsPanel = new LibraryOptionsPanel(description, myModel.getBaseDirectoryForLibrariesPath(), createLibraryVersionFilter(), container, !myConfigurable.isOnlyLibraryAdded()); + myLibraryOptionsPanel.setLibraryProvider(myModel.getLibraryProvider()); Disposer.register(myConfigurable, myLibraryOptionsPanel); if (addSeparator) { JComponent separator1 = SeparatorFactory.createSeparator("Libraries", null); @@ -111,6 +112,7 @@ public class FrameworkSupportOptionsComponent { if (myLibraryOptionsPanel != null) { myLibraryOptionsPanel.changeBaseDirectoryPath(myModel.getBaseDirectoryForLibrariesPath()); myLibraryOptionsPanel.setVersionFilter(createLibraryVersionFilter()); + myLibraryOptionsPanel.setLibraryProvider(myModel.getLibraryProvider()); myLibraryOptionsPanelWrapper.setVisible(myConfigurable.isVisible()); } } diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SelectTemplateStep.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SelectTemplateStep.java index 13b4fcda9964..40ec96e750ca 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SelectTemplateStep.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SelectTemplateStep.java @@ -106,7 +106,7 @@ public class SelectTemplateStep extends ModuleWizardStep implements SettingsStep Messages.installHyperlinkSupport(myDescriptionPane); myFormatPanel = new ProjectFormatPanel(); - myNamePathComponent = initNamePathComponent(context); + myNamePathComponent = NamePathComponent.initNamePathComponent(context); if (context.isCreatingNewProject()) { mySettingsPanel.add(myNamePathComponent, BorderLayout.NORTH); addExpertPanel(myModulePanel); @@ -168,24 +168,6 @@ public class SelectTemplateStep extends ModuleWizardStep implements SettingsStep return helpId; } - private static NamePathComponent initNamePathComponent(WizardContext context) { - NamePathComponent component = new NamePathComponent( - IdeBundle.message("label.project.name"), - IdeBundle.message("label.project.files.location"), - IdeBundle.message("title.select.project.file.directory", IdeBundle.message("project.new.wizard.project.identification")), - IdeBundle.message("description.select.project.file.directory", StringUtil - .capitalize(IdeBundle.message("project.new.wizard.project.identification"))), - true, false - ); - final String baseDir = context.getProjectFileDirectory(); - final String projectName = context.getProjectName(); - final String initialProjectName = projectName != null ? projectName : ProjectWizardUtil.findNonExistingFileName(baseDir, "untitled", ""); - component.setPath(projectName == null ? (baseDir + File.separator + initialProjectName) : baseDir); - component.setNameValue(initialProjectName); - component.getNameComponent().select(0, initialProjectName.length()); - return component; - } - private void setupPanels(@Nullable ProjectTemplate template) { restorePanel(myNamePathComponent, 4); diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java index 3b3acf09fb0c..bbc9b21769f2 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/StepSequence.java @@ -49,14 +49,17 @@ public class StepSequence { myCommonSteps.add(step); } - public void addCommonFinishingStep(@NotNull ModuleWizardStep step, @NotNull Set<String> suitableTypes) { + public void addCommonFinishingStep(@NotNull ModuleWizardStep step, @Nullable Set<String> suitableTypes) { myCommonFinishingSteps.add(Pair.create(step, suitableTypes)); } - public void addStepsForBuilder(@NotNull AbstractModuleBuilder builder, @NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) { + public void addStepsForBuilder(@NotNull AbstractModuleBuilder builder, + @NotNull WizardContext wizardContext, + @NotNull ModulesProvider modulesProvider, + boolean forNewWizard) { String id = builder.getBuilderId(); if (!mySpecificSteps.containsKey(id)) { - mySpecificSteps.put(id, Arrays.asList(builder.createWizardSteps(wizardContext, modulesProvider))); + mySpecificSteps.put(id, Arrays.asList(builder.createWizardSteps(wizardContext, modulesProvider, forNewWizard))); } } @@ -73,7 +76,8 @@ public class StepSequence { mySelectedSteps.addAll(steps); } for (Pair<ModuleWizardStep, Set<String>> pair : myCommonFinishingSteps) { - if (ContainerUtil.intersects(myTypes, pair.getSecond())) { + Set<String> types = pair.getSecond(); + if (types == null || ContainerUtil.intersects(myTypes, types)) { mySelectedSteps.add(pair.getFirst()); } } @@ -121,8 +125,4 @@ public class StepSequence { ContainerUtil.removeDuplicates(result); return result; } - - public ModuleWizardStep getFirstStep() { - return myCommonSteps.get(0); - } } diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SupportForFrameworksStep.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SupportForFrameworksStep.java index 78f9bb231482..08f56ea707b7 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SupportForFrameworksStep.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/SupportForFrameworksStep.java @@ -17,13 +17,10 @@ import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContaine import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.TestOnly; import javax.swing.*; -import javax.swing.tree.TreeNode; import java.util.List; /** @@ -128,23 +125,4 @@ public class SupportForFrameworksStep extends ModuleWizardStep { return getBaseDirectory(myBuilder); } } - - @TestOnly - public boolean enableSupport(final String frameworkId) { - return !TreeUtil.traverse((TreeNode)mySupportForFrameworksPanel.getFrameworksTree().getModel().getRoot(), new TreeUtil.Traverse() { - @Override - public boolean accept(Object node) { - if (node instanceof FrameworkSupportNode && frameworkId.equals( - ((FrameworkSupportNode)node).getProvider().getFrameworkType().getId())) { - TreeNode parent = ((FrameworkSupportNode)node).getParent(); - if (parent instanceof FrameworkSupportNode) { - ((FrameworkSupportNode)parent).setChecked(true); - } - ((FrameworkSupportNode)node).setChecked(true); - return false; - } - return true; - } - }); - } } diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java index 48a9d9297d79..8faaa8d28a09 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java @@ -15,6 +15,7 @@ */ package com.intellij.ide.util.newProjectWizard.impl; +import com.intellij.facet.impl.ui.libraries.FrameworkLibraryProvider; import com.intellij.framework.FrameworkGroup; import com.intellij.framework.FrameworkGroupVersion; import com.intellij.framework.FrameworkVersion; @@ -51,6 +52,7 @@ public abstract class FrameworkSupportModelBase extends UserDataHolderBase imple private final Map<String, FrameworkSupportNode> mySettingsMap = new HashMap<String, FrameworkSupportNode>(); private final Map<String, FrameworkSupportOptionsComponent> myOptionsComponentsMap = new HashMap<String, FrameworkSupportOptionsComponent>(); private final Map<String, FrameworkVersion> mySelectedVersions = new HashMap<String, FrameworkVersion>(); + private FrameworkLibraryProvider myLibraryProvider; public FrameworkSupportModelBase(final @Nullable Project project, @Nullable ModuleBuilder builder, @NotNull LibrariesContainer librariesContainer) { myProject = project; @@ -159,6 +161,17 @@ public abstract class FrameworkSupportModelBase extends UserDataHolderBase imple return false; } + public FrameworkLibraryProvider getLibraryProvider() { + return myLibraryProvider; + } + + public void setLibraryProvider(FrameworkLibraryProvider libraryProvider) { + myLibraryProvider = libraryProvider; + for (FrameworkSupportOptionsComponent optionsComponent : myOptionsComponentsMap.values()) { + optionsComponent.updateLibrariesPanel(); + } + } + @Nullable public <V extends FrameworkVersion> V getSelectedVersion(@NotNull String frameworkOrGroupId) { return (V)mySelectedVersions.get(frameworkOrGroupId); diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromScratchMode.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromScratchMode.java index bc10c316e6d7..bb631ec75ede 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromScratchMode.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromScratchMode.java @@ -63,7 +63,7 @@ public class CreateFromScratchMode extends WizardMode { StepSequence sequence = new StepSequence(); for (ModuleBuilder builder : builders) { - sequence.addStepsForBuilder(builder, context, modulesProvider); + sequence.addStepsForBuilder(builder, context, modulesProvider, false); } return sequence; } diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromTemplateMode.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromTemplateMode.java index 81aff5b35919..0d057b66904c 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromTemplateMode.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/modes/CreateFromTemplateMode.java @@ -106,7 +106,7 @@ public class CreateFromTemplateMode extends WizardMode { MultiMap<TemplatesGroup, ProjectTemplate> map = getTemplatesMap(context); StepSequence sequence = new StepSequence(); for (ProjectTemplate template : map.values()) { - sequence.addStepsForBuilder(template.createModuleBuilder(), context, modulesProvider); + sequence.addStepsForBuilder(template.createModuleBuilder(), context, modulesProvider, false); } mySelectTemplateStep = new SelectTemplateStep(context, sequence, map); sequence.addCommonStep(mySelectTemplateStep); diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java index 47889b02c923..2a81296181f3 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java @@ -25,6 +25,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.FieldPanel; import com.intellij.util.ui.UIUtil; @@ -118,6 +119,24 @@ public class NamePathComponent extends JPanel{ insets, 0, 0)); } + public static NamePathComponent initNamePathComponent(WizardContext context) { + NamePathComponent component = new NamePathComponent( + IdeBundle.message("label.project.name"), + IdeBundle.message("label.project.files.location"), + IdeBundle.message("title.select.project.file.directory", IdeBundle.message("project.new.wizard.project.identification")), + IdeBundle.message("description.select.project.file.directory", StringUtil + .capitalize(IdeBundle.message("project.new.wizard.project.identification"))), + true, false + ); + final String baseDir = context.getProjectFileDirectory(); + final String projectName = context.getProjectName(); + final String initialProjectName = projectName != null ? projectName : ProjectWizardUtil.findNonExistingFileName(baseDir, "untitled", ""); + component.setPath(projectName == null ? (baseDir + File.separator + initialProjectName) : baseDir); + component.setNameValue(initialProjectName); + component.getNameComponent().select(0, initialProjectName.length()); + return component; + } + private String getProjectFilePath(boolean isDefault) { if (isDefault) { return getPath() + "/" + getNameValue() + ProjectFileType.DOT_DEFAULT_EXTENSION; diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectWizardStepFactoryImpl.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectWizardStepFactoryImpl.java index 2674cd69ffdb..5397b3d47119 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectWizardStepFactoryImpl.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/ProjectWizardStepFactoryImpl.java @@ -16,7 +16,7 @@ package com.intellij.ide.util.projectWizard; import com.intellij.ide.util.frameworkSupport.FrameworkSupportUtil; -import com.intellij.ide.util.newProjectWizard.AddModuleWizard; +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; import com.intellij.ide.util.newProjectWizard.SourcePathsStep; import com.intellij.ide.util.newProjectWizard.SupportForFrameworksStep; import com.intellij.openapi.projectRoots.Sdk; @@ -114,7 +114,7 @@ public class ProjectWizardStepFactoryImpl extends ProjectWizardStepFactory { } projectSdkStep = new ProjectJdkStep(wizardContext) { public boolean isStepVisible() { - final Sdk newProjectJdk = AddModuleWizard.getProjectSdkByDefault(wizardContext); + final Sdk newProjectJdk = AbstractProjectWizard.getProjectSdkByDefault(wizardContext); if (newProjectJdk == null) return true; final ProjectBuilder projectBuilder = wizardContext.getProjectBuilder(); return projectBuilder != null && !projectBuilder.isSuitableSdk(newProjectJdk); @@ -127,7 +127,7 @@ public class ProjectWizardStepFactoryImpl extends ProjectWizardStepFactory { @Nullable @Override public Sdk getNewProjectSdk(WizardContext wizardContext) { - return AddModuleWizard.getNewProjectJdk(wizardContext); + return AbstractProjectWizard.getNewProjectJdk(wizardContext); } @Override diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandlerBase.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandlerBase.java index 806dd60fdde4..3c2b3a205fd5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandlerBase.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandlerBase.java @@ -16,10 +16,8 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.actionSystem.CustomShortcutSet; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsDummyElement; -import org.jetbrains.jps.model.JpsElementFactory; import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import javax.swing.*; @@ -49,10 +47,4 @@ public abstract class JavaResourceRootEditHandlerBase extends ModuleSourceRootEd public CustomShortcutSet getMarkRootShortcutSet() { return null; } - - @NotNull - @Override - public JpsDummyElement createDefaultProperties() { - return JpsElementFactory.getInstance().createDummyElement(); - } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java index 56ef125bfc09..a0a86e1504e7 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.roots.ui.configuration.actions; +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizardPro; import com.intellij.ide.util.projectWizard.ModuleBuilder; @@ -68,7 +69,7 @@ public class NewModuleAction extends AnAction implements DumbAware { } @Nullable - public Module createModuleFromWizard(Project project, @Nullable Object dataFromContext, AddModuleWizard wizard) { + public Module createModuleFromWizard(Project project, @Nullable Object dataFromContext, AbstractProjectWizard wizard) { final ProjectBuilder builder = wizard.getProjectBuilder(); if (builder instanceof ModuleBuilder) { final ModuleBuilder moduleBuilder = (ModuleBuilder)builder; diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactErrorPanel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactErrorPanel.java index 45e6a53084b8..4d0da3eb903c 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactErrorPanel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactErrorPanel.java @@ -91,9 +91,7 @@ public class ArtifactErrorPanel { if (myErrorLabel.isShowing()) { myErrorLabel.setText(errorText); } - else { - myErrorText = errorText; - } + myErrorText = errorText; myMainPanel.setVisible(true); myCurrentQuickFixes = quickFixes; myFixButton.setVisible(!quickFixes.isEmpty()); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java index 07634078cb5b..34bd02b84950 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java @@ -30,11 +30,15 @@ import com.intellij.openapi.roots.ui.configuration.PathUIUtils; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; +import com.intellij.util.IconUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; /** * @author nik @@ -108,7 +112,7 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen private static class AttachUrlJavadocDescriptor extends AttachRootButtonDescriptor { private AttachUrlJavadocDescriptor() { - super(JavadocOrderRootType.getInstance(), ProjectBundle.message("module.libraries.javadoc.url.button")); + super(JavadocOrderRootType.getInstance(), IconUtil.getAddLinkIcon(), ProjectBundle.message("module.libraries.javadoc.url.button")); } @Override diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java index 3afce2d2b9bd..f4c6db4c3f1f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java @@ -142,7 +142,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent myTreeBuilder = new LibraryTableTreeBuilder(myTree, (DefaultTreeModel)myTree.getModel(), treeStructure); myTreePanel.setLayout(new BorderLayout()); - ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTree).disableUpDownActions().disableAddAction() + ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTree).disableUpDownActions() .setRemoveActionName(ProjectBundle.message("library.detach.action")) .setRemoveAction(new AnActionButtonRunnable() { @Override @@ -173,29 +173,43 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent } }); + List<String> actionsOrder = new ArrayList<String>(); + actionsOrder.add("Add"); + final List<AttachRootButtonDescriptor> popupItems = new ArrayList<AttachRootButtonDescriptor>(); + for (AttachRootButtonDescriptor descriptor : myDescriptor.createAttachButtons()) { + Icon icon = descriptor.getToolbarIcon(); + if (icon != null) { + AttachItemAction action = new AttachItemAction(descriptor, descriptor.getButtonText(), icon); + toolbarDecorator.addExtraAction(AnActionButton.fromAction(action)); + actionsOrder.add(action.getTemplatePresentation().getText()); + } + else { + popupItems.add(descriptor); + } + } + actionsOrder.add("Remove"); + toolbarDecorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { - final AnAction[] children = getActions(); - if (children.length == 0) return; - final DefaultActionGroup actions = new DefaultActionGroup(children); - JBPopupFactory.getInstance().createActionGroupPopup(null, actions, - DataManager.getInstance().getDataContext(button.getContextComponent()), - JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, true) - .show(button.getPreferredPopupPoint()); - } + if (popupItems.isEmpty()) { + new AttachFilesAction(myDescriptor.getAttachFilesActionName()).actionPerformed(null); + return; + } - private AnAction[] getActions() { List<AnAction> actions = new ArrayList<AnAction>(); actions.add(new AttachFilesAction(myDescriptor.getAttachFilesActionName())); - for (AttachRootButtonDescriptor descriptor : myDescriptor.createAttachButtons()) { - actions.add(new AttachItemAction(descriptor, descriptor.getButtonText())); + for (AttachRootButtonDescriptor descriptor : popupItems) { + actions.add(new AttachItemAction(descriptor, descriptor.getButtonText(), null)); } - return actions.toArray(new AnAction[actions.size()]); + final DefaultActionGroup group = new DefaultActionGroup(actions); + JBPopupFactory.getInstance().createActionGroupPopup(null, group, + DataManager.getInstance().getDataContext(button.getContextComponent()), + JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, true) + .show(button.getPreferredPopupPoint()); } }); - - + toolbarDecorator.setButtonComparator(ArrayUtil.toStringArray(actionsOrder)); myTreePanel.add(toolbarDecorator.createPanel(), BorderLayout.CENTER); ToolbarDecorator.findRemoveButton(myTreePanel).addCustomUpdater(new AnActionButtonUpdater() { @@ -406,8 +420,9 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent private class AttachItemAction extends AttachItemActionBase { private final AttachRootButtonDescriptor myDescriptor; - protected AttachItemAction(AttachRootButtonDescriptor descriptor, String title) { + protected AttachItemAction(AttachRootButtonDescriptor descriptor, String title, final Icon icon) { super(title); + getTemplatePresentation().setIcon(icon); myDescriptor = descriptor; } @@ -472,23 +487,4 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent public void removeListener(Runnable listener) { myListeners.remove(listener); } - - @Nullable - private static Class<?> getElementsClass(Object[] elements) { - if (elements.length == 0) { - return null; - } - Class<?> cls = null; - for (Object element : elements) { - if (cls == null) { - cls = element.getClass(); - } - else { - if (!cls.equals(element.getClass())) { - return null; - } - } - } - return cls; - } } diff --git a/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java b/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java index 919f95239803..08c673fb1f55 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java +++ b/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java @@ -132,7 +132,7 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { for (String child : children) { if (child.endsWith(ZIP)) { URL templateUrl = new URL(url.first.toExternalForm() + "/" + child); - String name = child.substring(0, child.length() - ZIP.length()).replace('_', ' '); + String name = getTemplateName(child); templates.add(new LocalArchivedTemplate(name, templateUrl, url.second)); } } @@ -144,6 +144,10 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory { return templates.toArray(new ProjectTemplate[templates.size()]); } + public static String getTemplateName(String child) { + return child.substring(0, child.length() - ZIP.length()).replace('_', ' '); + } + @Override public int getGroupWeight(String group) { return CUSTOM_GROUP.equals(group) ? -2 : 0; diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 0aeb2bb8d1bd..cb34a20bd184 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -30,6 +30,7 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JavaVersionService; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.pom.java.LanguageLevel; @@ -37,6 +38,7 @@ import com.intellij.psi.*; import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; import com.intellij.psi.impl.source.resolve.JavaResolveUtil; +import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTagValue; @@ -311,16 +313,28 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(result); } else { - for (int i = 0; i < lambdaParameters.length; i++) { - PsiParameter lambdaParameter = lambdaParameters[i]; - if (!TypeConversionUtil.isAssignable(lambdaParameter.getType(), - GenericsUtil.eliminateWildcards( - LambdaUtil.getSubstitutor(interfaceMethod, resolveResult) - .substitute(parameters[i].getType())))) { - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(lambdaParameter) - .descriptionAndTooltip(incompatibleTypesMessage).create(); - myHolder.add(result); - break; + final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult); + if (expression.hasFormalParameterTypes()) { + for (int i = 0; i < lambdaParameters.length; i++) { + if (!Comparing.equal(lambdaParameters[i].getType(), substitutor.substitute(parameters[i].getType()))) { + HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(lambdaParameters[i]) + .descriptionAndTooltip(incompatibleTypesMessage) + .create(); + myHolder.add(result); + break; + } + } + } else { + for (int i = 0; i < lambdaParameters.length; i++) { + PsiParameter lambdaParameter = lambdaParameters[i]; + if (!TypeConversionUtil.isAssignable(lambdaParameter.getType(), + GenericsUtil.eliminateWildcards(substitutor.substitute(parameters[i].getType())))) { + HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(lambdaParameter) + .descriptionAndTooltip(incompatibleTypesMessage).create(); + myHolder.add(result); + break; + } } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java index 7a7478340a51..4554b15b9041 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/ExpressionTypeMemoryState.java @@ -58,14 +58,13 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl { super(factory); } - @Override - protected DfaMemoryStateImpl createNew() { - return new ExpressionTypeMemoryState(getFactory()); + private ExpressionTypeMemoryState(DfaMemoryStateImpl toCopy) { + super(toCopy); } @Override public DfaMemoryStateImpl createCopy() { - final ExpressionTypeMemoryState copy = (ExpressionTypeMemoryState)super.createCopy(); + final ExpressionTypeMemoryState copy = new ExpressionTypeMemoryState(this); copy.myStates.putAll(myStates); return copy; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 58bb1fc2cc1d..fed5b5b2e54a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -22,7 +22,6 @@ import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.*; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -100,24 +99,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { return JavaPsiFacade.getElementFactory(manager.getProject()).createTypeByFQClassName(fqn, scope); } - private boolean myRecursionStopper = false; - private <T extends Instruction> T addInstruction(T i) { - ProgressManager.checkCanceled(); - - if (!myRecursionStopper) { - myRecursionStopper = true; - try { - // add extra conditional goto in order to handle possible runtime exceptions that could be caught by finally block - if (i instanceof BranchingInstruction || i instanceof AssignInstruction || i instanceof MethodCallInstruction) { - addConditionalRuntimeThrow(); - } - } - finally { - myRecursionStopper = false; - } - } - myCurrentFlow.addInstruction(i); return i; } @@ -137,7 +119,10 @@ class ControlFlowAnalyzer extends JavaElementVisitor { private void finishElement(PsiElement element) { myCurrentFlow.finishElement(element); - assert element == myElementStack.pop(); + PsiElement popped = myElementStack.pop(); + if (element != popped) { + throw new AssertionError("Expected " + element + ", popped " + popped); + } } @Override @@ -146,64 +131,60 @@ class ControlFlowAnalyzer extends JavaElementVisitor { } @Override public void visitAssignmentExpression(PsiAssignmentExpression expression) { + PsiExpression lExpr = expression.getLExpression(); + PsiExpression rExpr = expression.getRExpression(); + startElement(expression); + if (rExpr == null) { + pushUnknown(); + finishElement(expression); + return; + } - try { - PsiExpression lExpr = expression.getLExpression(); - PsiExpression rExpr = expression.getRExpression(); + lExpr.accept(this); - if (rExpr == null) { - pushUnknown(); - return; + IElementType op = expression.getOperationTokenType(); + PsiType type = expression.getType(); + boolean isBoolean = PsiType.BOOLEAN.equals(type); + if (op == JavaTokenType.EQ) { + rExpr.accept(this); + generateBoxingUnboxingInstructionFor(rExpr, type); + } + else if (op == JavaTokenType.ANDEQ) { + if (isBoolean) { + generateNonLazyExpression(true, lExpr, rExpr, type); } - - lExpr.accept(this); - - IElementType op = expression.getOperationTokenType(); - PsiType type = expression.getType(); - boolean isBoolean = PsiType.BOOLEAN.equals(type); - if (op == JavaTokenType.EQ) { - rExpr.accept(this); - generateBoxingUnboxingInstructionFor(rExpr, type); - } - else if (op == JavaTokenType.ANDEQ) { - if (isBoolean) { - generateNonLazyExpression(true, lExpr, rExpr, type); - } - else { - generateDefaultBinOp(lExpr, rExpr, type); - } + else { + generateDefaultBinOp(lExpr, rExpr, type); } - else if (op == JavaTokenType.OREQ) { - if (isBoolean) { - generateNonLazyExpression(false, lExpr, rExpr, type); - } - else { - generateDefaultBinOp(lExpr, rExpr, type); - } + } + else if (op == JavaTokenType.OREQ) { + if (isBoolean) { + generateNonLazyExpression(false, lExpr, rExpr, type); } - else if (op == JavaTokenType.XOREQ) { - if (isBoolean) { - generateXorExpression(expression, new PsiExpression[]{lExpr, rExpr}, type); - } - else { - generateDefaultBinOp(lExpr, rExpr, type); - } + else { + generateDefaultBinOp(lExpr, rExpr, type); } - else if (op == JavaTokenType.PLUSEQ && type != null && type.equalsToText(JAVA_LANG_STRING)) { - lExpr.accept(this); - rExpr.accept(this); - addInstruction(new BinopInstruction(JavaTokenType.PLUS, null, lExpr.getProject())); + } + else if (op == JavaTokenType.XOREQ) { + if (isBoolean) { + generateXorExpression(expression, new PsiExpression[]{lExpr, rExpr}, type); } else { generateDefaultBinOp(lExpr, rExpr, type); } - - addInstruction(new AssignInstruction(rExpr)); } - finally { - finishElement(expression); + else if (op == JavaTokenType.PLUSEQ && type != null && type.equalsToText(JAVA_LANG_STRING)) { + lExpr.accept(this); + rExpr.accept(this); + addInstruction(new BinopInstruction(JavaTokenType.PLUS, null, lExpr.getProject())); } + else { + generateDefaultBinOp(lExpr, rExpr, type); + } + + addInstruction(new AssignInstruction(rExpr)); + finishElement(expression); } private void generateDefaultBinOp(PsiExpression lExpr, PsiExpression rExpr, final PsiType exprType) { @@ -658,11 +639,13 @@ class ControlFlowAnalyzer extends JavaElementVisitor { if (exception != null) { exception.accept(this); + addConditionalRuntimeThrow(); addInstruction(new DupInstruction()); addInstruction(new PushInstruction(myFactory.getConstFactory().getNull(), null)); addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, statement.getProject())); ConditionalGotoInstruction gotoInstruction = new ConditionalGotoInstruction(null, true, null); addInstruction(gotoInstruction); + addInstruction(new PushInstruction(myFactory.createTypeValue(myNpe, Nullness.NOT_NULL), null)); addThrowCode(myNpe); gotoInstruction.setOffset(myCurrentFlow.getInstructionCount()); addThrowCode(exception.getType()); @@ -1008,42 +991,40 @@ class ControlFlowAnalyzer extends JavaElementVisitor { public void visitPolyadicExpression(PsiPolyadicExpression expression) { startElement(expression); - try { - DfaValue dfaValue = myFactory.createValue(expression); - if (dfaValue != null) { - addInstruction(new PushInstruction(dfaValue, expression)); - return; - } - IElementType op = expression.getOperationTokenType(); - - PsiExpression[] operands = expression.getOperands(); - if (operands.length <= 1) { - pushUnknown(); - return; - } - PsiType type = expression.getType(); - if (op == JavaTokenType.ANDAND) { - generateAndExpression(operands, type, true); - } - else if (op == JavaTokenType.OROR) { - generateOrExpression(operands, type, true); - } - else if (op == JavaTokenType.XOR && PsiType.BOOLEAN.equals(type)) { - generateXorExpression(expression, operands, type); - } - else if (op == JavaTokenType.AND && PsiType.BOOLEAN.equals(type)) { - generateAndExpression(operands, type, false); - } - else if (op == JavaTokenType.OR && PsiType.BOOLEAN.equals(type)) { - generateOrExpression(operands, type, false); - } - else { - generateOther(expression, op, operands, type); - } + DfaValue dfaValue = myFactory.createValue(expression); + if (dfaValue != null) { + addInstruction(new PushInstruction(dfaValue, expression)); + finishElement(expression); + return; } - finally { + IElementType op = expression.getOperationTokenType(); + + PsiExpression[] operands = expression.getOperands(); + if (operands.length <= 1) { + pushUnknown(); finishElement(expression); + return; } + PsiType type = expression.getType(); + if (op == JavaTokenType.ANDAND) { + generateAndExpression(operands, type, true); + } + else if (op == JavaTokenType.OROR) { + generateOrExpression(operands, type, true); + } + else if (op == JavaTokenType.XOR && PsiType.BOOLEAN.equals(type)) { + generateXorExpression(expression, operands, type); + } + else if (op == JavaTokenType.AND && PsiType.BOOLEAN.equals(type)) { + generateAndExpression(operands, type, false); + } + else if (op == JavaTokenType.OR && PsiType.BOOLEAN.equals(type)) { + generateOrExpression(operands, type, false); + } + else { + generateOther(expression, op, operands, type); + } + finishElement(expression); } private void generateOther(PsiPolyadicExpression expression, IElementType op, PsiExpression[] operands, PsiType type) { @@ -1106,6 +1087,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { addInstruction(new MethodCallInstruction(expression, MethodCallInstruction.MethodType.UNBOXING, expectedType)); } else if (TypeConversionUtil.isAssignableFromPrimitiveWrapper(expectedType) && TypeConversionUtil.isPrimitiveAndNotNull(exprType)) { + addConditionalRuntimeThrow(); addInstruction(new MethodCallInstruction(expression, MethodCallInstruction.MethodType.BOXING, expectedType)); } else if (exprType != expectedType && @@ -1275,7 +1257,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { if (type instanceof PsiClassType) { type = ((PsiClassType)type).rawType(); } - addInstruction(new PushInstruction(myFactory.getTypeFactory().createTypeValue(type), null)); + addInstruction(new PushInstruction(myFactory.createTypeValue(type, Nullness.UNKNOWN), null)); addInstruction(new InstanceofInstruction(expression, expression.getProject(), operand, type)); } else { @@ -1301,58 +1283,56 @@ class ControlFlowAnalyzer extends JavaElementVisitor { } @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) { - try { - startElement(expression); + startElement(expression); - if (handleContracts(expression, getCallContracts(expression))) { - return; - } + if (handleContracts(expression, getCallContracts(expression))) { + finishElement(expression); + return; + } - PsiReferenceExpression methodExpression = expression.getMethodExpression(); - PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); + PsiReferenceExpression methodExpression = expression.getMethodExpression(); + PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); - if (qualifierExpression != null) { - qualifierExpression.accept(this); - } - else { - pushUnknown(); - } + if (qualifierExpression != null) { + qualifierExpression.accept(this); + } + else { + pushUnknown(); + } - PsiExpression[] expressions = expression.getArgumentList().getExpressions(); - PsiElement method = methodExpression.resolve(); - PsiParameter[] parameters = method instanceof PsiMethod ? ((PsiMethod)method).getParameterList().getParameters() : null; - for (int i = 0; i < expressions.length; i++) { - PsiExpression paramExpr = expressions[i]; - paramExpr.accept(this); - if (parameters != null && i < parameters.length) { - generateBoxingUnboxingInstructionFor(paramExpr, parameters[i].getType()); - } + PsiExpression[] expressions = expression.getArgumentList().getExpressions(); + PsiElement method = methodExpression.resolve(); + PsiParameter[] parameters = method instanceof PsiMethod ? ((PsiMethod)method).getParameterList().getParameters() : null; + for (int i = 0; i < expressions.length; i++) { + PsiExpression paramExpr = expressions[i]; + paramExpr.accept(this); + if (parameters != null && i < parameters.length) { + generateBoxingUnboxingInstructionFor(paramExpr, parameters[i].getType()); } + } - addInstruction(new MethodCallInstruction(expression, createChainedVariableValue(expression))); + addConditionalRuntimeThrow(); + addInstruction(new MethodCallInstruction(expression, createChainedVariableValue(expression))); - if (!myCatchStack.isEmpty()) { - addMethodThrows(expression.resolveMethod()); - } + if (!myCatchStack.isEmpty()) { + addMethodThrows(expression.resolveMethod()); + } - if (expressions.length == 1 && method instanceof PsiMethod && - "equals".equals(((PsiMethod)method).getName()) && parameters.length == 1 && - parameters[0].getType().equalsToText(JAVA_LANG_OBJECT) && - PsiType.BOOLEAN.equals(((PsiMethod)method).getReturnType())) { - addInstruction(new PushInstruction(myFactory.getConstFactory().getFalse(), null)); - addInstruction(new SwapInstruction()); - addInstruction(new ConditionalGotoInstruction(getEndOffset(expression), true, null)); + if (expressions.length == 1 && method instanceof PsiMethod && + "equals".equals(((PsiMethod)method).getName()) && parameters.length == 1 && + parameters[0].getType().equalsToText(JAVA_LANG_OBJECT) && + PsiType.BOOLEAN.equals(((PsiMethod)method).getReturnType())) { + addInstruction(new PushInstruction(myFactory.getConstFactory().getFalse(), null)); + addInstruction(new SwapInstruction()); + addInstruction(new ConditionalGotoInstruction(getEndOffset(expression), true, null)); - addInstruction(new PopInstruction()); - addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null)); + addInstruction(new PopInstruction()); + addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null)); - expressions[0].accept(this); - addInstruction(new ApplyNotNullInstruction(expression)); - } - } - finally { - finishElement(expression); + expressions[0].accept(this); + addInstruction(new ApplyNotNullInstruction(expression)); } + finishElement(expression); } private boolean handleContracts(PsiMethodCallExpression expression, List<MethodContract> _contracts) { @@ -1527,9 +1507,9 @@ class ControlFlowAnalyzer extends JavaElementVisitor { if (type == ASSERT_IS_NULL_METHOD || type == ASSERT_IS_NOT_NULL_METHOD) { constraints[checkedParam] = type == ASSERT_IS_NOT_NULL_METHOD ? ValueConstraint.NULL_VALUE : ValueConstraint.NOT_NULL_VALUE; return Collections.singletonList(new MethodContract(constraints, ValueConstraint.THROW_EXCEPTION)); - } else if (type == IS_NULL_METHOD || type == IS_NOT_NULL_METHOD) { - constraints[checkedParam] = type == IS_NULL_METHOD ? ValueConstraint.NOT_NULL_VALUE : ValueConstraint.NULL_VALUE; - return Collections.singletonList(new MethodContract(constraints, ValueConstraint.FALSE_VALUE)); + } else if (type == IS_NOT_NULL_METHOD || type == IS_NULL_METHOD) { + constraints[checkedParam] = ValueConstraint.NULL_VALUE; + return Collections.singletonList(new MethodContract(constraints, type == IS_NULL_METHOD ? ValueConstraint.TRUE_VALUE : ValueConstraint.FALSE_VALUE)); } else { //assertTrue or assertFalse constraints[checkedParam] = type == ASSERT_FALSE_METHOD ? ValueConstraint.TRUE_VALUE : ValueConstraint.FALSE_VALUE; return Collections.singletonList(new MethodContract(constraints, ValueConstraint.THROW_EXCEPTION)); @@ -1594,7 +1574,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { final DfaValue dfaValue; if (type instanceof PsiClassType) { - dfaValue = myFactory.getTypeFactory().createTypeValue(type); + dfaValue = myFactory.createTypeValue(type, Nullness.UNKNOWN); } else { dfaValue = null; @@ -1623,6 +1603,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { addInstruction(new PopInstruction()); } } + addConditionalRuntimeThrow(); addInstruction(new MethodCallInstruction(expression, null)); } else { @@ -1640,6 +1621,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { } } + addConditionalRuntimeThrow(); addInstruction(new MethodCallInstruction(expression, null)); if (!myCatchStack.isEmpty()) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index bbac522a4c5a..b462090126a2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -33,8 +33,10 @@ import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix; import com.intellij.codeInspection.*; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; @@ -47,6 +49,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtilRt; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -145,7 +148,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { PsiClass containingClass = PsiTreeUtil.getParentOfType(scope, PsiClass.class); if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass)) return; - final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(SUGGEST_NULLABLE_ANNOTATIONS) { + final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner() { @Override protected boolean shouldCheckTimeLimit() { if (!onTheFly) return false; @@ -159,7 +162,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { ProblemsHolder holder, StandardDataFlowRunner dfaRunner, Collection<DfaMemoryState> initialStates) { - final StandardInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner); + final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner); final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor, IGNORE_ASSERT_STATEMENTS, initialStates); if (rc == RunnerResult.OK) { createDescription(dfaRunner, holder, visitor); @@ -213,7 +216,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { protected void addSurroundWithIfFix(PsiExpression qualifier, List<LocalQuickFix> fixes) { } - private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, StandardInstructionVisitor visitor) { + private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, DataFlowInstructionVisitor visitor) { Pair<Set<Instruction>, Set<Instruction>> constConditions = runner.getConstConditionalExpressions(); Set<Instruction> trueSet = constConditions.getFirst(); Set<Instruction> falseSet = constConditions.getSecond(); @@ -221,28 +224,25 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { ArrayList<Instruction> allProblems = new ArrayList<Instruction>(); allProblems.addAll(trueSet); allProblems.addAll(falseSet); - allProblems.addAll(runner.getNPEInstructions()); allProblems.addAll(runner.getCCEInstructions()); allProblems.addAll(StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor)); - Collections.sort(allProblems, new Comparator<Instruction>() { - @Override - public int compare(Instruction i1, Instruction i2) { - return i1.getIndex() - i2.getIndex(); - } - }); - HashSet<PsiElement> reportedAnchors = new HashSet<PsiElement>(); - - for (Instruction instruction : allProblems) { - if (instruction instanceof MethodCallInstruction) { - reportCallMayProduceNpe(holder, (MethodCallInstruction)instruction, reportedAnchors); + for (PsiElement element : visitor.getProblems(NullabilityProblem.callNPE)) { + if (reportedAnchors.add(element)) { + reportCallMayProduceNpe(holder, (PsiMethodCallExpression)element); } - else if (instruction instanceof FieldReferenceInstruction && - reportedAnchors.add(((FieldReferenceInstruction)instruction).getElementToAssert())) { - reportFieldAccessMayProduceNpe(holder, (FieldReferenceInstruction)instruction); + } + for (PsiElement element : visitor.getProblems(NullabilityProblem.fieldAccessNPE)) { + if (reportedAnchors.add(element)) { + PsiElement parent = element.getParent(); + PsiElement fieldAccess = parent instanceof PsiArrayAccessExpression || parent instanceof PsiReferenceExpression ? parent : element; + reportFieldAccessMayProduceNpe(holder, element, (PsiExpression)fieldAccess); } - else if (instruction instanceof TypeCastInstruction && + } + + for (Instruction instruction : allProblems) { + if (instruction instanceof TypeCastInstruction && reportedAnchors.add(((TypeCastInstruction)instruction).getCastExpression().getCastType())) { reportCastMayFail(holder, (TypeCastInstruction)instruction); } @@ -251,11 +251,15 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { } } - reportNullableArguments(runner, holder, reportedAnchors); - reportNullableAssignments(runner, holder, reportedAnchors); - reportUnboxedNullables(runner, holder, reportedAnchors); - reportNullableReturns(runner, holder, reportedAnchors); - reportNullableArgumentsPassedToNonAnnotated(runner, holder, reportedAnchors); + reportNullableArguments(visitor, holder, reportedAnchors); + reportNullableAssignments(visitor, holder, reportedAnchors); + reportUnboxedNullables(visitor, holder, reportedAnchors); + if (!runner.isInNullableMethod() && runner.isInMethod() && (runner.isInNotNullMethod() || SUGGEST_NULLABLE_ANNOTATIONS)) { + reportNullableReturns(runner, visitor, holder, reportedAnchors); + } + if (SUGGEST_NULLABLE_ANNOTATIONS) { + reportNullableArgumentsPassedToNonAnnotated(visitor, holder, reportedAnchors); + } if (REPORT_CONSTANT_REFERENCE_VALUES) { reportConstantReferenceValues(holder, visitor, reportedAnchors); @@ -317,15 +321,14 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { return value instanceof String ? "\"" + StringUtil.escapeStringCharacters((String)value) + "\"" : String.valueOf(value); } - private void reportNullableArgumentsPassedToNonAnnotated(StandardDataFlowRunner runner, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { - Set<PsiExpression> exprs = runner.getNullableArgumentsPassedToNonAnnotatedParam(); - for (PsiExpression expr : exprs) { + private void reportNullableArgumentsPassedToNonAnnotated(DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { + for (PsiElement expr : visitor.getProblems(NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter)) { if (reportedAnchors.contains(expr)) continue; final String text = isNullLiteralExpression(expr) ? "Passing <code>null</code> argument to non annotated parameter" : "Argument <code>#ref</code> #loc might be null but passed to non annotated parameter"; - LocalQuickFix[] fixes = createNPEFixes(expr, expr); + LocalQuickFix[] fixes = createNPEFixes((PsiExpression)expr, (PsiExpression)expr); final PsiElement parent = expr.getParent(); if (parent instanceof PsiExpressionList) { final int idx = ArrayUtilRt.find(((PsiExpressionList)parent).getExpressions(), expr); @@ -349,22 +352,15 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { } } - private void reportCallMayProduceNpe(ProblemsHolder holder, MethodCallInstruction mcInstruction, Set<PsiElement> reportedAnchors) { - if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) { - PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression(); - if (!reportedAnchors.add(callExpression)) return; - - LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression); + private void reportCallMayProduceNpe(ProblemsHolder holder, PsiMethodCallExpression callExpression) { + LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression); - holder.registerProblem(callExpression, - InspectionsBundle.message("dataflow.message.npe.method.invocation"), - fix); - } + holder.registerProblem(callExpression, + InspectionsBundle.message("dataflow.message.npe.method.invocation"), + fix); } - private void reportFieldAccessMayProduceNpe(ProblemsHolder holder, FieldReferenceInstruction frInstruction) { - PsiElement elementToAssert = frInstruction.getElementToAssert(); - PsiExpression expression = frInstruction.getExpression(); + private void reportFieldAccessMayProduceNpe(ProblemsHolder holder, PsiElement elementToAssert, PsiExpression expression) { if (expression instanceof PsiArrayAccessExpression) { LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression); holder.registerProblem(expression, @@ -382,8 +378,11 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { private static void reportCastMayFail(ProblemsHolder holder, TypeCastInstruction instruction) { PsiTypeCastExpression typeCast = instruction.getCastExpression(); - holder.registerProblem(typeCast.getCastType(), - InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText())); + PsiExpression operand = typeCast.getOperand(); + PsiTypeElement castType = typeCast.getCastType(); + assert castType != null; + assert operand != null; + holder.registerProblem(castType, InspectionsBundle.message("dataflow.message.cce", operand.getText())); } private void handleBranchingInstruction(ProblemsHolder holder, @@ -413,7 +412,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { } else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) { boolean evaluatesToTrue = trueSet.contains(instruction); - if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) { + if (onTheLeftSideOfConditionalAssignment(psiAnchor)) { holder.registerProblem( psiAnchor, InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)), @@ -436,21 +435,20 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { visitor.silenceConstantCondition(psiAnchor); } - private void reportNullableArguments(StandardDataFlowRunner runner, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { - Set<PsiExpression> exprs = runner.getNullableArguments(); - for (PsiExpression expr : exprs) { + private void reportNullableArguments(DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { + for (PsiElement expr : visitor.getProblems(NullabilityProblem.passingNullableToNotNullParameter)) { if (!reportedAnchors.add(expr)) continue; final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message("dataflow.message.passing.null.argument") : InspectionsBundle.message("dataflow.message.passing.nullable.argument"); - LocalQuickFix[] fixes = createNPEFixes(expr, expr); + LocalQuickFix[] fixes = createNPEFixes((PsiExpression)expr, (PsiExpression)expr); holder.registerProblem(expr, text, fixes); } } - private static void reportNullableAssignments(StandardDataFlowRunner runner, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { - for (PsiExpression expr : runner.getNullableAssignments()) { + private static void reportNullableAssignments(DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { + for (PsiElement expr : visitor.getProblems(NullabilityProblem.assigningToNotNull)) { if (!reportedAnchors.add(expr)) continue; final String text = isNullLiteralExpression(expr) @@ -460,16 +458,16 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { } } - private static void reportUnboxedNullables(StandardDataFlowRunner runner, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { - for (PsiExpression expr : runner.getUnboxedNullables()) { + private static void reportUnboxedNullables(DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { + for (PsiElement expr : visitor.getProblems(NullabilityProblem.unboxingNullable)) { if (!reportedAnchors.add(expr)) continue; holder.registerProblem(expr, InspectionsBundle.message("dataflow.message.unboxing")); } } - private static void reportNullableReturns(StandardDataFlowRunner runner, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { - for (PsiReturnStatement statement : runner.getNullableReturns()) { - final PsiExpression expr = statement.getReturnValue(); + private static void reportNullableReturns(StandardDataFlowRunner runner, DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { + for (PsiElement statement : visitor.getProblems(NullabilityProblem.nullableReturn)) { + final PsiExpression expr = ((PsiReturnStatement)statement).getReturnValue(); assert expr != null; if (!reportedAnchors.add(expr)) continue; @@ -547,7 +545,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { return parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getCondition() == element; } - private static boolean isNullLiteralExpression(PsiExpression expr) { + private static boolean isNullLiteralExpression(PsiElement expr) { if (expr instanceof PsiLiteralExpression) { final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expr; return PsiType.NULL.equals(literalExpression.getType()); @@ -555,7 +553,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { return false; } - private static boolean onTheLeftSideOfConditionalAssignemnt(final PsiElement psiAnchor) { + private static boolean onTheLeftSideOfConditionalAssignment(final PsiElement psiAnchor) { final PsiElement parent = psiAnchor.getParent(); if (parent instanceof PsiAssignmentExpression) { final PsiAssignmentExpression expression = (PsiAssignmentExpression)parent; @@ -699,45 +697,55 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { private static class DataFlowInstructionVisitor extends StandardInstructionVisitor { private final StandardDataFlowRunner myRunner; + private final MultiMap<NullabilityProblem, PsiElement> myProblems = new MultiMap<NullabilityProblem, PsiElement>(); + private final Map<Pair<NullabilityProblem, PsiElement>, StateInfo> myStateInfos = ContainerUtil.newHashMap(); private DataFlowInstructionVisitor(StandardDataFlowRunner runner) { myRunner = runner; } @Override - protected void onAssigningToNotNullableVariable(AssignInstruction instruction) { - myRunner.onAssigningToNotNullableVariable(instruction.getRExpression()); - } - - @Override - protected void onNullableReturn(CheckReturnValueInstruction instruction) { - myRunner.onNullableReturn(instruction.getReturn()); - } - - @Override protected void onInstructionProducesCCE(TypeCastInstruction instruction) { myRunner.onInstructionProducesCCE(instruction); } - - @Override - protected void onInstructionProducesNPE(Instruction instruction) { - if (instruction instanceof MethodCallInstruction && - ((MethodCallInstruction)instruction).getMethodType() == MethodCallInstruction.MethodType.UNBOXING) { - myRunner.onUnboxingNullable(((MethodCallInstruction)instruction).getContext()); - } - else { - myRunner.onInstructionProducesNPE(instruction); - } - } - - @Override - protected void onPassingNullParameter(PsiExpression arg) { - myRunner.onPassingNullParameter(arg); + + Collection<PsiElement> getProblems(final NullabilityProblem kind) { + return ContainerUtil.filter(myProblems.get(kind), new Condition<PsiElement>() { + @Override + public boolean value(PsiElement psiElement) { + StateInfo info = myStateInfos.get(Pair.create(kind, psiElement)); + // non-ephemeral NPE should be reported + // ephemeral NPE should also be reported if only ephemeral states have reached a particular problematic instruction + // (e.g. if it's inside "if (var == null)" check after contract method invocation + return info.normalNpe || info.ephemeralNpe && !info.normalOk; + } + }); } @Override - protected void onPassingNullParameterToNonAnnotated(DataFlowRunner runner, PsiExpression arg) { - myRunner.onPassingNullParameterToNonAnnotated(arg); + protected boolean checkNotNullable(DfaMemoryState state, DfaValue value, NullabilityProblem problem, PsiElement anchor) { + boolean ok = super.checkNotNullable(state, value, problem, anchor); + if (!ok && anchor != null) { + myProblems.putValue(problem, anchor); + } + Pair<NullabilityProblem, PsiElement> key = Pair.create(problem, anchor); + StateInfo info = myStateInfos.get(key); + if (info == null) { + myStateInfos.put(key, info = new StateInfo()); + } + if (state.isEphemeral() && !ok) { + info.ephemeralNpe = true; + } else if (!state.isEphemeral()) { + if (ok) info.normalOk = true; + else info.normalNpe = true; + } + return ok; + } + + private static class StateInfo { + boolean ephemeralNpe; + boolean normalNpe; + boolean normalOk; } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index 298b51bc4a24..38c242bc8e2a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -24,10 +24,7 @@ */ package com.intellij.codeInspection.dataFlow; -import com.intellij.codeInspection.dataFlow.instructions.BranchingInstruction; -import com.intellij.codeInspection.dataFlow.instructions.EmptyInstruction; -import com.intellij.codeInspection.dataFlow.instructions.Instruction; -import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction; +import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.openapi.application.ApplicationManager; @@ -38,7 +35,9 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.MultiMapBasedOnSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -108,6 +107,17 @@ public class DataFlowRunner { myInstructions = flow.getInstructions(); myFields = flow.getFields(); myNestedClosures.clear(); + + Set<Instruction> joinInstructions = ContainerUtil.newHashSet(); + for (Instruction instruction : myInstructions) { + if (instruction instanceof GotoInstruction) { + joinInstructions.add(myInstructions[((GotoInstruction)instruction).getOffset()]); + } else if (instruction instanceof ConditionalGotoInstruction) { + joinInstructions.add(myInstructions[((ConditionalGotoInstruction)instruction).getOffset()]); + } else if (instruction instanceof GosubInstruction) { + joinInstructions.add(myInstructions[((GosubInstruction)instruction).getSubprogramOffset()]); + } + } if (LOG.isDebugEnabled()) { LOG.debug("Analyzing code block: " + psiBlock.getText()); @@ -123,47 +133,61 @@ public class DataFlowRunner { return RunnerResult.TOO_COMPLEX; } - final ArrayList<DfaInstructionState> queue = new ArrayList<DfaInstructionState>(); + final StateQueue queue = new StateQueue(); for (final DfaMemoryState initialState : initialStates) { - queue.add(new DfaInstructionState(myInstructions[0], initialState)); + queue.offer(new DfaInstructionState(myInstructions[0], initialState)); } + MultiMapBasedOnSet<BranchingInstruction, DfaMemoryState> processedStates = new MultiMapBasedOnSet<BranchingInstruction, DfaMemoryState>(); + MultiMapBasedOnSet<BranchingInstruction, DfaMemoryState> incomingStates = new MultiMapBasedOnSet<BranchingInstruction, DfaMemoryState>(); + WorkingTimeMeasurer measurer = new WorkingTimeMeasurer(shouldCheckTimeLimit() ? ourTimeLimit : ourTimeLimit * 42); int count = 0; while (!queue.isEmpty()) { - if (count % 64 == 0 && measurer.isTimeOver()) { - LOG.debug("Too complex because the analysis took too long"); - psiBlock.putUserData(TOO_EXPENSIVE_HASH, psiBlock.getText().hashCode()); - return RunnerResult.TOO_COMPLEX; - } - ProgressManager.checkCanceled(); - - DfaInstructionState instructionState = queue.remove(0); - if (LOG.isDebugEnabled()) { - LOG.debug(instructionState.toString()); - } - //System.out.println(instructionState.toString()); - - Instruction instruction = instructionState.getInstruction(); - long distance = instructionState.getDistanceFromStart(); + for (DfaInstructionState instructionState : queue.getNextInstructionStates(joinInstructions)) { + if (count++ % 1024 == 0 && measurer.isTimeOver()) { + LOG.debug("Too complex because the analysis took too long"); + psiBlock.putUserData(TOO_EXPENSIVE_HASH, psiBlock.getText().hashCode()); + return RunnerResult.TOO_COMPLEX; + } + ProgressManager.checkCanceled(); - if (instruction instanceof BranchingInstruction) { - if (!instruction.setMemoryStateProcessed(instructionState.getMemoryState().createCopy())) { - LOG.debug("Too complex because too many different possible states"); - return RunnerResult.TOO_COMPLEX; // Too complex :( + if (LOG.isDebugEnabled()) { + LOG.debug(instructionState.toString()); + } + //System.out.println(instructionState.toString()); + + Instruction instruction = instructionState.getInstruction(); + + if (instruction instanceof BranchingInstruction) { + BranchingInstruction branching = (BranchingInstruction)instruction; + if (processedStates.get(branching).contains(instructionState.getMemoryState())) { + continue; + } + if (processedStates.get(branching).size() > MAX_STATES_PER_BRANCH) { + LOG.debug("Too complex because too many different possible states"); + return RunnerResult.TOO_COMPLEX; // Too complex :( + } + processedStates.putValue(branching, instructionState.getMemoryState().createCopy()); } - } - DfaInstructionState[] after = acceptInstruction(visitor, instructionState); - for (DfaInstructionState state : after) { - Instruction nextInstruction = state.getInstruction(); - if ((!(nextInstruction instanceof BranchingInstruction) || !nextInstruction.isMemoryStateProcessed(state.getMemoryState())) && instruction.getIndex() < endOffset) { - state.setDistanceFromStart(distance + 1); - queue.add(state); + DfaInstructionState[] after = acceptInstruction(visitor, instructionState); + for (DfaInstructionState state : after) { + Instruction nextInstruction = state.getInstruction(); + if (nextInstruction.getIndex() >= endOffset) { + continue; + } + if (nextInstruction instanceof BranchingInstruction) { + BranchingInstruction branching = (BranchingInstruction)nextInstruction; + if (processedStates.get(branching).contains(state.getMemoryState()) || + incomingStates.get(branching).contains(state.getMemoryState())) { + continue; + } + incomingStates.putValue(branching, state.getMemoryState().createCopy()); + } + queue.offer(state); } } - - count++; } psiBlock.putUserData(TOO_EXPENSIVE_HASH, null); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java index 87d8b8a1da50..1683807450ab 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java @@ -25,23 +25,26 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.instructions.Instruction; +import com.intellij.openapi.util.Pair; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -public class DfaInstructionState { +import java.util.Collections; +import java.util.List; +import java.util.PriorityQueue; +import java.util.Set; + +public class DfaInstructionState implements Comparable<DfaInstructionState> { public static final DfaInstructionState[] EMPTY_ARRAY = new DfaInstructionState[0]; private final DfaMemoryState myBeforeMemoryState; private final Instruction myInstruction; - private long myDistanceFromStart = 0; public DfaInstructionState(@NotNull Instruction myInstruction, @NotNull DfaMemoryState myBeforeMemoryState) { this.myBeforeMemoryState = myBeforeMemoryState; this.myInstruction = myInstruction; } - public long getDistanceFromStart() { return myDistanceFromStart; } - - public void setDistanceFromStart(long distanceFromStart) { myDistanceFromStart = distanceFromStart; } - @NotNull public Instruction getInstruction() { return myInstruction; @@ -55,4 +58,58 @@ public class DfaInstructionState { public String toString() { return getInstruction().getIndex() + " " + getInstruction() + ": " + getMemoryState().toString(); } + + @Override + public int compareTo(@NotNull DfaInstructionState o) { + return myInstruction.getIndex() - o.myInstruction.getIndex(); + } } + +class StateQueue { + private final PriorityQueue<DfaInstructionState> myQueue = new PriorityQueue<DfaInstructionState>(); + private final Set<Pair<Instruction, DfaMemoryState>> mySet = ContainerUtil.newHashSet(); + + void offer(DfaInstructionState state) { + if (mySet.add(Pair.create(state.getInstruction(), state.getMemoryState()))) { + myQueue.offer(state); + } + } + + boolean isEmpty() { + return myQueue.isEmpty(); + } + + List<DfaInstructionState> getNextInstructionStates(Set<Instruction> joinInstructions) { + DfaInstructionState state = myQueue.poll(); + final Instruction instruction = state.getInstruction(); + mySet.remove(Pair.create(instruction, state.getMemoryState())); + + DfaInstructionState next = myQueue.peek(); + if (next == null || next.compareTo(state) != 0) return Collections.singletonList(state); + + List<DfaMemoryStateImpl> memoryStates = ContainerUtil.newArrayList(); + memoryStates.add((DfaMemoryStateImpl)state.getMemoryState()); + while (!myQueue.isEmpty() && myQueue.peek().compareTo(state) == 0) { + DfaMemoryState anotherState = myQueue.poll().getMemoryState(); + mySet.remove(Pair.create(instruction, anotherState)); + memoryStates.add((DfaMemoryStateImpl)anotherState); + } + + if (memoryStates.size() > 1 && joinInstructions.contains(instruction)) { + while (true) { + List<DfaMemoryStateImpl> nextStates = new StateMerger(memoryStates).merge(); + if (nextStates == null) break; + memoryStates = nextStates; + } + } + + return ContainerUtil.map(memoryStates, new Function<DfaMemoryStateImpl, DfaInstructionState>() { + @Override + public DfaInstructionState fun(DfaMemoryStateImpl state) { + return new DfaInstructionState(instruction, state); + } + }); + } + + +}
\ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index 8309670020ab..106267affda4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -59,4 +59,13 @@ public interface DfaMemoryState { @Nullable DfaConstValue getConstantValue(DfaVariableValue value); + + /** + * Ephemeral means a state that was created when considering a method contract and checking if one of its arguments is null. + * With explicit null check, that would result in any non-annotated variable being treated as nullable and producing possible NPE warnings later. + * With contracts, we don't want this. So the state where this variable is null is marked ephemeral and no NPE warnings are issued for such states. + */ + void markEphemeral(); + + boolean isEphemeral(); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index d77a0f985985..f5430d5fd713 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -26,6 +26,7 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.value.*; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.UnorderedPair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.TypeConversionUtil; @@ -41,43 +42,50 @@ import java.util.*; public class DfaMemoryStateImpl implements DfaMemoryState { private final DfaValueFactory myFactory; - private final List<SortedIntSet> myEqClasses = new ArrayList<SortedIntSet>(); - private final Stack<DfaValue> myStack = new Stack<DfaValue>(); - private TIntStack myOffsetStack = new TIntStack(1); - private final TLongHashSet myDistinctClasses = new TLongHashSet(); - private final THashMap<DfaVariableValue,DfaVariableState> myVariableStates = new THashMap<DfaVariableValue, DfaVariableState>(); - private final THashSet<DfaVariableValue> myUnknownVariables = new THashSet<DfaVariableValue>(); + private final List<EqClass> myEqClasses; + private final Stack<DfaValue> myStack; + private TIntStack myOffsetStack; + private final TLongHashSet myDistinctClasses; + private final Map<DfaVariableValue,DfaVariableState> myVariableStates; + private final Map<DfaVariableValue,DfaVariableState> myDefaultVariableStates; + private final Set<DfaVariableValue> myUnknownVariables; + private boolean myEphemeral; public DfaMemoryStateImpl(final DfaValueFactory factory) { myFactory = factory; + myDefaultVariableStates = ContainerUtil.newTroveMap(); + myEqClasses = ContainerUtil.newArrayList(); + myUnknownVariables = ContainerUtil.newTroveSet(); + myVariableStates = ContainerUtil.newTroveMap(); + myDistinctClasses = new TLongHashSet(); + myOffsetStack = new TIntStack(); + myStack = new Stack<DfaValue>(); + } + + protected DfaMemoryStateImpl(DfaMemoryStateImpl toCopy) { + myFactory = toCopy.myFactory; + myEphemeral = toCopy.myEphemeral; + myDefaultVariableStates = toCopy.myDefaultVariableStates; // shared between all states + + myStack = new Stack<DfaValue>(toCopy.myStack); + myDistinctClasses = new TLongHashSet(toCopy.myDistinctClasses.toArray()); + myUnknownVariables = new THashSet<DfaVariableValue>(toCopy.myUnknownVariables); + myOffsetStack = toCopy.myOffsetStack; + + myEqClasses = ContainerUtil.newArrayList(toCopy.myEqClasses); + myVariableStates = new THashMap<DfaVariableValue, DfaVariableState>(toCopy.myVariableStates); + + myCachedDistinctClassPairs = toCopy.myCachedDistinctClassPairs; + myCachedNonTrivialEqClasses = toCopy.myCachedNonTrivialEqClasses; } public DfaValueFactory getFactory() { return myFactory; } - protected DfaMemoryStateImpl createNew() { - return new DfaMemoryStateImpl(myFactory); - } - @Override public DfaMemoryStateImpl createCopy() { - DfaMemoryStateImpl newState = createNew(); - - newState.myStack.addAll(myStack); - newState.myDistinctClasses.addAll(myDistinctClasses.toArray()); - newState.myUnknownVariables.addAll(myUnknownVariables); - newState.myOffsetStack = new TIntStack(myOffsetStack); - - for (int i = 0; i < myEqClasses.size(); i++) { - SortedIntSet aClass = myEqClasses.get(i); - newState.myEqClasses.add(aClass != null ? new SortedIntSet(aClass.toNativeArray()) : null); - } - - for (DfaVariableValue dfaVariableValue : myVariableStates.keySet()) { - newState.myVariableStates.put(dfaVariableValue, myVariableStates.get(dfaVariableValue).clone()); - } - return newState; + return new DfaMemoryStateImpl(this); } public boolean equals(Object obj) { @@ -85,84 +93,70 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!(obj instanceof DfaMemoryStateImpl)) return false; DfaMemoryStateImpl that = (DfaMemoryStateImpl)obj; - if (myDistinctClasses.size() != that.myDistinctClasses.size()) return false; - if (myStack.size() != that.myStack.size()) return false; - if (myOffsetStack.size() != that.myOffsetStack.size()) return false; - if (myVariableStates.size() != that.myVariableStates.size()) return false; - if (myUnknownVariables.size() != that.myUnknownVariables.size()) return false; + return equalsSuperficially(that) && myUnknownVariables.equals(that.myUnknownVariables) && equalsByRelations(that); + } - if (!myStack.equals(that.myStack)) return false; - if (!myOffsetStack.equals(that.myOffsetStack)) return false; - if (!myVariableStates.equals(that.myVariableStates)) return false; - if (!myUnknownVariables.equals(that.myUnknownVariables)) return false; - + boolean equalsSuperficially(DfaMemoryStateImpl other) { + return myEphemeral == other.myEphemeral && myStack.equals(other.myStack) && myOffsetStack.equals(other.myOffsetStack); + } + + boolean equalsByRelations(DfaMemoryStateImpl that) { + if (myDistinctClasses.size() != that.myDistinctClasses.size()) return false; if (!getNonTrivialEqClasses().equals(that.getNonTrivialEqClasses())) return false; if (!getDistinctClassPairs().equals(that.getDistinctClassPairs())) return false; - + if (!myVariableStates.equals(that.myVariableStates)) return false; return true; } - private Set<Set<SortedIntSet>> getDistinctClassPairs() { - Set<Set<SortedIntSet>> result = ContainerUtil.newHashSet(); + private Set<UnorderedPair<EqClass>> myCachedDistinctClassPairs; + Set<UnorderedPair<EqClass>> getDistinctClassPairs() { + if (myCachedDistinctClassPairs != null) return myCachedDistinctClassPairs; + + Set<UnorderedPair<EqClass>> result = ContainerUtil.newHashSet(); for (long encodedPair : myDistinctClasses.toArray()) { - THashSet<SortedIntSet> pair = new THashSet<SortedIntSet>(2); - pair.add(myEqClasses.get(low(encodedPair))); - pair.add(myEqClasses.get(high(encodedPair))); - result.add(pair); + result.add(new UnorderedPair<EqClass>(myEqClasses.get(low(encodedPair)), myEqClasses.get(high(encodedPair)))); } - return result; + return myCachedDistinctClassPairs = result; } - private Set<SortedIntSet> getNonTrivialEqClasses() { - Set<SortedIntSet> result = ContainerUtil.newHashSet(); - for (SortedIntSet eqClass : myEqClasses) { + private Set<EqClass> myCachedNonTrivialEqClasses; + Set<EqClass> getNonTrivialEqClasses() { + if (myCachedNonTrivialEqClasses != null) return myCachedNonTrivialEqClasses; + + Set<EqClass> result = ContainerUtil.newHashSet(); + for (EqClass eqClass : myEqClasses) { if (eqClass != null && eqClass.size() > 1) { result.add(eqClass); } } - return result; + return myCachedNonTrivialEqClasses = result; } public int hashCode() { - return 0; - //return ((myEqClasses.hashCode() * 31 + myStack.hashCode()) * 31 + myVariableStates.hashCode()) * 31 + myUnknownVariables.hashCode(); - } - - private void appendClass(StringBuilder buf, @Nullable SortedIntSet aClass) { - if (aClass == null) return; - - buf.append("("); - - for (int i = 0; i < aClass.size(); i++) { - if (i > 0) buf.append(", "); - int value = aClass.get(i); - DfaValue dfaValue = myFactory.getValue(value); - buf.append(dfaValue); - } - buf.append(")"); + return (((getNonTrivialEqClasses().hashCode() * 31 + + getDistinctClassPairs().hashCode()) * 31 + + myStack.hashCode()) * 31 + + myUnknownVariables.hashCode()) * 31 + + myVariableStates.hashCode(); } @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { StringBuilder result = new StringBuilder(); result.append('<'); + if (myEphemeral) { + result.append("ephemeral, "); + } - for (SortedIntSet set : getNonTrivialEqClasses()) { - appendClass(result, set); + for (EqClass set : getNonTrivialEqClasses()) { + result.append(set); } if (!myDistinctClasses.isEmpty()) { result.append("\n distincts: "); List<String> distincts = new ArrayList<String>(); - for (Set<SortedIntSet> pair : getDistinctClassPairs()) { - ArrayList<SortedIntSet> list = new ArrayList<SortedIntSet>(pair); - StringBuilder one = new StringBuilder(); - one.append("{"); - appendClass(one, list.get(0)); - one.append(", "); - appendClass(one, list.get(1)); - one.append("}"); - distincts.add(one.toString()); + for (UnorderedPair<EqClass> pair : getDistinctClassPairs()) { + distincts.add("{" + pair.first + ", " + pair.second + "}"); } Collections.sort(distincts); result.append(StringUtil.join(distincts, " ")); @@ -174,7 +168,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!myVariableStates.isEmpty()) { result.append("\n vars: "); for (Map.Entry<DfaVariableValue, DfaVariableState> entry : myVariableStates.entrySet()) { - result.append("\n[").append(entry.getKey()).append("->").append(entry.getValue()).append("]"); + result.append("[").append(entry.getKey()).append("->").append(entry.getValue()).append("] "); } } if (!myUnknownVariables.isEmpty()) { @@ -201,11 +195,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState { @Override public int popOffset() { + myOffsetStack = new TIntStack(myOffsetStack); return myOffsetStack.pop(); } @Override public void pushOffset(int offset) { + myOffsetStack = new TIntStack(myOffsetStack); myOffsetStack.push(offset); } @@ -220,13 +216,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState { flushVariable(var); if (value instanceof DfaUnknownValue) { - getVariableState(var).setNullable(false); + setVariableState(var, getVariableState(var).withNullable(false)); return; } - getVariableState(var).setValue(value); + setVariableState(var, getVariableState(var).withValue(value)); if (value instanceof DfaTypeValue) { - getVariableState(var).setNullable(((DfaTypeValue)value).isNullable()); + setVariableState(var, getVariableState(var).withNullable(((DfaTypeValue)value).isNullable())); DfaRelationValue dfaInstanceof = myFactory.getRelationFactory().createRelation(var, value, JavaTokenType.INSTANCEOF_KEYWORD, false); if (((DfaTypeValue)value).isNotNull()) { applyCondition(dfaInstanceof); @@ -240,10 +236,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState { applyCondition(dfaEqual); if (value instanceof DfaVariableValue) { - myVariableStates.put(var, getVariableState((DfaVariableValue)value).clone()); + setVariableState(var, getVariableState((DfaVariableValue)value)); } else if (value instanceof DfaBoxedValue) { - getVariableState(var).setNullable(false); + setVariableState(var, getVariableState(var).withNullable(false)); applyCondition(compareToNull(var, true)); } } @@ -260,7 +256,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!canBeReused(dfaValue) && !(((DfaBoxedValue)dfaValue).getWrappedValue() instanceof DfaConstValue)) { return null; } - SortedIntSet aClass = new SortedIntSet(); + EqClass aClass = new EqClass(myFactory); aClass.add(dfaValue.getID()); myEqClasses.add(aClass); @@ -270,20 +266,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState { @NotNull private List<DfaValue> getEqClassesFor(@NotNull DfaValue dfaValue) { int index = getEqClassIndex(dfaValue); - SortedIntSet set = index == -1 ? null : myEqClasses.get(index); + EqClass set = index == -1 ? null : myEqClasses.get(index); if (set == null) { return Collections.emptyList(); } - final List<DfaValue> result = new ArrayList<DfaValue>(set.size()); - set.forEach(new TIntProcedure() { - @Override - public boolean execute(int c1) { - DfaValue value = myFactory.getValue(c1); - result.add(value); - return true; - } - }); - return result; + return set.getMemberValues(); } private boolean canBeNaN(@NotNull DfaValue dfaValue) { @@ -309,7 +296,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { private int getEqClassIndex(@NotNull DfaValue dfaValue) { for (int i = 0; i < myEqClasses.size(); i++) { - SortedIntSet aClass = myEqClasses.get(i); + EqClass aClass = myEqClasses.get(i); if (aClass != null && aClass.contains(dfaValue.getID())) { if (!canBeReused(dfaValue) && aClass.size() > 1) return -1; return i; @@ -368,8 +355,8 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } private boolean uniteClasses(int c1Index, int c2Index) { - SortedIntSet c1 = myEqClasses.get(c1Index); - SortedIntSet c2 = myEqClasses.get(c2Index); + EqClass c1 = myEqClasses.get(c1Index); + EqClass c2 = myEqClasses.get(c2Index); Set<DfaVariableValue> vars = ContainerUtil.newTroveSet(); Set<DfaVariableValue> negatedVars = ContainerUtil.newTroveSet(); @@ -379,15 +366,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState { int nConst = 0; for (int c : cs) { - DfaValue dfaValue = myFactory.getValue(c); - if (dfaValue instanceof DfaBoxedValue) dfaValue = ((DfaBoxedValue)dfaValue).getWrappedValue(); - if (dfaValue instanceof DfaUnboxedValue) dfaValue = ((DfaUnboxedValue)dfaValue).getVariable(); + DfaValue dfaValue = unwrap(myFactory.getValue(c)); if (dfaValue instanceof DfaConstValue) nConst++; if (dfaValue instanceof DfaVariableValue) { DfaVariableValue variableValue = (DfaVariableValue)dfaValue; if (variableValue.isNegated()) { negatedVars.add(variableValue.createNegated()); - } else { + } + else { vars.add(variableValue); } } @@ -412,6 +398,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } + myEqClasses.set(c1Index, c1 = new EqClass(c1)); for (int i = 0; i < c2.size(); i++) { int c = c2.get(i); c1.add(c); @@ -458,7 +445,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { public boolean isNull(DfaValue dfaValue) { if (dfaValue instanceof DfaTypeValue && ((DfaTypeValue)dfaValue).isNotNull()) return false; - if (dfaValue instanceof DfaConstValue) return ((DfaConstValue)dfaValue).getConstant() == null; + if (dfaValue instanceof DfaConstValue) return ((DfaConstValue)dfaValue).getValue() == null; if (dfaValue instanceof DfaVariableValue) { int c1Index = getEqClassIndex(dfaValue); @@ -495,33 +482,47 @@ public class DfaMemoryStateImpl implements DfaMemoryState { @Override @Nullable public DfaConstValue getConstantValue(DfaVariableValue value) { - DfaConstValue result = null; - for (DfaValue equal : getEqClassesFor(value)) { - if (equal instanceof DfaVariableValue) continue; - DfaConstValue constValue = asConstantValue(equal); - if (constValue == null) return null; - result = constValue; - } - return result; + int index = getEqClassIndex(value); + EqClass ec = index == -1 ? null : myEqClasses.get(index); + return ec == null ? null : ec.findConstant(true); + } + + @Override + public void markEphemeral() { + myEphemeral = true; + } + + @Override + public boolean isEphemeral() { + return myEphemeral; } @Override public boolean applyInstanceofOrNull(DfaRelationValue dfaCond) { - DfaValue left = dfaCond.getLeftOperand(); - if (left instanceof DfaBoxedValue) { - left = ((DfaBoxedValue)left).getWrappedValue(); - } - else if (left instanceof DfaUnboxedValue) { - left = ((DfaUnboxedValue)left).getVariable(); - } + DfaValue left = unwrap(dfaCond.getLeftOperand()); if (!(left instanceof DfaVariableValue)) return true; DfaVariableValue dfaVar = (DfaVariableValue)left; DfaTypeValue dfaType = (DfaTypeValue)dfaCond.getRightOperand(); - final DfaVariableState varState = getVariableState(dfaVar); - return isNull(dfaVar) || varState.setInstanceofValue(dfaType); + if (isUnknownState(dfaVar) || isNull(dfaVar)) return true; + DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue(dfaType); + if (newState != null) { + setVariableState(dfaVar, newState); + return true; + } + return false; + } + + static DfaValue unwrap(DfaValue value) { + if (value instanceof DfaBoxedValue) { + return ((DfaBoxedValue)value).getWrappedValue(); + } + else if (value instanceof DfaUnboxedValue) { + return ((DfaUnboxedValue)value).getVariable(); + } + return value; } @Override @@ -563,12 +564,25 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (dfaRight instanceof DfaTypeValue) { if (dfaLeft instanceof DfaVariableValue) { - DfaVariableState varState = getVariableState((DfaVariableValue)dfaLeft); DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft; + if (isUnknownState(dfaVar)) return true; + if (isNegated) { - return varState.addNotInstanceofValue((DfaTypeValue)dfaRight) || applyCondition(compareToNull(dfaVar, false)); + DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue)dfaRight); + if (newState != null) { + setVariableState(dfaVar, newState); + return true; + } + return applyCondition(compareToNull(dfaVar, false)); + } + if (applyCondition(compareToNull(dfaVar, true))) { + DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue((DfaTypeValue)dfaRight); + if (newState != null) { + setVariableState(dfaVar, newState); + return true; + } } - return applyCondition(compareToNull(dfaVar, true)) && varState.setInstanceofValue((DfaTypeValue)dfaRight); + return false; } return true; } @@ -595,7 +609,9 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (isNotNull(dfaVar)) { return true; } - getVariableState(dfaVar).setNullable(true); + if (!isUnknownState(dfaVar)) { + setVariableState(dfaVar, getVariableState(dfaVar).withNullability(Nullness.NULLABLE)); + } } return false; } @@ -637,7 +653,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!TypeConversionUtil.isPrimitiveWrapper(type)) { return true; } - if (negated && !isMaybeBoxedConstant(dfaRight)) { + if (negated && !(unwrap(dfaRight) instanceof DfaConstValue)) { // from the fact (wrappers are not the same) does not follow (unboxed values are not equals) return true; } @@ -646,11 +662,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return applyRelation(boxedFactory.createUnboxed(dfaLeft), boxedFactory.createUnboxed(dfaRight), negated); } - private static boolean isMaybeBoxedConstant(DfaValue val) { - return val instanceof DfaConstValue || - val instanceof DfaBoxedValue && ((DfaBoxedValue)val).getWrappedValue() instanceof DfaConstValue; - } - private boolean checkCompareWithBooleanLiteral(DfaValue dfaLeft, DfaValue dfaRight, boolean negated) { if (dfaRight instanceof DfaConstValue) { Object constVal = ((DfaConstValue)dfaRight).getValue(); @@ -691,18 +702,28 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!isNegated) { //Equals if (c1Index.equals(c2Index)) return true; if (!uniteClasses(c1Index, c2Index)) return false; + + for (long encodedPair : myDistinctClasses.toArray()) { + EqClass c1 = myEqClasses.get(low(encodedPair)); + EqClass c2 = myEqClasses.get(high(encodedPair)); + if (c1.findConstant(false) != null && c2.findConstant(false) != null) { + myDistinctClasses.remove(encodedPair); + } + } + myCachedDistinctClassPairs = null; + myCachedNonTrivialEqClasses = null; } else { // Not Equals if (c1Index.equals(c2Index)) return false; makeClassesDistinct(c1Index, c2Index); + myCachedDistinctClassPairs = null; } return true; } private boolean isUnknownState(DfaValue val) { - if (val instanceof DfaBoxedValue) return isUnknownState(((DfaBoxedValue)val).getWrappedValue()); - if (val instanceof DfaUnboxedValue) return isUnknownState(((DfaUnboxedValue)val).getVariable()); + val = unwrap(val); if (val instanceof DfaVariableValue) { if (myUnknownVariables.contains(val)) return true; DfaVariableValue negatedValue = ((DfaVariableValue)val).getNegatedValue(); @@ -731,17 +752,33 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return myFactory.getRelationFactory().createRelation(dfaVar, dfaNull, JavaTokenType.EQEQ, negated); } + void setVariableState(DfaVariableValue dfaVar, DfaVariableState state) { + assert !myUnknownVariables.contains(dfaVar); + if (state.equals(myDefaultVariableStates.get(dfaVar))) { + myVariableStates.remove(dfaVar); + } else { + myVariableStates.put(dfaVar, state); + } + } + public DfaVariableState getVariableState(DfaVariableValue dfaVar) { DfaVariableState state = myVariableStates.get(dfaVar); if (state == null) { - state = createVariableState(dfaVar); + state = myDefaultVariableStates.get(dfaVar); + if (state == null) { + state = createVariableState(dfaVar); + DfaTypeValue initialType = dfaVar.getTypeValue(); + if (initialType != null) { + state = state.withInstanceofValue(initialType); + assert state != null; + } + myDefaultVariableStates.put(dfaVar, state); + } + if (isUnknownState(dfaVar)) { - state.setNullable(false); - return state; + return state.withNullable(false); } - - myVariableStates.put(dfaVar, state); } return state; @@ -757,28 +794,25 @@ public class DfaMemoryStateImpl implements DfaMemoryState { @Override public void flushFields(DfaVariableValue[] fields) { - Set<DfaVariableValue> allVars = new HashSet<DfaVariableValue>(myVariableStates.keySet()); - Collections.addAll(allVars, fields); - - Set<DfaVariableValue> dependencies = new HashSet<DfaVariableValue>(); - for (DfaVariableValue variableValue : allVars) { - dependencies.addAll(myFactory.getVarFactory().getAllQualifiedBy(variableValue)); - } - allVars.addAll(dependencies); - - for (DfaVariableValue value : allVars) { - if (myVariableStates.containsKey(value) || getEqClassIndex(value) >= 0) { - if (value.isFlushableByCalls()) { - doFlush(value); - myUnknownVariables.add(value); + for (EqClass aClass : myEqClasses) { + if (aClass != null) { + for (DfaVariableValue value : aClass.getVariables()) { + if (value.isFlushableByCalls()) { + doFlush(value, true); + } } } } + for (DfaVariableValue value : new ArrayList<DfaVariableValue>(myVariableStates.keySet())) { + if (value.isFlushableByCalls()) { + doFlush(value, true); + } + } } @Override public void flushVariable(@NotNull DfaVariableValue variable) { - doFlush(variable); + doFlush(variable, false); flushDependencies(variable); myUnknownVariables.remove(variable); myUnknownVariables.removeAll(myFactory.getVarFactory().getAllQualifiedBy(variable)); @@ -786,11 +820,15 @@ public class DfaMemoryStateImpl implements DfaMemoryState { public void flushDependencies(DfaVariableValue variable) { for (DfaVariableValue dependent : myFactory.getVarFactory().getAllQualifiedBy(variable)) { - doFlush(dependent); + doFlush(dependent, false); } } - private void doFlush(DfaVariableValue varPlain) { + Set<DfaVariableValue> getUnknownVariables() { + return myUnknownVariables; + } + + void doFlush(DfaVariableValue varPlain, boolean markUnknown) { DfaVariableValue varNegated = varPlain.getNegatedValue(); final int idPlain = varPlain.getID(); @@ -799,7 +837,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { int size = myEqClasses.size(); int interruptCount = 0; for (int varClassIndex = 0; varClassIndex < size; varClassIndex++) { - final SortedIntSet varClass = myEqClasses.get(varClassIndex); + EqClass varClass = myEqClasses.get(varClassIndex); if (varClass == null) continue; for (int i = 0; i < varClass.size(); i++) { @@ -809,6 +847,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { int cl = varClass.get(i); DfaValue value = myFactory.getValue(cl); if (mine(idPlain, value) || idNegated >= 0 && mine(idNegated, value)) { + myEqClasses.set(varClassIndex, varClass = new EqClass(varClass)); varClass.remove(i); break; } @@ -823,10 +862,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } } - else if (containsConstantsOnly(varClassIndex)) { + else if (varClass.containsConstantsOnly()) { for (long pair : myDistinctClasses.toArray()) { - if (low(pair) == varClassIndex && containsConstantsOnly(high(pair)) || - high(pair) == varClassIndex && containsConstantsOnly(low(pair))) { + if (low(pair) == varClassIndex && myEqClasses.get(high(pair)).containsConstantsOnly() || + high(pair) == varClassIndex && myEqClasses.get(low(pair)).containsConstantsOnly()) { myDistinctClasses.remove(pair); } } @@ -837,28 +876,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (varNegated != null) { myVariableStates.remove(varNegated); } - } - - @Nullable private static DfaConstValue asConstantValue(DfaValue value) { - if (value instanceof DfaConstValue) return (DfaConstValue)value; - if (value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue() instanceof DfaConstValue) return (DfaConstValue)((DfaBoxedValue)value).getWrappedValue(); - return null; - } - - private boolean containsConstantsOnly(int id) { - SortedIntSet varClass = myEqClasses.get(id); - for (int i = 0; i < varClass.size(); i++) { - if (asConstantValue(myFactory.getValue(varClass.get(i))) == null) { - return false; - } + if (markUnknown) { + myUnknownVariables.add(varPlain); } - - return true; + myCachedNonTrivialEqClasses = null; + myCachedDistinctClassPairs = null; } private static boolean mine(int id, DfaValue value) { - return value != null && id == value.getID() || - value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue().getID() == id || - value instanceof DfaUnboxedValue && ((DfaUnboxedValue)value).getVariable().getID() == id; + return value != null && id == unwrap(value).getID(); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java index 3b493d4dea26..8ed7836f0dfd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java @@ -37,9 +37,6 @@ import java.util.List; import java.util.Set; public class DfaPsiUtil { - public static boolean isPlainMutableField(PsiVariable var) { - return !var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && !var.hasModifierProperty(PsiModifier.VOLATILE) && var instanceof PsiField; - } public static boolean isFinalField(PsiVariable var) { return var.hasModifierProperty(PsiModifier.FINAL) && !var.hasModifierProperty(PsiModifier.TRANSIENT) && var instanceof PsiField; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index 8c3cce8a51ea..16a2a6d8e3a7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -163,9 +163,10 @@ public class DfaUtil { } @Override - public DfaInstructionState[] visitAssign(AssignInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { + public DfaInstructionState[] visitAssign(AssignInstruction instruction, DataFlowRunner runner, DfaMemoryState _memState) { final Instruction nextInstruction = runner.getInstruction(instruction.getIndex() + 1); + ValuableDataFlowRunner.MyDfaMemoryState memState = (ValuableDataFlowRunner.MyDfaMemoryState)_memState; final DfaValue dfaSource = memState.pop(); final DfaValue dfaDest = memState.pop(); @@ -176,10 +177,10 @@ public class DfaUtil { final IElementType type = parent instanceof PsiAssignmentExpression ? ((PsiAssignmentExpression)parent).getOperationTokenType() : JavaTokenType.EQ; // store current value - to use in case of '+=' - final PsiExpression prevValue = ((ValuableDataFlowRunner.ValuableDfaVariableState)((ValuableDataFlowRunner.MyDfaMemoryState)memState).getVariableState(var)).myExpression; + final PsiExpression prevValue = ((ValuableDataFlowRunner.ValuableDfaVariableState)memState.getVariableState(var)).myExpression; memState.setVarValue(var, dfaSource); // state may have been changed so re-retrieve it - final ValuableDataFlowRunner.ValuableDfaVariableState curState = (ValuableDataFlowRunner.ValuableDfaVariableState)((ValuableDataFlowRunner.MyDfaMemoryState)memState).getVariableState(var); + final ValuableDataFlowRunner.ValuableDfaVariableState curState = (ValuableDataFlowRunner.ValuableDfaVariableState)memState.getVariableState(var); final PsiExpression curValue = curState.myExpression; final PsiExpression nextValue; if (type == JavaTokenType.PLUSEQ && prevValue != null) { @@ -196,7 +197,7 @@ public class DfaUtil { else { nextValue = curValue == null ? rightValue : curValue; } - curState.myExpression = nextValue; + memState.setVariableState(var, curState.withExpression(nextValue)); } memState.push(dfaDest); return new DfaInstructionState[]{new DfaInstructionState(nextInstruction, memState)}; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java index 81738226061a..61d61c26cf79 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaVariableState.java @@ -24,138 +24,134 @@ */ package com.intellij.codeInspection.dataFlow; +import com.intellij.codeInspection.dataFlow.value.DfaPsiType; import com.intellij.codeInspection.dataFlow.value.DfaTypeValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; -import com.intellij.psi.*; -import gnu.trove.THashSet; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiPrimitiveType; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; import java.util.Set; -public class DfaVariableState implements Cloneable { - private final Set<DfaTypeValue> myInstanceofValues; - private final Set<DfaTypeValue> myNotInstanceofValues; - private Nullness myNullability; +public class DfaVariableState { + protected final Set<DfaPsiType> myInstanceofValues; + protected final Set<DfaPsiType> myNotInstanceofValues; + protected final Nullness myNullability; public DfaVariableState(@NotNull DfaVariableValue dfaVar) { - myInstanceofValues = new HashSet<DfaTypeValue>(); - myNotInstanceofValues = new HashSet<DfaTypeValue>(); - - myNullability = dfaVar.getInherentNullability(); - DfaTypeValue initialType = dfaVar.getTypeValue(); - if (initialType != null) { - setInstanceofValue(initialType); - } + this(Collections.<DfaPsiType>emptySet(), Collections.<DfaPsiType>emptySet(), dfaVar.getInherentNullability()); } - protected DfaVariableState(final DfaVariableState toClone) { - myInstanceofValues = new THashSet<DfaTypeValue>(toClone.myInstanceofValues); - myNotInstanceofValues = new THashSet<DfaTypeValue>(toClone.myNotInstanceofValues); - myNullability = toClone.myNullability; + protected DfaVariableState(Set<DfaPsiType> instanceofValues, + Set<DfaPsiType> notInstanceofValues, Nullness nullability) { + myInstanceofValues = instanceofValues; + myNotInstanceofValues = notInstanceofValues; + myNullability = nullability; } public boolean isNullable() { return myNullability == Nullness.NULLABLE; } - private boolean checkInstanceofValue(DfaTypeValue dfaType) { + private boolean checkInstanceofValue(DfaPsiType dfaType) { if (myInstanceofValues.contains(dfaType)) return true; - for (DfaTypeValue dfaTypeValue : myNotInstanceofValues) { + for (DfaPsiType dfaTypeValue : myNotInstanceofValues) { if (dfaTypeValue.isAssignableFrom(dfaType)) return false; } - for (DfaTypeValue dfaTypeValue : myInstanceofValues) { + for (DfaPsiType dfaTypeValue : myInstanceofValues) { if (!dfaType.isConvertibleFrom(dfaTypeValue)) return false; } return true; } - public boolean setInstanceofValue(DfaTypeValue dfaType) { - if (dfaType.isNullable()) { - myNullability = Nullness.NULLABLE; - } - - if (dfaType.getType() instanceof PsiPrimitiveType) return true; - - if (checkInstanceofValue(dfaType)) { - myInstanceofValues.add(dfaType); - return true; + @Nullable + public DfaVariableState withInstanceofValue(DfaTypeValue dfaType) { + if (dfaType.getDfaType().getPsiType() instanceof PsiPrimitiveType) return this; + + if (checkInstanceofValue(dfaType.getDfaType())) { + DfaVariableState result = dfaType.isNullable() ? withNullability(Nullness.NULLABLE) : this; + if (!myInstanceofValues.contains(dfaType.getDfaType())) { + HashSet<DfaPsiType> newInstanceof = ContainerUtil.newHashSet(myInstanceofValues); + newInstanceof.add(dfaType.getDfaType()); + result = createCopy(newInstanceof, myNotInstanceofValues, result.myNullability); + } + return result; } - return false; + return null; } - public boolean addNotInstanceofValue(DfaTypeValue dfaType) { - if (myNotInstanceofValues.contains(dfaType)) return true; + @Nullable + public DfaVariableState withNotInstanceofValue(DfaTypeValue dfaType) { + if (myNotInstanceofValues.contains(dfaType.getDfaType())) return this; - for (DfaTypeValue dfaTypeValue : myInstanceofValues) { - if (dfaType.isAssignableFrom(dfaTypeValue)) return false; + for (DfaPsiType dfaTypeValue : myInstanceofValues) { + if (dfaType.getDfaType().isAssignableFrom(dfaTypeValue)) return null; } - myNotInstanceofValues.add(dfaType); - return true; + HashSet<DfaPsiType> newNotInstanceof = ContainerUtil.newHashSet(myNotInstanceofValues); + newNotInstanceof.add(dfaType.getDfaType()); + return createCopy(myInstanceofValues, newNotInstanceof, myNullability); } public int hashCode() { - return myInstanceofValues.hashCode() + myNotInstanceofValues.hashCode(); + return (myInstanceofValues.hashCode() * 31 + myNotInstanceofValues.hashCode()) * 31 + myNullability.hashCode(); } public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof DfaVariableState)) return false; DfaVariableState aState = (DfaVariableState) obj; - return myInstanceofValues.equals(aState.myInstanceofValues) && - myNotInstanceofValues.equals(aState.myNotInstanceofValues) && - myNullability == aState.myNullability; + return myNullability == aState.myNullability && + myInstanceofValues.equals(aState.myInstanceofValues) && + myNotInstanceofValues.equals(aState.myNotInstanceofValues); } - @Override - protected DfaVariableState clone() { - return new DfaVariableState(this); + protected DfaVariableState createCopy(Set<DfaPsiType> instanceofValues, Set<DfaPsiType> notInstanceofValues, Nullness nullability) { + return new DfaVariableState(instanceofValues, notInstanceofValues, nullability); } public String toString() { @NonNls StringBuilder buf = new StringBuilder(); + buf.append(myNullability); if (!myInstanceofValues.isEmpty()) { - buf.append("instanceof "); - for (Iterator<DfaTypeValue> iterator = myInstanceofValues.iterator(); iterator.hasNext();) { - DfaTypeValue dfaTypeValue = iterator.next(); - buf.append("{").append(dfaTypeValue).append("}"); - if (iterator.hasNext()) buf.append(", "); - } + buf.append(" instanceof ").append(StringUtil.join(myInstanceofValues, ",")); } if (!myNotInstanceofValues.isEmpty()) { - buf.append("not instanceof "); - for (Iterator<DfaTypeValue> iterator = myNotInstanceofValues.iterator(); iterator.hasNext();) { - DfaTypeValue dfaTypeValue = iterator.next(); - buf.append("{").append(dfaTypeValue).append("}"); - if (iterator.hasNext()) buf.append(", "); - } + buf.append(" not instanceof ").append(StringUtil.join(myNotInstanceofValues, ",")); } - buf.append(myNullability); return buf.toString(); } + public Nullness getNullability() { + return myNullability; + } + public boolean isNotNull() { return myNullability == Nullness.NOT_NULL; } - public void setNullable(final boolean nullable) { - if (myNullability != Nullness.NOT_NULL) { - myNullability = nullable ? Nullness.NULLABLE : Nullness.UNKNOWN; - } + DfaVariableState withNullability(@NotNull Nullness nullness) { + return myNullability == nullness ? this : createCopy(myInstanceofValues, myNotInstanceofValues, nullness); + } + + public DfaVariableState withNullable(final boolean nullable) { + return myNullability != Nullness.NOT_NULL ? withNullability(nullable ? Nullness.NULLABLE : Nullness.UNKNOWN) : this; } - public void setValue(DfaValue value) { + public DfaVariableState withValue(DfaValue value) { + return this; } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/EqClass.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/EqClass.java new file mode 100644 index 000000000000..c6fc62170ef2 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/EqClass.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.intellij.codeInspection.dataFlow; + +import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaValue; +import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; +import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.TIntProcedure; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author peter + */ +class EqClass extends SortedIntSet { + private final DfaValueFactory myFactory; + + EqClass(DfaValueFactory factory) { + myFactory = factory; + } + + EqClass(EqClass toCopy) { + super(toCopy.toNativeArray()); + myFactory = toCopy.myFactory; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("("); + for (int i = 0; i < size(); i++) { + if (i > 0) buf.append(", "); + int value = get(i); + DfaValue dfaValue = myFactory.getValue(value); + buf.append(dfaValue); + } + buf.append(")"); + return buf.toString(); + } + + List<DfaVariableValue> getVariables() { + List<DfaVariableValue> vars = ContainerUtil.newArrayList(); + for (DfaValue value : getMemberValues()) { + value = DfaMemoryStateImpl.unwrap(value); + if (value instanceof DfaVariableValue) { + vars.add((DfaVariableValue)value); + } + } + return vars; + } + + List<DfaValue> getMemberValues() { + final List<DfaValue> result = new ArrayList<DfaValue>(size()); + forEach(new TIntProcedure() { + @Override + public boolean execute(int c1) { + DfaValue value = myFactory.getValue(c1); + result.add(value); + return true; + } + }); + return result; + } + + @Nullable + DfaConstValue findConstant(boolean wrapped) { + for (DfaValue value : getMemberValues()) { + if (wrapped) { + value = DfaMemoryStateImpl.unwrap(value); + } + if (value instanceof DfaConstValue) { + return (DfaConstValue)value; + } + } + return null; + } + + @Nullable + private static DfaConstValue asConstantValue(DfaValue value) { + value = DfaMemoryStateImpl.unwrap(value); + return value instanceof DfaConstValue ? (DfaConstValue)value : null; + } + + boolean containsConstantsOnly() { + for (int i = 0; i < size(); i++) { + if (asConstantValue(myFactory.getValue(get(i))) == null) { + return false; + } + } + + return true; + } + +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java new file mode 100644 index 000000000000..8155149ed1ec --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java @@ -0,0 +1,14 @@ +package com.intellij.codeInspection.dataFlow; + +/** + * @author peter + */ +public enum NullabilityProblem { + callNPE, + fieldAccessNPE, + unboxingNullable, + assigningToNotNull, + nullableReturn, + passingNullableToNotNullParameter, + passingNullableArgumentToNonAnnotatedParameter, +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java index b7fc6c7dcfc8..2d6ee1b71232 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardDataFlowRunner.java @@ -27,36 +27,23 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.dataFlow.instructions.InstanceofInstruction; import com.intellij.codeInspection.dataFlow.instructions.Instruction; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; -import com.intellij.psi.*; -import gnu.trove.THashSet; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.Set; public class StandardDataFlowRunner extends DataFlowRunner { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowRunner"); - - private final Set<Instruction> myNPEInstructions = new HashSet<Instruction>(); private final Set<Instruction> myCCEInstructions = new HashSet<Instruction>(); - private final Set<PsiExpression> myNullableArguments = new HashSet<PsiExpression>(); - private final Set<PsiExpression> myNullableArgumentsPassedToNonAnnotatedParam = new HashSet<PsiExpression>(); - private final Set<PsiExpression> myNullableAssignments = new HashSet<PsiExpression>(); - private final Set<PsiReturnStatement> myNullableReturns = new HashSet<PsiReturnStatement>(); - private final boolean mySuggestNullableAnnotations; private boolean myInNullableMethod = false; private boolean myInNotNullMethod = false; private boolean myIsInMethod = false; - private final Set<PsiExpression> myUnboxedNullables = new THashSet<PsiExpression>(); - - public StandardDataFlowRunner(boolean suggestNullableAnnotations) { - mySuggestNullableAnnotations = suggestNullableAnnotations; - } - @Override protected void prepareAnalysis(@NotNull PsiElement psiBlock, Iterable<DfaMemoryState> initialStates) { myIsInMethod = psiBlock.getParent() instanceof PsiMethod; @@ -68,17 +55,7 @@ public class StandardDataFlowRunner extends DataFlowRunner { myInNotNullMethod = NullableNotNullManager.isNotNull(method); } - myNPEInstructions.clear(); myCCEInstructions.clear(); - myNullableArguments.clear(); - myNullableArgumentsPassedToNonAnnotatedParam.clear(); - myNullableAssignments.clear(); - myNullableReturns.clear(); - myUnboxedNullables.clear(); - } - - public void onInstructionProducesNPE(Instruction instruction) { - myNPEInstructions.add(instruction); } public void onInstructionProducesCCE(Instruction instruction) { @@ -89,74 +66,24 @@ public class StandardDataFlowRunner extends DataFlowRunner { return myCCEInstructions; } - @NotNull public Set<Instruction> getNPEInstructions() { - return myNPEInstructions; - } - - @NotNull public Set<PsiReturnStatement> getNullableReturns() { - return myNullableReturns; - } - public boolean isInNotNullMethod() { return myInNotNullMethod; } - @NotNull public Set<PsiExpression> getNullableArguments() { - return myNullableArguments; - } - - public Set<PsiExpression> getNullableArgumentsPassedToNonAnnotatedParam() { - return myNullableArgumentsPassedToNonAnnotatedParam; - } - - @NotNull public Set<PsiExpression> getNullableAssignments() { - return myNullableAssignments; + public boolean isInNullableMethod() { + return myInNullableMethod; } - @NotNull public Set<PsiExpression> getUnboxedNullables() { - return myUnboxedNullables; - } - - public void onUnboxingNullable(@NotNull PsiExpression expression) { - LOG.assertTrue(expression.isValid()); - if (expression.isPhysical()) { - myUnboxedNullables.add(expression); - } - } - - public void onPassingNullParameter(PsiExpression expr) { - myNullableArguments.add(expr); - } - - public void onPassingNullParameterToNonAnnotated(PsiExpression expr) { - if (mySuggestNullableAnnotations) { - myNullableArgumentsPassedToNonAnnotatedParam.add(expr); - } - } - - public void onAssigningToNotNullableVariable(final PsiExpression expr) { - myNullableAssignments.add(expr); - } - - public void onNullableReturn(final PsiReturnStatement statement) { - if (myInNullableMethod || !myIsInMethod) return; - if (myInNotNullMethod || mySuggestNullableAnnotations) { - myNullableReturns.add(statement); - } + public boolean isInMethod() { + return myIsInMethod; } public boolean problemsDetected(StandardInstructionVisitor visitor) { final Pair<Set<Instruction>, Set<Instruction>> constConditions = getConstConditionalExpressions(); return !constConditions.getFirst().isEmpty() || !constConditions.getSecond().isEmpty() - || !myNPEInstructions.isEmpty() || !myCCEInstructions.isEmpty() - || !getRedundantInstanceofs(this, visitor).isEmpty() - || !myNullableArguments.isEmpty() - || !myNullableArgumentsPassedToNonAnnotatedParam.isEmpty() - || !myNullableAssignments.isEmpty() - || !myNullableReturns.isEmpty() - || !myUnboxedNullables.isEmpty(); + || !getRedundantInstanceofs(this, visitor).isEmpty(); } @NotNull public static Set<Instruction> getRedundantInstanceofs(final DataFlowRunner runner, StandardInstructionVisitor visitor) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 3770e49600db..90a64901c424 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -115,17 +115,15 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (dfaDest instanceof DfaVariableValue) { DfaVariableValue var = (DfaVariableValue) dfaDest; - final PsiModifierListOwner psiVariable = var.getPsiVariable(); - if (DfaPsiUtil.getElementNullability(var.getVariableType(), psiVariable) == Nullness.NOT_NULL) { - if (!memState.checkNotNullable(dfaSource)) { - onAssigningToNotNullableVariable(instruction); - } + if (var.getInherentNullability() == Nullness.NOT_NULL) { + checkNotNullable(memState, dfaSource, NullabilityProblem.assigningToNotNull, instruction.getRExpression()); } - if (!(psiVariable instanceof PsiField) || !psiVariable.hasModifierProperty(PsiModifier.VOLATILE)) { + final PsiModifierListOwner psi = var.getPsiVariable(); + if (!(psi instanceof PsiField) || !psi.hasModifierProperty(PsiModifier.VOLATILE)) { memState.setVarValue(var, dfaSource); } - } else if (dfaDest instanceof DfaTypeValue && ((DfaTypeValue)dfaDest).isNotNull() && !memState.checkNotNullable(dfaSource)) { - onAssigningToNotNullableVariable(instruction); + } else if (dfaDest instanceof DfaTypeValue && ((DfaTypeValue)dfaDest).isNotNull()) { + checkNotNullable(memState, dfaSource, NullabilityProblem.assigningToNotNull, instruction.getRExpression()); } memState.push(dfaDest); @@ -133,27 +131,19 @@ public class StandardInstructionVisitor extends InstructionVisitor { return nextInstruction(instruction, runner, memState); } - protected void onAssigningToNotNullableVariable(AssignInstruction instruction) {} - @Override public DfaInstructionState[] visitCheckReturnValue(CheckReturnValueInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { final DfaValue retValue = memState.pop(); - if (!memState.checkNotNullable(retValue)) { - onNullableReturn(instruction); - } + checkNotNullable(memState, retValue, NullabilityProblem.nullableReturn, instruction.getReturn()); return nextInstruction(instruction, runner, memState); } - protected void onNullableReturn(CheckReturnValueInstruction instruction) {} - @Override public DfaInstructionState[] visitFieldReference(FieldReferenceInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { final DfaValue qualifier = memState.pop(); - if (!memState.checkNotNullable(qualifier)) { - onInstructionProducesNPE(instruction); - + if (!checkNotNullable(memState, qualifier, NullabilityProblem.fieldAccessNPE, instruction.getElementToAssert())) { if (qualifier instanceof DfaVariableValue) { memState.setVarValue((DfaVariableValue)qualifier, runner.getFactory() .createTypeValue(((DfaVariableValue)qualifier).getVariableType(), Nullness.NOT_NULL)); @@ -194,7 +184,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { final DfaValueFactory factory = runner.getFactory(); DfaValue dfaExpr = factory.createValue(instruction.getCasted()); if (dfaExpr != null) { - DfaTypeValue dfaType = factory.getTypeFactory().createTypeValue(instruction.getCastTo()); + DfaTypeValue dfaType = (DfaTypeValue)factory.createTypeValue(instruction.getCastTo(), Nullness.UNKNOWN); DfaRelationValue dfaInstanceof = factory.getRelationFactory().createRelation(dfaExpr, dfaType, JavaTokenType.INSTANCEOF_KEYWORD, false); if (dfaInstanceof != null && !memState.applyInstanceofOrNull(dfaInstanceof)) { onInstructionProducesCCE(instruction); @@ -218,23 +208,24 @@ public class StandardInstructionVisitor extends InstructionVisitor { final DfaValue arg = memState.pop(); PsiExpression expr = args[(args.length - i - 1)]; if (map.get(expr) == Nullness.NOT_NULL) { - if (!memState.checkNotNullable(arg)) { - onPassingNullParameter(expr); + if (!checkNotNullable(memState, arg, NullabilityProblem.passingNullableToNotNullParameter, expr)) { if (arg instanceof DfaVariableValue) { memState.setVarValue((DfaVariableValue)arg, runner.getFactory() .createTypeValue(((DfaVariableValue)arg).getVariableType(), Nullness.NOT_NULL)); } } } - else if (map.get(expr) == Nullness.UNKNOWN && !memState.checkNotNullable(arg)) { - onPassingNullParameterToNonAnnotated(runner, expr); + else if (map.get(expr) == Nullness.UNKNOWN) { + checkNotNullable(memState, arg, NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter, expr); } } @NotNull final DfaValue qualifier = memState.pop(); try { - if (!memState.checkNotNullable(qualifier)) { - onInstructionProducesNPE(instruction); + boolean unboxing = instruction.getMethodType() == MethodCallInstruction.MethodType.UNBOXING; + NullabilityProblem problem = unboxing ? NullabilityProblem.unboxingNullable : NullabilityProblem.callNPE; + PsiExpression anchor = unboxing ? instruction.getContext() : instruction.getCallExpression(); + if (!checkNotNullable(memState, qualifier, problem, anchor)) { if (qualifier instanceof DfaVariableValue) { memState.setVarValue((DfaVariableValue)qualifier, runner.getFactory().createTypeValue( ((DfaVariableValue)qualifier).getVariableType(), Nullness.NOT_NULL)); @@ -296,11 +287,11 @@ public class StandardInstructionVisitor extends InstructionVisitor { return TypeConversionUtil.computeCastTo(o, PsiType.LONG); } - - protected void onInstructionProducesNPE(Instruction instruction) {} - - protected void onPassingNullParameter(PsiExpression arg) {} - protected void onPassingNullParameterToNonAnnotated(DataFlowRunner runner, PsiExpression arg) {} + protected boolean checkNotNullable(DfaMemoryState state, + DfaValue value, NullabilityProblem problem, + PsiElement anchor) { + return state.checkNotNullable(value); + } @Override public DfaInstructionState[] visitBinop(BinopInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { @@ -351,11 +342,10 @@ public class StandardInstructionVisitor extends InstructionVisitor { return null; } - if (isViaMethods(dfaLeft) || isViaMethods(dfaRight)) { - skipConstantConditionReporting(instruction.getPsiAnchor()); - } myCanBeNullInInstanceof.add(instruction); + boolean specialContractTreatment = isUnknownComparisonWithNullInContract(instruction, dfaLeft, dfaRight, factory, memState); + ArrayList<DfaInstructionState> states = new ArrayList<DfaInstructionState>(); final DfaMemoryState trueCopy = memState.createCopy(); @@ -363,6 +353,9 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (!dfaRelation.isNegated()) { checkOneOperandNotNull(dfaRight, dfaLeft, factory, trueCopy); } + if (specialContractTreatment && !dfaRelation.isNegated()) { + trueCopy.markEphemeral(); + } trueCopy.push(factory.getConstFactory().getTrue()); instruction.setTrueReachable(); states.add(new DfaInstructionState(next, trueCopy)); @@ -374,6 +367,9 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (dfaRelation.isNegated()) { checkOneOperandNotNull(dfaRight, dfaLeft, factory, falseCopy); } + if (specialContractTreatment && dfaRelation.isNegated()) { + falseCopy.markEphemeral(); + } falseCopy.push(factory.getConstFactory().getFalse()); instruction.setFalseReachable(); states.add(new DfaInstructionState(next, falseCopy)); @@ -385,12 +381,25 @@ public class StandardInstructionVisitor extends InstructionVisitor { return states.toArray(new DfaInstructionState[states.size()]); } - public void skipConstantConditionReporting(@Nullable PsiElement anchor) { - ContainerUtil.addIfNotNull(myNotToReportReachability, anchor); + private static boolean isUnknownComparisonWithNullInContract(BinopInstruction instruction, + DfaValue dfaLeft, + DfaValue dfaRight, + DfaValueFactory factory, + DfaMemoryState memoryState) { + if (instruction.getPsiAnchor() != null || dfaRight != factory.getConstFactory().getNull()) { + return false; + } + if (dfaLeft instanceof DfaVariableValue) { + return ((DfaMemoryStateImpl)memoryState).getVariableState((DfaVariableValue)dfaLeft).getNullability() == Nullness.UNKNOWN; + } + if (dfaLeft instanceof DfaTypeValue) { + return ((DfaTypeValue)dfaLeft).getNullness() == Nullness.UNKNOWN; + } + return false; } - private static boolean isViaMethods(DfaValue dfa) { - return dfa instanceof DfaVariableValue && ((DfaVariableValue)dfa).isViaMethods(); + public void skipConstantConditionReporting(@Nullable PsiElement anchor) { + ContainerUtil.addIfNotNull(myNotToReportReachability, anchor); } private void handleInstanceof(InstanceofInstruction instruction, DfaValue dfaRight, DfaValue dfaLeft) { @@ -399,7 +408,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { myCanBeNullInInstanceof.add(instruction); } - if (((DfaTypeValue)dfaRight).getType().isAssignableFrom(((DfaTypeValue)dfaLeft).getType())) { + if (((DfaTypeValue)dfaRight).getDfaType().isAssignableFrom(((DfaTypeValue)dfaLeft).getDfaType())) { return; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java new file mode 100644 index 000000000000..e886dde637a0 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java @@ -0,0 +1,217 @@ +/* + * 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.dataFlow; + +import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaValue; +import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.UnorderedPair; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author peter + */ +class StateMerger { + private final List<DfaMemoryStateImpl> myStates; + private final MultiMap<UnorderedPair<DfaValue>,DfaMemoryStateImpl> myStatesByEq = new MultiMap<UnorderedPair<DfaValue>, DfaMemoryStateImpl>(); + private final Map<DfaMemoryStateImpl, Map<DfaVariableValue, DfaConstValue>> myVarValues = ContainerUtil.newIdentityHashMap(); + + public StateMerger(List<DfaMemoryStateImpl> states) { + myStates = states; + for (DfaMemoryStateImpl state : myStates) { + ProgressManager.checkCanceled(); + + Map<DfaVariableValue,DfaConstValue> varValues = ContainerUtil.newHashMap(); + for (UnorderedPair<DfaValue> pair : getEqPairs(state)) { + myStatesByEq.putValue(pair, state); + if (pair.first instanceof DfaVariableValue && pair.second instanceof DfaConstValue) { + varValues.put((DfaVariableValue)pair.first, (DfaConstValue)pair.second); + } + } + myVarValues.put(state, varValues); + } + } + + @Nullable + public List<DfaMemoryStateImpl> merge() { + for (final DfaMemoryStateImpl state : myStates) { + ProgressManager.checkCanceled(); + MultiMap<DfaVariableValue, DfaValue> distincts = getDistinctsMap(state); + for (DfaVariableValue var : distincts.keySet()) { + Map<DfaValue, Collection<DfaMemoryStateImpl>> statesByValue = getCompatibleStatesByValue(state, var, distincts); + if (statesByValue == null) { + continue; + } + + DfaMemoryStateImpl copy = copyWithoutVar(state, var); + + final Set<DfaMemoryStateImpl> complementaryStates = findComplementaryStates(var, statesByValue, copy); + if (complementaryStates == null) { + continue; + } + + complementaryStates.add(state); + copy = copy.createCopy(); + for (DfaMemoryStateImpl removedState : complementaryStates) { + for (DfaVariableValue unknownVar : removedState.getUnknownVariables()) { + copy.doFlush(unknownVar, true); + } + if (removedState.isNull(var)) { + copy.setVariableState(var, copy.getVariableState(var).withNullability(Nullness.NULLABLE)); + } + } + + List<DfaMemoryStateImpl> result = ContainerUtil.newArrayList(); + result.add(copy); + result.addAll(ContainerUtil.filter(myStates, new Condition<DfaMemoryStateImpl>() { + @Override + public boolean value(DfaMemoryStateImpl state) { + return !complementaryStates.contains(state); + } + })); + return result; + } + + } + return null; + } + + private Map<Pair<DfaMemoryStateImpl, DfaVariableValue>, DfaMemoryStateImpl> myCopyCache = ContainerUtil.newHashMap(); + private DfaMemoryStateImpl copyWithoutVar(DfaMemoryStateImpl state, DfaVariableValue var) { + Pair<DfaMemoryStateImpl, DfaVariableValue> key = Pair.create(state, var); + DfaMemoryStateImpl copy = myCopyCache.get(key); + if (copy == null) { + copy = state.createCopy(); + copy.flushVariable(var); + myCopyCache.put(key, copy); + } + return copy; + } + + @Nullable + private Set<DfaMemoryStateImpl> findComplementaryStates(DfaVariableValue var, + Map<DfaValue, Collection<DfaMemoryStateImpl>> statesByValue, + DfaMemoryStateImpl mainCopy) { + Set<DfaMemoryStateImpl> removedStates = ContainerUtil.newTroveSet(ContainerUtil.<DfaMemoryStateImpl>identityStrategy()); + + eachValue: + for (DfaValue value : statesByValue.keySet()) { + for (DfaMemoryStateImpl originalState : statesByValue.get(value)) { + if (mainCopy.equalsByRelations(copyWithoutVar(originalState, var))) { + removedStates.add(originalState); + continue eachValue; + } + } + return null; + } + return removedStates; + } + + @Nullable + private Map<DfaValue, Collection<DfaMemoryStateImpl>> getCompatibleStatesByValue(final DfaMemoryStateImpl state, + final DfaVariableValue var, + MultiMap<DfaVariableValue, DfaValue> distincts) { + Map<DfaValue, Collection<DfaMemoryStateImpl>> statesByValue = ContainerUtil.newHashMap(); + for (DfaValue value : distincts.get(var)) { + List<DfaMemoryStateImpl> compatible = ContainerUtil.filter(myStatesByEq.get(createPair(var, value)), new Condition<DfaMemoryStateImpl>() { + @Override + public boolean value(DfaMemoryStateImpl state2) { + return areCompatible(state, state2, var); + } + }); + if (compatible.isEmpty()) { + return null; + } + statesByValue.put(value, compatible); + } + return statesByValue; + } + + private boolean areCompatible(DfaMemoryStateImpl state1, DfaMemoryStateImpl state2, DfaVariableValue differentVar) { + if (!state1.equalsSuperficially(state2)) { + return false; + } + Map<DfaVariableValue, DfaConstValue> varValues1 = myVarValues.get(state1); + Map<DfaVariableValue, DfaConstValue> varValues2 = myVarValues.get(state2); + + for (DfaVariableValue var : varValues1.keySet()) { + if (var != differentVar && varValues1.get(var) != varValues2.get(var)) { + return false; + } + } + for (DfaVariableValue var : varValues2.keySet()) { + if (var != differentVar && !varValues1.containsKey(var)) { + return false; + } + } + return true; + } + + private static MultiMap<DfaVariableValue, DfaValue> getDistinctsMap(DfaMemoryStateImpl state) { + MultiMap<DfaVariableValue, DfaValue> distincts = new MultiMap<DfaVariableValue, DfaValue>(); + for (UnorderedPair<EqClass> classPair : state.getDistinctClassPairs()) { + for (DfaValue value1 : classPair.first.getMemberValues()) { + value1 = DfaMemoryStateImpl.unwrap(value1); + for (DfaValue value2 : classPair.second.getMemberValues()) { + value2 = DfaMemoryStateImpl.unwrap(value2); + if (value1 instanceof DfaVariableValue) { + if (value2 instanceof DfaVariableValue || value2 instanceof DfaConstValue) { + distincts.putValue((DfaVariableValue)value1, value2); + } + } + if (value2 instanceof DfaVariableValue) { + if (value1 instanceof DfaVariableValue || value1 instanceof DfaConstValue) { + distincts.putValue((DfaVariableValue)value2, value1); + } + } + } + } + } + return distincts; + } + + private static List<UnorderedPair<DfaValue>> getEqPairs(DfaMemoryStateImpl state) { + Set<UnorderedPair<DfaValue>> eqPairs = ContainerUtil.newHashSet(); + for (EqClass eqClass : state.getNonTrivialEqClasses()) { + DfaConstValue constant = eqClass.findConstant(true); + List<DfaVariableValue> vars = eqClass.getVariables(); + for (int i = 0; i < vars.size(); i++) { + DfaVariableValue var = vars.get(i); + if (constant != null) { + eqPairs.add(createPair(var, constant)); + } + for (int j = i + 1; j < vars.size(); j++) { + eqPairs.add(createPair(var, vars.get(j))); + } + } + } + return ContainerUtil.newArrayList(eqPairs); + } + + private static UnorderedPair<DfaValue> createPair(DfaVariableValue var, DfaValue val) { + return new UnorderedPair<DfaValue>(var, val); + } +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java index e4631d66c79e..87aa89759798 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ValuableDataFlowRunner.java @@ -16,10 +16,14 @@ package com.intellij.codeInspection.dataFlow; +import com.intellij.codeInspection.dataFlow.value.DfaPsiType; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.psi.PsiExpression; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; /** * @author Gregory.Shrago @@ -36,9 +40,13 @@ public class ValuableDataFlowRunner extends DataFlowRunner { super(factory); } + MyDfaMemoryState(DfaMemoryStateImpl toCopy) { + super(toCopy); + } + @Override - protected DfaMemoryStateImpl createNew() { - return new MyDfaMemoryState(getFactory()); + public DfaMemoryStateImpl createCopy() { + return new MyDfaMemoryState(this); } @Override @@ -49,21 +57,37 @@ public class ValuableDataFlowRunner extends DataFlowRunner { } static class ValuableDfaVariableState extends DfaVariableState { - DfaValue myValue; - PsiExpression myExpression; + final DfaValue myValue; + final PsiExpression myExpression; private ValuableDfaVariableState(final DfaVariableValue psiVariable) { super(psiVariable); + myValue = null; + myExpression = null; + } + + private ValuableDfaVariableState(Set<DfaPsiType> instanceofValues, + Set<DfaPsiType> notInstanceofValues, + Nullness nullability, DfaValue value, PsiExpression expression) { + super(instanceofValues, notInstanceofValues, nullability); + myValue = value; + myExpression = expression; } - protected ValuableDfaVariableState(final ValuableDfaVariableState state) { - super(state); - myExpression = state.myExpression; + @Override + protected DfaVariableState createCopy(Set<DfaPsiType> instanceofValues, Set<DfaPsiType> notInstanceofValues, Nullness nullability) { + return new ValuableDfaVariableState(instanceofValues, notInstanceofValues, nullability, myValue, myExpression); } @Override - public void setValue(final DfaValue value) { - myValue = value; + public DfaVariableState withValue(@Nullable final DfaValue value) { + if (value == myValue) return this; + return new ValuableDfaVariableState(myInstanceofValues, myNotInstanceofValues, myNullability, value, myExpression); + } + + public ValuableDfaVariableState withExpression(@Nullable final PsiExpression expression) { + if (expression == myExpression) return this; + return new ValuableDfaVariableState(myInstanceofValues, myNotInstanceofValues, myNullability, myValue, expression); } @Override @@ -72,8 +96,25 @@ public class ValuableDataFlowRunner extends DataFlowRunner { } @Override - protected ValuableDfaVariableState clone() { - return new ValuableDfaVariableState(this); + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ValuableDfaVariableState)) return false; + if (!super.equals(o)) return false; + + ValuableDfaVariableState state = (ValuableDfaVariableState)o; + + if (myExpression != null ? !myExpression.equals(state.myExpression) : state.myExpression != null) return false; + if (myValue != null ? !myValue.equals(state.myValue) : state.myValue != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (myValue != null ? myValue.hashCode() : 0); + result = 31 * result + (myExpression != null ? myExpression.hashCode() : 0); + return result; } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java index dd2514c41f8e..6e64a6b86416 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BinopInstruction.java @@ -33,6 +33,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import static com.intellij.psi.JavaTokenType.*; @@ -41,11 +42,10 @@ public class BinopInstruction extends BranchingInstruction { private final IElementType myOperationSign; private final Project myProject; - public BinopInstruction(IElementType opSign, PsiElement psiAnchor, @NotNull Project project) { + public BinopInstruction(IElementType opSign, @Nullable PsiElement psiAnchor, @NotNull Project project) { + super(psiAnchor); myProject = project; myOperationSign = ourSignificantOperations.contains(opSign) ? opSign : null; - - setPsiAnchor(psiAnchor); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java index d1524fc42092..0f83d84afd28 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/BranchingInstruction.java @@ -27,17 +27,19 @@ package com.intellij.codeInspection.dataFlow.instructions; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLiteralExpression; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; public abstract class BranchingInstruction extends Instruction { private boolean myIsTrueReachable; private boolean myIsFalseReachable; - private boolean isConstTrue; - private PsiElement myExpression; + private final boolean isConstTrue; + private final PsiElement myExpression; - protected BranchingInstruction() { + protected BranchingInstruction(@Nullable PsiElement psiAnchor) { myIsTrueReachable = false; myIsFalseReachable = false; - setPsiAnchor(null); + myExpression = psiAnchor; + isConstTrue = psiAnchor != null && isBoolConst(psiAnchor); } public boolean isTrueReachable() { @@ -70,8 +72,4 @@ public abstract class BranchingInstruction extends Instruction { return "true".equals(text) || "false".equals(text); } - protected void setPsiAnchor(PsiElement psiAnchor) { - myExpression = psiAnchor; - isConstTrue = psiAnchor != null && isBoolConst(psiAnchor); - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java index 2b93e95045cb..212a02f361ad 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/ConditionalGotoInstruction.java @@ -33,9 +33,9 @@ public class ConditionalGotoInstruction extends BranchingInstruction { private final boolean myIsNegated; public ConditionalGotoInstruction(ControlFlow.ControlFlowOffset myOffset, boolean isNegated, PsiElement psiAnchor) { + super(psiAnchor); this.myOffset = myOffset; myIsNegated = isNegated; - setPsiAnchor(psiAnchor); } public boolean isNegated() { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java index 9d2a5944c138..dc1fd6fc6f74 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GosubInstruction.java @@ -27,15 +27,19 @@ public class GosubInstruction extends Instruction { mySubprogramOffset = subprogramOffset; } + public int getSubprogramOffset() { + return mySubprogramOffset.getInstructionOffset(); + } + @Override public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) { final int returnIndex = getIndex() + 1; stateBefore.pushOffset(returnIndex); - Instruction nextInstruction = runner.getInstruction(mySubprogramOffset.getInstructionOffset()); + Instruction nextInstruction = runner.getInstruction(getSubprogramOffset()); return new DfaInstructionState[] {new DfaInstructionState(nextInstruction, stateBefore)}; } public String toString() { - return "GOSUB: " + mySubprogramOffset.getInstructionOffset(); + return "GOSUB: " + getSubprogramOffset(); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java index 328609095456..c4400f771fcc 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/GotoInstruction.java @@ -34,14 +34,18 @@ public class GotoInstruction extends Instruction { this.myOffset = myOffset; } + public int getOffset() { + return myOffset.getInstructionOffset(); + } + @Override public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) { - Instruction nextInstruction = runner.getInstruction(myOffset.getInstructionOffset()); + Instruction nextInstruction = runner.getInstruction(getOffset()); return new DfaInstructionState[]{new DfaInstructionState(nextInstruction, stateBefore)}; } public String toString() { - return "GOTO: " + myOffset.getInstructionOffset(); + return "GOTO: " + getOffset(); } public void setOffset(final int offset) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java index 5514268233cd..096188ec1e8e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/Instruction.java @@ -28,18 +28,9 @@ import com.intellij.codeInspection.dataFlow.DataFlowRunner; import com.intellij.codeInspection.dataFlow.DfaInstructionState; import com.intellij.codeInspection.dataFlow.DfaMemoryState; import com.intellij.codeInspection.dataFlow.InstructionVisitor; -import com.intellij.openapi.progress.ProgressManager; - -import java.util.ArrayList; -import java.util.List; public abstract class Instruction { private int myIndex; - private final List<DfaMemoryState> myProcessedStates; - - protected Instruction() { - myProcessedStates = new ArrayList<DfaMemoryState>(); - } protected final DfaInstructionState[] nextInstruction(DataFlowRunner runner, DfaMemoryState stateBefore) { return new DfaInstructionState[] {new DfaInstructionState(runner.getInstruction(getIndex() + 1), stateBefore)}; @@ -47,23 +38,6 @@ public abstract class Instruction { public abstract DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor); - public boolean isMemoryStateProcessed(DfaMemoryState dfaMemState) { - for (DfaMemoryState state : myProcessedStates) { - ProgressManager.checkCanceled(); - if (dfaMemState.equals(state)) { - return true; - } - } - - return false; - } - - public boolean setMemoryStateProcessed(DfaMemoryState dfaMemState) { - if (myProcessedStates.size() > DataFlowRunner.MAX_STATES_PER_BRANCH) return false; - myProcessedStates.add(dfaMemState); - return true; - } - public void setIndex(int index) { myIndex = index; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaPsiType.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaPsiType.java new file mode 100644 index 000000000000..f58e44fc83e4 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaPsiType.java @@ -0,0 +1,67 @@ +/* + * 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.dataFlow.value; + +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * @author peter + */ +public class DfaPsiType { + private final PsiType myPsiType; + private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myAssignableCache; + private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myConvertibleCache; + + DfaPsiType(@NotNull PsiType psiType, Map<Pair<DfaPsiType, DfaPsiType>, Boolean> assignableCache, Map<Pair<DfaPsiType, DfaPsiType>, Boolean> convertibleCache) { + myPsiType = psiType; + myAssignableCache = assignableCache; + myConvertibleCache = convertibleCache; + } + + @NotNull + public PsiType getPsiType() { + return myPsiType; + } + + public boolean isAssignableFrom(DfaPsiType other) { + if (other == this) return true; + Pair<DfaPsiType, DfaPsiType> key = Pair.create(this, other); + Boolean result = myAssignableCache.get(key); + if (result == null) { + myAssignableCache.put(key, result = myPsiType.isAssignableFrom(other.myPsiType)); + } + return result; + } + + public boolean isConvertibleFrom(DfaPsiType other) { + if (other == this) return true; + Pair<DfaPsiType, DfaPsiType> key = Pair.create(this, other); + Boolean result = myConvertibleCache.get(key); + if (result == null) { + myConvertibleCache.put(key, result = myPsiType.isConvertibleFrom(other.myPsiType)); + } + return result; + } + + @Override + public String toString() { + return myPsiType.getPresentableText(); + } +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java index f7b648762365..193d3426ea29 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaTypeValue.java @@ -25,72 +25,51 @@ package com.intellij.codeInspection.dataFlow.value; import com.intellij.codeInspection.dataFlow.Nullness; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiKeyword; -import com.intellij.psi.PsiType; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Map; public class DfaTypeValue extends DfaValue { public static class Factory { - private final DfaTypeValue mySharedInstance; - private final HashMap<String,ArrayList<DfaTypeValue>> myStringToObject; + private final Map<DfaPsiType,ArrayList<DfaTypeValue>> myCache = ContainerUtil.newHashMap(); private final DfaValueFactory myFactory; Factory(DfaValueFactory factory) { myFactory = factory; - mySharedInstance = new DfaTypeValue(factory); - myStringToObject = new HashMap<String, ArrayList<DfaTypeValue>>(); } @NotNull - public DfaTypeValue createTypeValue(@NotNull PsiType type, @NotNull Nullness nullable) { - type = TypeConversionUtil.erasure(type); - mySharedInstance.myType = type; - mySharedInstance.myCanonicalText = StringUtil.notNullize(type.getCanonicalText(), PsiKeyword.NULL); - mySharedInstance.myNullness = nullable; - - String id = mySharedInstance.toString(); - ArrayList<DfaTypeValue> conditions = myStringToObject.get(id); + public DfaTypeValue createTypeValue(@NotNull DfaPsiType type, @NotNull Nullness nullness) { + ArrayList<DfaTypeValue> conditions = myCache.get(type); if (conditions == null) { conditions = new ArrayList<DfaTypeValue>(); - myStringToObject.put(id, conditions); + myCache.put(type, conditions); } else { for (DfaTypeValue aType : conditions) { - if (aType.hardEquals(mySharedInstance)) return aType; + if (aType.myNullness == nullness) return aType; } } - DfaTypeValue result = new DfaTypeValue(type, nullable, myFactory, mySharedInstance.myCanonicalText); + DfaTypeValue result = new DfaTypeValue(type, nullness, myFactory); conditions.add(result); - return result; + return new DfaTypeValue(type, nullness, myFactory); } - public DfaTypeValue createTypeValue(@NotNull PsiType type) { - return createTypeValue(type, Nullness.UNKNOWN); - } } - private PsiType myType; - private String myCanonicalText; + private DfaPsiType myType; private Nullness myNullness; - private DfaTypeValue(DfaValueFactory factory) { - super(factory); - } - - private DfaTypeValue(PsiType type, Nullness nullness, DfaValueFactory factory, String canonicalText) { + private DfaTypeValue(DfaPsiType type, Nullness nullness, DfaValueFactory factory) { super(factory); myType = type; myNullness = nullness; - myCanonicalText = canonicalText; } - public PsiType getType() { + public DfaPsiType getDfaType() { return myType; } @@ -102,23 +81,13 @@ public class DfaTypeValue extends DfaValue { return myNullness == Nullness.NOT_NULL; } - @NonNls - public String toString() { - return myCanonicalText + ", nullable=" + myNullness; + public Nullness getNullness() { + return myNullness; } - private boolean hardEquals(DfaTypeValue aType) { - return myCanonicalText.equals(aType.myCanonicalText) && myNullness == aType.myNullness && myType.equals(aType.myType); - } - - public boolean isAssignableFrom(DfaTypeValue dfaType) { - return dfaType != null && myType.isAssignableFrom(dfaType.myType); + @NonNls + public String toString() { + return myType + ", nullable=" + myNullness; } - public boolean isConvertibleFrom(DfaTypeValue dfaType) { - if (dfaType == null) return false; - assert myType.isValid() : "my type invalid"; - assert dfaType.myType.isValid() : " their type invalid"; - return myType.isConvertibleFrom(dfaType.myType); - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java index e19b3ce2125e..c78bfb149d6a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValue.java @@ -21,13 +21,7 @@ public class DfaValue { protected DfaValue(final DfaValueFactory factory) { myFactory = factory; - if (factory == null) { - myID = 0; - } - else { - myID = factory.createID(); - factory.registerValue(this); - } + myID = factory == null ? 0 : factory.registerValue(this); } public int getID() { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java index f6b900f9f85d..70cb578bd4fa 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaValueFactory.java @@ -25,24 +25,26 @@ package com.intellij.codeInspection.dataFlow.value; import com.intellij.codeInspection.dataFlow.Nullness; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; import com.intellij.psi.util.PsiTreeUtil; -import gnu.trove.TIntObjectHashMap; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class DfaValueFactory { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.value.DfaValueFactory"); +import java.util.List; +import java.util.Map; - private int myLastID; - private final TIntObjectHashMap<DfaValue> myValues; +public class DfaValueFactory { + private final List<DfaValue> myValues = ContainerUtil.newArrayList(); + private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myAssignableCache = ContainerUtil.newHashMap(); + private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myConvertibleCache = ContainerUtil.newHashMap(); + private final Map<PsiType, DfaPsiType> myDfaTypes = ContainerUtil.newHashMap(); public DfaValueFactory() { - myValues = new TIntObjectHashMap<DfaValue>(); - myLastID = 0; - + myValues.add(null); myVarFactory = new DfaVariableValue.Factory(this); myConstFactory = new DfaConstValue.Factory(this); myBoxedFactory = new DfaBoxedValue.Factory(this); @@ -52,17 +54,20 @@ public class DfaValueFactory { public DfaValue createTypeValue(@Nullable PsiType type, Nullness nullability) { if (type == null) return DfaUnknownValue.getInstance(); - return getTypeFactory().createTypeValue(type, nullability); + return getTypeFactory().createTypeValue(internType(type), nullability); } - int createID() { - myLastID++; - LOG.assertTrue(myLastID >= 0, "Overflow"); - return myLastID; + private DfaPsiType internType(@NotNull PsiType psiType) { + DfaPsiType dfaType = myDfaTypes.get(psiType); + if (dfaType == null) { + myDfaTypes.put(psiType, dfaType = new DfaPsiType(TypeConversionUtil.erasure(psiType), myAssignableCache, myConvertibleCache)); + } + return dfaType; } - void registerValue(DfaValue value) { - myValues.put(value.getID(), value); + int registerValue(DfaValue value) { + myValues.add(value); + return myValues.size() - 1; } public DfaValue getValue(int id) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index e522b8fb2c6f..fa2217a2918b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -30,6 +30,7 @@ import com.intellij.codeInspection.dataFlow.Nullness; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Trinity; import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; @@ -90,7 +91,7 @@ public class DfaVariableValue extends DfaValue { myIsNegated = isNegated; myQualifier = qualifier; myVarType = varType; - myTypeValue = varType == null ? null : myFactory.getTypeFactory().createTypeValue(varType, Nullness.UNKNOWN); + myTypeValue = varType == null ? null : (DfaTypeValue)myFactory.createTypeValue(varType, Nullness.UNKNOWN); } @Nullable @@ -132,7 +133,7 @@ public class DfaVariableValue extends DfaValue { private boolean hardEquals(PsiModifierListOwner psiVar, PsiType varType, boolean negated, DfaVariableValue qualifier) { return psiVar == myVariable && - Comparing.equal(varType, myVarType) && + Comparing.equal(TypeConversionUtil.erasure(varType), TypeConversionUtil.erasure(myVarType)) && negated == myIsNegated && (myQualifier == null ? qualifier == null : myQualifier.hardEquals(qualifier.getPsiVariable(), qualifier.getVariableType(), qualifier.isNegated(), qualifier.getQualifier())); @@ -143,10 +144,6 @@ public class DfaVariableValue extends DfaValue { return myQualifier; } - public boolean isViaMethods() { - return myVariable instanceof PsiMethod || myQualifier != null && myQualifier.isViaMethods(); - } - public Nullness getInherentNullability() { if (myInherentNullability != null) { return myInherentNullability; @@ -190,14 +187,12 @@ public class DfaVariableValue extends DfaValue { return Nullness.UNKNOWN; } - public boolean isLocalVariable() { - return myVariable instanceof PsiLocalVariable || myVariable instanceof PsiParameter; - } - public boolean isFlushableByCalls() { - if (isLocalVariable()) return false; - if (!myVariable.hasModifierProperty(PsiModifier.FINAL)) return true; - return myQualifier != null && myQualifier.isFlushableByCalls(); + if (myVariable instanceof PsiLocalVariable || myVariable instanceof PsiParameter) return false; + if (myVariable instanceof PsiVariable && myVariable.hasModifierProperty(PsiModifier.FINAL)) { + return myQualifier != null && myQualifier.isFlushableByCalls(); + } + return true; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java index 71fa80a2077f..c46bfb656769 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java @@ -223,7 +223,7 @@ public class RefJavaUtilImpl extends RefJavaUtil{ refParent = refParent.getOwner(); } - return (RefClass)refElement; + return refElement instanceof RefClass ? (RefClass)refElement : null; } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index f33c6e4a394a..15e6d5a04d9f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -255,7 +255,7 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { for (OverrideImplementsAnnotationsHandler each : Extensions.getExtensions(OverrideImplementsAnnotationsHandler.EP_NAME)) { for (String annotation : each.getAnnotations(project)) { if (moduleScope != null && facade.findClass(annotation, moduleScope) == null) continue; - if (AnnotationUtil.isAnnotated(overridden, annotation, false, false)) { + if (AnnotationUtil.isAnnotated(overridden, annotation, false, false) && !AnnotationUtil.isAnnotated(method, annotation, false, false)) { AddAnnotationPsiFix.removePhysicalAnnotations(method, each.annotationsToRemove(project, annotation)); AddAnnotationPsiFix.addPhysicalAnnotation(annotation, PsiNameValuePair.EMPTY_ARRAY, method.getModifierList()); } diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java index b3434ac20c10..9646ef9983ad 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/AnnotationParameterInfoHandler.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.intellij.util.text.CharArrayUtil; +import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -110,14 +111,18 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA @Override public void updateUI(final PsiAnnotationMethod p, final ParameterInfoUIContext context) { - @NonNls StringBuffer buffer = new StringBuffer(); + updateUIText(p, context); + } + + public static String updateUIText(PsiAnnotationMethod p, ParameterInfoUIContext context) { + @NonNls StringBuilder buffer = new StringBuilder(); int highlightStartOffset; int highlightEndOffset; buffer.append(p.getReturnType().getPresentableText()); buffer.append(" "); - highlightStartOffset = buffer.length(); + highlightStartOffset = XmlStringUtil.escapeString(buffer.toString()).length(); buffer.append(p.getName()); - highlightEndOffset = buffer.length(); + highlightEndOffset = XmlStringUtil.escapeString(buffer.toString()).length(); buffer.append("()"); if (p.getDefaultValue() != null) { @@ -125,8 +130,8 @@ public class AnnotationParameterInfoHandler implements ParameterInfoHandler<PsiA buffer.append(p.getDefaultValue().getText()); } - context.setupUIComponentPresentation(buffer.toString(), highlightStartOffset, highlightEndOffset, false, p.isDeprecated(), - false, context.getDefaultParameterColor()); + return context.setupUIComponentPresentation(buffer.toString(), highlightStartOffset, highlightEndOffset, false, p.isDeprecated(), + false, context.getDefaultParameterColor()); } private static PsiAnnotationMethod findAnnotationMethod(PsiFile file, int offset) { diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java index 7193cc96ffed..6fb2bc7458c8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java @@ -623,7 +623,7 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool { params.dataFlowToThis = true; params.scope = new AnalysisScope(new LocalSearchScope(scope), manager.getProject()); - SliceRootNode rootNode = new SliceRootNode(manager.getProject(), new DuplicateMap(), SliceManager.createRootUsage(argument, params)); + SliceRootNode rootNode = new SliceRootNode(manager.getProject(), new DuplicateMap(), SliceUsage.createRootUsage(argument, params)); Collection<? extends AbstractTreeNode> children = rootNode.getChildren().iterator().next().getChildren(); for (AbstractTreeNode child : children) { diff --git a/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java b/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java index fd624b1322d2..d6be007b9ba9 100644 --- a/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java +++ b/java/java-impl/src/com/intellij/ide/highlighter/JavaFileHighlighter.java @@ -107,11 +107,13 @@ public class JavaFileHighlighter extends SyntaxHighlighterBase { myLanguageLevel = languageLevel; } + @Override @NotNull public Lexer getHighlightingLexer() { return new JavaHighlightingLexer(myLanguageLevel); } + @Override @NotNull public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { return pack(ourMap1.get(tokenType), ourMap2.get(tokenType)); diff --git a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java index 402e7f54e0dc..f93464e952db 100644 --- a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java +++ b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java @@ -16,7 +16,7 @@ package com.intellij.ide.util.gotoByName; import com.intellij.ide.util.DefaultPsiElementCellRenderer; -import com.intellij.navigation.ChooseByNameContributor; +import com.intellij.navigation.ChooseByNameContributorEx; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -26,7 +26,9 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; import com.intellij.util.containers.HashSet; +import com.intellij.util.indexing.IdFilter; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -34,7 +36,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; -public class DefaultSymbolNavigationContributor implements ChooseByNameContributor { +public class DefaultSymbolNavigationContributor implements ChooseByNameContributorEx { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.DefaultSymbolNavigationContributor"); @Override @@ -91,6 +93,13 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut return false; } + public void processNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + PsiShortNamesCache cache = PsiShortNamesCache.getInstance(scope.getProject()); + cache.processAllClassNames(processor, scope, filter); + cache.processAllFieldNames(processor, scope, filter); + cache.processAllMethodNames(processor, scope, filter); + } + private static class MyComparator implements Comparator<PsiModifierListOwner>{ public static final MyComparator INSTANCE = new MyComparator(); diff --git a/java/java-impl/src/com/intellij/lang/java/JavaSyntaxHighlighterFactory.java b/java/java-impl/src/com/intellij/lang/java/JavaSyntaxHighlighterFactory.java index 918b8ff92098..7ee3d7bb35ca 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaSyntaxHighlighterFactory.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaSyntaxHighlighterFactory.java @@ -45,7 +45,7 @@ public class JavaSyntaxHighlighterFactory extends SyntaxHighlighterFactory imple */ @Nullable @Override - public SyntaxHighlighter create(FileType fileType, @Nullable Project project, @Nullable VirtualFile file) { + public SyntaxHighlighter create(@NotNull FileType fileType, @Nullable Project project, @Nullable VirtualFile file) { if (project != null && file != null) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile instanceof ClsFileImpl) { diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 7baff1405151..d392d7a7a481 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -263,6 +263,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo final Indent defaultChildIndent = getChildIndent(parent, indentOptions); if (defaultChildIndent != null) return defaultChildIndent; } + if (child.getTreeParent() instanceof PsiLambdaExpression && child instanceof PsiCodeBlock) { + return Indent.getNoneIndent(); + } return null; } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 1376f44c07ca..8f090b072d16 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -795,6 +795,12 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { { minSpaces = 1; minLineFeeds = 0; + if (myChild1 != null) { + ASTNode lastElement = myChild1; + while (lastElement.getLastChildNode() != null) lastElement = lastElement.getLastChildNode(); + //Not to place second statement on the same line with first one, if last ends with single line comment + if (lastElement instanceof PsiComment && lastElement.getElementType() == JavaTokenType.END_OF_LINE_COMMENT) minLineFeeds = 1; + } } myResult = Spacing.createSpacing(minSpaces, 0, minLineFeeds, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); } @@ -1086,7 +1092,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { createParenthSpace(mySettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_METHOD_PARENTHESES); } else if (myRole1 == ChildRole.COMMA) { - createSpaceInCode(true); + createSpaceInCode(mySettings.SPACE_AFTER_COMMA); } } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildBlockWrapFactory.java b/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildBlockWrapFactory.java index eeeae0eb3fdf..ad4d8c02c5f1 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildBlockWrapFactory.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildBlockWrapFactory.java @@ -19,6 +19,7 @@ import com.intellij.formatting.ASTBlock; import com.intellij.formatting.Wrap; import com.intellij.formatting.WrapType; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiPolyadicExpression; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.formatter.java.JavaFormatterUtil; @@ -83,7 +84,10 @@ public class JavaChildBlockWrapFactory { return Wrap.createWrap(settings.THROWS_LIST_WRAP, true); } else if (nodeType == JavaElementType.CODE_BLOCK) { - return Wrap.createWrap(Wrap.NORMAL, false); + if (settings.KEEP_SIMPLE_METHODS_IN_ONE_LINE && node.getPsi().getParent() instanceof PsiMethod && !node.textContains('\n')) { + return null; + } + return Wrap.createWrap(WrapType.NORMAL, false); } else if (JavaFormatterUtil.isAssignment(node)) { return Wrap.createWrap(settings.ASSIGNMENT_WRAP, true); diff --git a/java/java-impl/src/com/intellij/psi/impl/file/PsiJavaDirectoryFactory.java b/java/java-impl/src/com/intellij/psi/impl/file/PsiJavaDirectoryFactory.java index 7971d2f350d5..e92396e00a2f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/PsiJavaDirectoryFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/PsiJavaDirectoryFactory.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.file; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -23,6 +24,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; /** * @author yole @@ -34,6 +36,7 @@ public class PsiJavaDirectoryFactory extends PsiDirectoryFactory { myManager = manager; } + @NotNull @Override public PsiDirectory createDirectory(@NotNull final VirtualFile file) { return new PsiJavaDirectoryImpl(myManager, file); @@ -61,8 +64,10 @@ public class PsiJavaDirectoryFactory extends PsiDirectoryFactory { } @Override - public boolean isPackage(PsiDirectory directory) { - return ProjectRootManager.getInstance(myManager.getProject()).getFileIndex().getPackageNameByDirectory(directory.getVirtualFile()) != null; + public boolean isPackage(@NotNull PsiDirectory directory) { + ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex(); + VirtualFile virtualFile = directory.getVirtualFile(); + return fileIndex.isUnderSourceRootOfType(virtualFile, JavaModuleSourceRootTypes.SOURCES) && fileIndex.getPackageNameByDirectory(virtualFile) != null; } @Override diff --git a/java/java-impl/src/com/intellij/psi/impl/search/JavaIndexPatternBuilder.java b/java/java-impl/src/com/intellij/psi/impl/search/JavaIndexPatternBuilder.java index 379486347cb9..f404c401ae6f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/JavaIndexPatternBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/JavaIndexPatternBuilder.java @@ -24,6 +24,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlTokenType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -35,7 +36,7 @@ public class JavaIndexPatternBuilder implements IndexPatternBuilder { @Override @Nullable - public Lexer getIndexingLexer(final PsiFile file) { + public Lexer getIndexingLexer(@NotNull final PsiFile file) { if (file instanceof PsiJavaFile && !(file instanceof JspFile)) { return JavaParserDefinition.createLexer(((PsiJavaFile)file).getLanguageLevel()); } @@ -44,7 +45,7 @@ public class JavaIndexPatternBuilder implements IndexPatternBuilder { @Override @Nullable - public TokenSet getCommentTokenSet(final PsiFile file) { + public TokenSet getCommentTokenSet(@NotNull final PsiFile file) { if (file instanceof PsiJavaFile && !(file instanceof ServerPageFile)) { return TokenSet.orSet(StdTokenSets.COMMENT_BIT_SET, XML_COMMENT_BIT_SET, JavaDocTokenType.ALL_JAVADOC_TOKENS, XML_DATA_CHARS); } diff --git a/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java b/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java index 6011081b0051..57539ae07de0 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * 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. @@ -32,13 +32,14 @@ import com.intellij.psi.jsp.JspFile; import com.intellij.psi.jsp.JspTokenType; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; /** * @author yole */ public class JspIndexPatternBuilder implements IndexPatternBuilder { @Override - public Lexer getIndexingLexer(final PsiFile file) { + public Lexer getIndexingLexer(@NotNull final PsiFile file) { if (JspPsiUtil.isInJspFile(file)) { EditorHighlighter highlighter = null; @@ -67,7 +68,7 @@ public class JspIndexPatternBuilder implements IndexPatternBuilder { } @Override - public TokenSet getCommentTokenSet(final PsiFile file) { + public TokenSet getCommentTokenSet(@NotNull final PsiFile file) { final JspFile jspFile = JspPsiUtil.getJspFile(file); TokenSet commentTokens = TokenSet.orSet(JavaIndexPatternBuilder.XML_COMMENT_BIT_SET, StdTokenSets.COMMENT_BIT_SET); final ParserDefinition parserDefinition = diff --git a/java/java-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java b/java/java-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java index 92068c2c0d9a..894b88b5d11e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/LexerEditorHighlighterLexer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.psi.tree.IElementType; import com.intellij.util.text.CharSequenceSubSequence; +import org.jetbrains.annotations.NotNull; /** * @author Sergey Evdokimov @@ -38,7 +39,7 @@ public class LexerEditorHighlighterLexer extends LexerBase { } @Override - public void start(CharSequence buffer, int startOffset, int endOffset, int state) { + public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int state) { if (myAlreadyInitializedHighlighter) { this.buffer = buffer; start = startOffset; @@ -75,6 +76,7 @@ public class LexerEditorHighlighterLexer extends LexerBase { iterator.advance(); } + @NotNull @Override public CharSequence getBufferSequence() { return buffer; diff --git a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java index 8c4f926900f5..11c77dd05cb1 100644 --- a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsDialog.java @@ -87,6 +87,8 @@ public class EncapsulateFieldsDialog extends RefactoringDialog implements Encaps private final JRadioButton myRbAccessorPackageLocal = new JRadioButton(); private DocCommentPanel myJavadocPolicy; + private boolean myCbUseAccessorWhenAccessibleValue; + { myRbAccessorPackageLocal.setFocusable(false); myRbAccessorPrivate.setFocusable(false); @@ -270,13 +272,23 @@ public class EncapsulateFieldsDialog extends RefactoringDialog implements Encaps myCbEncapsulateSet.addActionListener(checkboxListener); myRbFieldAsIs.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { - myCbUseAccessorsWhenAccessible.setEnabled(!myRbFieldAsIs.isSelected()); + if (myRbFieldAsIs.isSelected()) { + myCbUseAccessorWhenAccessibleValue = myCbUseAccessorsWhenAccessible.isSelected(); + + myCbUseAccessorsWhenAccessible.setSelected(true); + myCbUseAccessorsWhenAccessible.setEnabled(false); + } + else { + myCbUseAccessorsWhenAccessible.setEnabled(true); + myCbUseAccessorsWhenAccessible.setSelected(myCbUseAccessorWhenAccessibleValue); + } } } ); myCbUseAccessorsWhenAccessible.setSelected( JavaRefactoringSettings.getInstance().ENCAPSULATE_FIELDS_USE_ACCESSORS_WHEN_ACCESSIBLE ); + myCbUseAccessorWhenAccessibleValue = myCbUseAccessorsWhenAccessible.isSelected(); myRbFieldPrivate.setSelected(true); myRbAccessorPublic.setSelected(true); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index eee40ea2d34c..c8007a344815 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -330,7 +330,7 @@ public class ExtractMethodProcessor implements MatchProvider { } private boolean isNotNull(PsiVariable outputVariable) { - final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(false); + final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(); final PsiCodeBlock block = myElementFactory.createCodeBlock(); for (PsiElement element : myElements) { block.add(element); diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassDialog.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassDialog.java index 24dd3cff4ee5..ca324a02a25f 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractClassDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -261,40 +261,34 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi protected JComponent createCenterPanel() { final JPanel panel = new JPanel(new BorderLayout()); - final MemberSelectionPanel memberSelectionPanel = - new MemberSelectionPanel(RefactorJBundle.message("members.to.extract.label"), memberInfo, "As enum") { - @Override - protected MemberSelectionTable createMemberSelectionTable(final List<MemberInfo> memberInfo, String abstractColumnHeader) { - return new MemberSelectionTable(memberInfo, abstractColumnHeader) { - @Nullable - @Override - protected Object getAbstractColumnValue(MemberInfo memberInfo) { - if (isExtractAsEnum()) { - final PsiMember member = memberInfo.getMember(); - if (isConstantField(member)) { - return Boolean.valueOf(enumConstants.contains(memberInfo)); - } - } - return null; - } - - @Override - protected boolean isAbstractColumnEditable(int rowIndex) { - final MemberInfo info = memberInfo.get(rowIndex); - if (info.isChecked()) { - final PsiMember member = info.getMember(); - if (isConstantField(member)) { - if (enumConstants.isEmpty()) return true; - final MemberInfo currentEnumConstant = enumConstants.get(0); - if (((PsiField)currentEnumConstant.getMember()).getType().equals(((PsiField)member).getType())) return true; - } - } - return false; - } - }; + final MemberSelectionTable table = new MemberSelectionTable(memberInfo, "As enum") { + @Nullable + @Override + protected Object getAbstractColumnValue(MemberInfo memberInfo) { + if (isExtractAsEnum()) { + final PsiMember member = memberInfo.getMember(); + if (isConstantField(member)) { + return Boolean.valueOf(enumConstants.contains(memberInfo)); + } } - }; - final MemberSelectionTable table = memberSelectionPanel.getTable(); + return null; + } + + @Override + protected boolean isAbstractColumnEditable(int rowIndex) { + final MemberInfo info = memberInfo.get(rowIndex); + if (info.isChecked()) { + final PsiMember member = info.getMember(); + if (isConstantField(member)) { + if (enumConstants.isEmpty()) return true; + final MemberInfo currentEnumConstant = enumConstants.get(0); + if (((PsiField)currentEnumConstant.getMember()).getType().equals(((PsiField)member).getType())) return true; + } + } + return false; + } + }; + table.setMemberInfoModel(new DelegatingMemberInfoModel<PsiMember, MemberInfo>(table.getMemberInfoModel()) { @Override @@ -342,6 +336,10 @@ class ExtractClassDialog extends RefactoringDialog implements MemberInfoChangeLi return cause; } }); + + final MemberSelectionPanelBase<PsiMember, MemberInfo, MemberSelectionTable> memberSelectionPanel = + new MemberSelectionPanelBase<PsiMember, MemberInfo, MemberSelectionTable>(RefactorJBundle.message("members.to.extract.label"), table); + panel.add(memberSelectionPanel, BorderLayout.CENTER); table.addMemberInfoChangeListener(this); extractAsEnum.addActionListener(new ActionListener() { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java index 223a180a7914..dac214dd0803 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java @@ -158,6 +158,9 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro } if (parent instanceof PsiExpression) { expression = (PsiExpression)parent; + if (expression.getText().equals(exprText)) { + return expression; + } } else { return null; } diff --git a/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java b/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java index 3cca01e51a3a..d0c10bafef21 100644 --- a/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -153,16 +153,17 @@ public class JavaPullUpHandler implements RefactoringActionHandler, PullUpDialog public boolean checkConflicts(final PullUpDialog dialog) { - final MemberInfo[] infos = dialog.getSelectedMemberInfos(); + final List<MemberInfo> infos = dialog.getSelectedMemberInfos(); + final MemberInfo[] memberInfos = infos.toArray(new MemberInfo[infos.size()]); final PsiClass superClass = dialog.getSuperClass(); - if (!checkWritable(superClass, infos)) return false; + if (!checkWritable(superClass, memberInfos)) return false; final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>(); if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { public void run() { final PsiDirectory targetDirectory = superClass.getContainingFile().getContainingDirectory(); final PsiPackage targetPackage = targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null; conflicts - .putAllValues(PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, targetPackage, targetDirectory, dialog.getContainmentVerifier())); + .putAllValues(PullUpConflictsUtil.checkConflicts(memberInfos, mySubclass, superClass, targetPackage, targetDirectory, dialog.getContainmentVerifier())); } }, RefactoringBundle.message("detecting.possible.conflicts"), true, myProject)) return false; if (!conflicts.isEmpty()) { diff --git a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpConflictsUtil.java b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpConflictsUtil.java index 4d5d8b5b1a59..801612a49055 100644 --- a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpConflictsUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpConflictsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -30,15 +30,16 @@ import com.intellij.psi.*; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.*; import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.classMembers.MemberInfoBase; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RefactoringConflictsUtil; import com.intellij.refactoring.util.RefactoringHierarchyUtil; import com.intellij.refactoring.util.RefactoringUIUtil; import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor; import com.intellij.refactoring.util.classMembers.InterfaceContainmentVerifier; -import com.intellij.refactoring.util.classMembers.MemberInfo; import com.intellij.usageView.UsageInfo; import com.intellij.util.VisibilityUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,16 +52,16 @@ import java.util.Set; public class PullUpConflictsUtil { private PullUpConflictsUtil() {} - public static MultiMap<PsiElement, String> checkConflicts(final MemberInfo[] infos, - PsiClass subclass, - @Nullable PsiClass superClass, - @NotNull PsiPackage targetPackage, - @NotNull PsiDirectory targetDirectory, - final InterfaceContainmentVerifier interfaceContainmentVerifier) { + public static MultiMap<PsiElement, String> checkConflicts(MemberInfoBase<? extends PsiMember>[] infos, + PsiClass subclass, + @Nullable PsiClass superClass, + @NotNull PsiPackage targetPackage, + @NotNull PsiDirectory targetDirectory, + final InterfaceContainmentVerifier interfaceContainmentVerifier) { return checkConflicts(infos, subclass, superClass, targetPackage, targetDirectory, interfaceContainmentVerifier, true); } - public static MultiMap<PsiElement, String> checkConflicts(final MemberInfo[] infos, + public static MultiMap<PsiElement, String> checkConflicts(final MemberInfoBase<? extends PsiMember>[] infos, @NotNull final PsiClass subclass, @Nullable PsiClass superClass, @NotNull final PsiPackage targetPackage, @@ -79,7 +80,7 @@ public class PullUpConflictsUtil { isInterfaceTarget = false; targetRepresentativeElement = targetDirectory; } - for (MemberInfo info : infos) { + for (MemberInfoBase<? extends PsiMember> info : infos) { PsiMember member = info.getMember(); if (member instanceof PsiMethod) { if (!info.isToAbstract() && !isInterfaceTarget) { @@ -129,15 +130,15 @@ public class PullUpConflictsUtil { movedMembers2Super? new ConflictingUsagesOfSubClassMembers(member, movedMembers, abstractMethods, subclass, superClass, superClass != null ? null : targetPackage, conflicts, interfaceContainmentVerifier) - : new ConflictingUsagesOfSuperClassMemebers(member, subclass, targetPackage, movedMembers, conflicts); + : new ConflictingUsagesOfSuperClassMembers(member, subclass, targetPackage, movedMembers, conflicts); member.accept(visitor); } checkModuleConflictsList.add(member); } for (final PsiMethod method : abstractMethods) { - checkModuleConflictsList.add(method.getParameterList()); - checkModuleConflictsList.add(method.getReturnTypeElement()); - checkModuleConflictsList.add(method.getTypeParameterList()); + ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getParameterList()); + ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getReturnTypeElement()); + ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getTypeParameterList()); } RefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList, new UsageInfo[0], targetRepresentativeElement, conflicts); @@ -190,8 +191,8 @@ public class PullUpConflictsUtil { return conflicts; } - private static void checkInterfaceTarget(MemberInfo[] infos, MultiMap<PsiElement, String> conflictsList) { - for (MemberInfo info : infos) { + private static void checkInterfaceTarget(MemberInfoBase<? extends PsiMember>[] infos, MultiMap<PsiElement, String> conflictsList) { + for (MemberInfoBase<? extends PsiMember> info : infos) { PsiElement member = info.getMember(); if (member instanceof PsiField || member instanceof PsiClass) { @@ -214,9 +215,9 @@ public class PullUpConflictsUtil { } private static void checkSuperclassMembers(PsiClass superClass, - MemberInfo[] infos, + MemberInfoBase<? extends PsiMember>[] infos, MultiMap<PsiElement, String> conflictsList) { - for (MemberInfo info : infos) { + for (MemberInfoBase<? extends PsiMember> info : infos) { PsiMember member = info.getMember(); boolean isConflict = false; if (member instanceof PsiField) { @@ -268,7 +269,7 @@ public class PullUpConflictsUtil { return false; } - private static class ConflictingUsagesOfSuperClassMemebers extends ClassMemberReferencesVisitor { + private static class ConflictingUsagesOfSuperClassMembers extends ClassMemberReferencesVisitor { private PsiMember myMember; private PsiClass mySubClass; @@ -276,10 +277,10 @@ public class PullUpConflictsUtil { private Set<PsiMember> myMovedMembers; private MultiMap<PsiElement, String> myConflicts; - public ConflictingUsagesOfSuperClassMemebers(PsiMember member, PsiClass aClass, - PsiPackage targetPackage, - Set<PsiMember> movedMembers, - MultiMap<PsiElement, String> conflicts) { + public ConflictingUsagesOfSuperClassMembers(PsiMember member, PsiClass aClass, + PsiPackage targetPackage, + Set<PsiMember> movedMembers, + MultiMap<PsiElement, String> conflicts) { super(aClass); myMember = member; mySubClass = aClass; diff --git a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java index 526262efaedc..6af5d471aae8 100644 --- a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpDialog.java @@ -28,43 +28,40 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.classMembers.MemberInfoChange; +import com.intellij.refactoring.classMembers.MemberInfoModel; +import com.intellij.refactoring.ui.AbstractMemberSelectionTable; import com.intellij.refactoring.ui.ClassCellRenderer; import com.intellij.refactoring.ui.DocCommentPanel; -import com.intellij.refactoring.ui.MemberSelectionPanel; -import com.intellij.refactoring.ui.RefactoringDialog; +import com.intellij.refactoring.ui.MemberSelectionTable; import com.intellij.refactoring.util.DocCommentPolicy; import com.intellij.refactoring.util.RefactoringHierarchyUtil; import com.intellij.refactoring.util.classMembers.InterfaceContainmentVerifier; import com.intellij.refactoring.util.classMembers.MemberInfo; import com.intellij.refactoring.util.classMembers.MemberInfoStorage; import com.intellij.refactoring.util.classMembers.UsesAndInterfacesDependencyMemberInfoModel; -import com.intellij.usageView.UsageViewUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.ArrayList; import java.util.List; /** * @author dsl * Date: 18.06.2002 */ -public class PullUpDialog extends RefactoringDialog { +public class PullUpDialog extends PullUpDialogBase<MemberInfoStorage, MemberInfo, PsiMember, PsiClass> { private final Callback myCallback; - private MemberSelectionPanel myMemberSelectionPanel; - private MyMemberInfoModel myMemberInfoModel; - private final PsiClass myClass; - private final List<PsiClass> mySuperClasses; - private final MemberInfoStorage myMemberInfoStorage; - private List<MemberInfo> myMemberInfos; private DocCommentPanel myJavaDocPanel; - private JComboBox myClassCombo; + + private final InterfaceContainmentVerifier myInterfaceContainmentVerifier = new InterfaceContainmentVerifier() { + public boolean checkedInterfacesContain(PsiMethod psiMethod) { + return PullUpHelper.checkedInterfacesContain(myMemberInfos, psiMethod); + } + }; + private static final String PULL_UP_STATISTICS_KEY = "pull.up##"; public interface Callback { @@ -72,42 +69,16 @@ public class PullUpDialog extends RefactoringDialog { } public PullUpDialog(Project project, PsiClass aClass, List<PsiClass> superClasses, MemberInfoStorage memberInfoStorage, Callback callback) { - super(project, true); - myClass = aClass; - mySuperClasses = superClasses; - myMemberInfoStorage = memberInfoStorage; - myMemberInfos = myMemberInfoStorage.getClassMemberInfos(aClass); + super(project, aClass, superClasses, memberInfoStorage, JavaPullUpHandler.REFACTORING_NAME); myCallback = callback; - setTitle(JavaPullUpHandler.REFACTORING_NAME); - init(); } - @Nullable - public PsiClass getSuperClass() { - if (myClassCombo != null) { - return (PsiClass) myClassCombo.getSelectedItem(); - } - else { - return null; - } - } - public int getJavaDocPolicy() { return myJavaDocPanel.getPolicy(); } - public MemberInfo[] getSelectedMemberInfos() { - ArrayList<MemberInfo> list = new ArrayList<MemberInfo>(myMemberInfos.size()); - for (MemberInfo info : myMemberInfos) { - if (info.isChecked() && myMemberInfoModel.isMemberEnabled(info)) { - list.add(info); - } - } - return list.toArray(new MemberInfo[list.size()]); - } - protected String getDimensionServiceKey() { return "#com.intellij.refactoring.memberPullUp.PullUpDialog"; } @@ -116,51 +87,23 @@ public class PullUpDialog extends RefactoringDialog { return myInterfaceContainmentVerifier; } - protected JComponent createNorthPanel() { - JPanel panel = new JPanel(); - - panel.setLayout(new GridBagLayout()); - GridBagConstraints gbConstraints = new GridBagConstraints(); - - gbConstraints.insets = new Insets(4, 0, 4, 8); - gbConstraints.weighty = 1; - gbConstraints.weightx = 1; - gbConstraints.gridy = 0; - gbConstraints.gridwidth = GridBagConstraints.REMAINDER; - gbConstraints.fill = GridBagConstraints.BOTH; - gbConstraints.anchor = GridBagConstraints.WEST; - final JLabel classComboLabel = new JLabel(); - panel.add(classComboLabel, gbConstraints); - - myClassCombo = new JComboBox(mySuperClasses.toArray()); - myClassCombo.setRenderer(new ClassCellRenderer(myClassCombo.getRenderer())); - classComboLabel.setText(RefactoringBundle.message("pull.up.members.to", UsageViewUtil.getLongName(myClass))); - classComboLabel.setLabelFor(myClassCombo); - final PsiClass preselection = getPreselection(); - int indexToSelect = 0; - if (preselection != null) { - indexToSelect = mySuperClasses.indexOf(preselection); - } - myClassCombo.setSelectedIndex(indexToSelect); - myClassCombo.addItemListener(new ItemListener() { + @Override + protected void initClassCombo(JComboBox classCombo) { + classCombo.setRenderer(new ClassCellRenderer(classCombo.getRenderer())); + classCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { - updateMemberInfo(); if (myMemberSelectionPanel != null) { - myMemberInfoModel.setSuperClass(getSuperClass()); + ((MyMemberInfoModel)myMemberInfoModel).setSuperClass(getSuperClass()); myMemberSelectionPanel.getTable().setMemberInfos(myMemberInfos); myMemberSelectionPanel.getTable().fireExternalDataChange(); } } } }); - gbConstraints.gridy++; - panel.add(myClassCombo, gbConstraints); - - return panel; } - private PsiClass getPreselection() { + protected PsiClass getPreselection() { PsiClass preselection = RefactoringHierarchyUtil.getNearestBaseClass(myClass, false); final String statKey = PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(); @@ -185,15 +128,6 @@ public class PullUpDialog extends RefactoringDialog { HelpManager.getInstance().invokeHelp(HelpID.MEMBERS_PULL_UP); } - private void updateMemberInfo() { - final PsiClass targetClass = (PsiClass) myClassCombo.getSelectedItem(); - myMemberInfos = myMemberInfoStorage.getIntermediateMemberInfosList(targetClass); - /*Set duplicate = myMemberInfoStorage.getDuplicatedMemberInfos(targetClass); - for (Iterator iterator = duplicate.getSectionsIterator(); getSectionsIterator.hasNext();) { - ((MemberInfo) iterator.next()).setChecked(false); - }*/ - } - protected void doAction() { if (!myCallback.checkConflicts(this)) return; JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC = myJavaDocPanel.getPolicy(); @@ -203,21 +137,15 @@ public class PullUpDialog extends RefactoringDialog { StatisticsManager .getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), name)); } - - invokeRefactoring(new PullUpHelper(myClass, superClass, getSelectedMemberInfos(), + + List<MemberInfo> infos = getSelectedMemberInfos(); + invokeRefactoring(new PullUpHelper(myClass, superClass, infos.toArray(new MemberInfo[infos.size()]), new DocCommentPolicy(getJavaDocPolicy()))); close(OK_EXIT_CODE); } - protected JComponent createCenterPanel() { - JPanel panel = new JPanel(new BorderLayout()); - myMemberSelectionPanel = new MemberSelectionPanel(RefactoringBundle.message("members.to.be.pulled.up"), myMemberInfos, RefactoringBundle.message("make.abstract")); - myMemberInfoModel = new MyMemberInfoModel(); - myMemberInfoModel.memberInfoChanged(new MemberInfoChange<PsiMember, MemberInfo>(myMemberInfos)); - myMemberSelectionPanel.getTable().setMemberInfoModel(myMemberInfoModel); - myMemberSelectionPanel.getTable().addMemberInfoChangeListener(myMemberInfoModel); - panel.add(myMemberSelectionPanel, BorderLayout.CENTER); - + @Override + protected void addCustomElementsToCentralPanel(JPanel panel) { myJavaDocPanel = new DocCommentPanel(RefactoringBundle.message("javadoc.for.abstracts")); myJavaDocPanel.setPolicy(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC); boolean hasJavadoc = false; @@ -233,14 +161,17 @@ public class PullUpDialog extends RefactoringDialog { } UIUtil.setEnabled(myJavaDocPanel, hasJavadoc, true); panel.add(myJavaDocPanel, BorderLayout.EAST); - return panel; } - private final InterfaceContainmentVerifier myInterfaceContainmentVerifier = - new InterfaceContainmentVerifier() { - public boolean checkedInterfacesContain(PsiMethod psiMethod) { - return PullUpHelper.checkedInterfacesContain(myMemberInfos, psiMethod); - } - }; + + @Override + protected AbstractMemberSelectionTable<PsiMember, MemberInfo> createMemberSelectionTable(List<MemberInfo> infos) { + return new MemberSelectionTable(infos, RefactoringBundle.message("make.abstract")); + } + + @Override + protected MemberInfoModel<PsiMember, MemberInfo> createMemberInfoModel() { + return new MyMemberInfoModel(); + } private class MyMemberInfoModel extends UsesAndInterfacesDependencyMemberInfoModel { public MyMemberInfoModel() { @@ -296,11 +227,9 @@ public class PullUpDialog extends RefactoringDialog { PsiClass currentSuperClass = getSuperClass(); if (currentSuperClass != null && currentSuperClass.isInterface()) { - PsiElement element = member.getMember(); - if (element instanceof PsiModifierListOwner) { - if (((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC)) { - return super.checkForProblems(member); - } + PsiMember element = member.getMember(); + if (element.hasModifierProperty(PsiModifier.STATIC)) { + return super.checkForProblems(member); } return OK; } diff --git a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpHelper.java b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpHelper.java index ea230e3517ce..bde3f6cfd5f2 100644 --- a/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpHelper.java +++ b/java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpHelper.java @@ -47,6 +47,7 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.*; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.classMembers.MemberInfoBase; import com.intellij.refactoring.listeners.JavaRefactoringListenerManager; import com.intellij.refactoring.listeners.impl.JavaRefactoringListenerManagerImpl; import com.intellij.refactoring.util.*; @@ -67,7 +68,7 @@ import java.util.*; public class PullUpHelper extends BaseRefactoringProcessor{ private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.memberPullUp.PullUpHelper"); - private static final Key<Boolean> PRESERVE_QUALIFIER = Key.<Boolean>create("PRESERVE_QUALIFIER"); + private static final Key<Boolean> PRESERVE_QUALIFIER = Key.create("PRESERVE_QUALIFIER"); private final PsiClass mySourceClass; private final PsiClass myTargetSuperClass; private final boolean myIsTargetInterface; @@ -169,158 +170,22 @@ public class PullUpHelper extends BaseRefactoringProcessor{ // correct private member visibility for (MemberInfo info : myMembersToMove) { if (info.getMember() instanceof PsiClass && info.getOverrides() != null) continue; - PsiModifierListOwner modifierListOwner = info.getMember(); - if (myIsTargetInterface) { - PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PUBLIC, true); - } - else if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) { - if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, movedMembers, myTargetSuperClass, mySourceClass)) { - PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true); - } - if (modifierListOwner instanceof PsiClass) { - modifierListOwner.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitMethod(PsiMethod method) { - check(method); - } - - @Override - public void visitField(PsiField field) { - check(field); - } - - @Override - public void visitClass(PsiClass aClass) { - check(aClass); - super.visitClass(aClass); - } - - private void check(PsiMember member) { - if (member.hasModifierProperty(PsiModifier.PRIVATE)) { - if (willBeUsedInSubclass(member, movedMembers, myTargetSuperClass, mySourceClass)) { - PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true); - } - } - } - }); - } - } + setCorrectVisibility(movedMembers, info); ChangeContextUtil.encodeContextInfo(info.getMember(), true); } final PsiSubstitutor substitutor = upDownSuperClassSubstitutor(); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); // do actual move for (MemberInfo info : myMembersToMove) { if (info.getMember() instanceof PsiMethod) { - PsiMethod method = (PsiMethod)info.getMember(); - PsiMethod sibling = method; - PsiMethod anchor = null; - while (sibling != null) { - sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class); - if (sibling != null) { - anchor = MethodSignatureUtil - .findMethodInSuperClassBySignatureInDerived(method.getContainingClass(), myTargetSuperClass, - sibling.getSignature(PsiSubstitutor.EMPTY), false); - if (anchor != null) { - break; - } - } - } - PsiMethod methodCopy = (PsiMethod)method.copy(); - if (method.findSuperMethods(myTargetSuperClass).length == 0) { - deleteOverrideAnnotationIfFound(methodCopy); - } - boolean isOriginalMethodAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT); - if (myIsTargetInterface || info.isToAbstract()) { - ChangeContextUtil.clearContextInfo(method); - - if (!info.isToAbstract() && !method.hasModifierProperty(PsiModifier.ABSTRACT) && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) { - //pull as default - RefactoringUtil.makeMethodDefault(methodCopy); - isOriginalMethodAbstract = true; - } else { - RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy); - } - - RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); - - myJavaDocPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract); - - final PsiMember movedElement = anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy); - CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject()); - if (styleSettings.INSERT_OVERRIDE_ANNOTATION) { - if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myTargetSuperClass.isInterface() || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) { - new AddAnnotationFix(Override.class.getName(), method).invoke(method.getProject(), null, mySourceClass.getContainingFile()); - } - } - if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myTargetSuperClass.isInterface()) { - if (isOriginalMethodAbstract) { - for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) { - deleteOverrideAnnotationIfFound(oMethod); - } - } - deleteOverrideAnnotationIfFound(method); - } - myMembersAfterMove.add(movedElement); - if (isOriginalMethodAbstract) { - method.delete(); - } - } - else { - if (isOriginalMethodAbstract) { - PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true); - } - RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); - fixReferencesToStatic(methodCopy, movedMembers); - final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false); - if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - superClassMethod.replace(methodCopy); - } - else { - final PsiMember movedElement = - anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy); - myMembersAfterMove.add(movedElement); - } - method.delete(); - } + doMoveMethod(movedMembers, substitutor, info); } else if (info.getMember() instanceof PsiField) { - PsiField field = (PsiField)info.getMember(); - field.normalizeDeclaration(); - RefactoringUtil.replaceMovedMemberTypeParameters(field, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); - fixReferencesToStatic(field, movedMembers); - if (myIsTargetInterface) { - PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true); - } - final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(field); - myMembersAfterMove.add(movedElement); - field.delete(); + doMoveField(movedMembers, substitutor, info); } else if (info.getMember() instanceof PsiClass) { - PsiClass aClass = (PsiClass)info.getMember(); - if (Boolean.FALSE.equals(info.getOverrides())) { - final PsiReferenceList sourceReferenceList = info.getSourceReferenceList(); - LOG.assertTrue(sourceReferenceList != null); - PsiJavaCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) ? - RefactoringUtil.removeFromReferenceList(sourceReferenceList, aClass) : - RefactoringUtil.findReferenceToClass(sourceReferenceList, aClass); - if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) { - RefactoringUtil.replaceMovedMemberTypeParameters(ref, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); - final PsiReferenceList referenceList = - myTargetSuperClass.isInterface() ? myTargetSuperClass.getExtendsList() : myTargetSuperClass.getImplementsList(); - assert referenceList != null; - referenceList.add(ref); - } - } - else { - RefactoringUtil.replaceMovedMemberTypeParameters(aClass, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); - fixReferencesToStatic(aClass, movedMembers); - final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(aClass); - myMembersAfterMove.add(movedElement); - aClass.delete(); - } + doMoveClass(movedMembers, substitutor, info); } } @@ -357,6 +222,160 @@ public class PullUpHelper extends BaseRefactoringProcessor{ } } + private void setCorrectVisibility(final Set<PsiMember> movedMembers, MemberInfo info) { + PsiModifierListOwner modifierListOwner = info.getMember(); + if (myIsTargetInterface) { + PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PUBLIC, true); + } + else if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) { + if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, movedMembers, myTargetSuperClass, mySourceClass)) { + PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true); + } + if (modifierListOwner instanceof PsiClass) { + modifierListOwner.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitMethod(PsiMethod method) { + check(method); + } + + @Override + public void visitField(PsiField field) { + check(field); + } + + @Override + public void visitClass(PsiClass aClass) { + check(aClass); + super.visitClass(aClass); + } + + private void check(PsiMember member) { + if (member.hasModifierProperty(PsiModifier.PRIVATE)) { + if (willBeUsedInSubclass(member, movedMembers, myTargetSuperClass, mySourceClass)) { + PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true); + } + } + } + }); + } + } + } + + private void doMoveClass(Set<PsiMember> movedMembers, PsiSubstitutor substitutor, MemberInfo info) { + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + PsiClass aClass = (PsiClass)info.getMember(); + if (Boolean.FALSE.equals(info.getOverrides())) { + final PsiReferenceList sourceReferenceList = info.getSourceReferenceList(); + LOG.assertTrue(sourceReferenceList != null); + PsiJavaCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) ? + RefactoringUtil.removeFromReferenceList(sourceReferenceList, aClass) : + RefactoringUtil.findReferenceToClass(sourceReferenceList, aClass); + if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) { + RefactoringUtil.replaceMovedMemberTypeParameters(ref, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); + final PsiReferenceList referenceList = + myTargetSuperClass.isInterface() ? myTargetSuperClass.getExtendsList() : myTargetSuperClass.getImplementsList(); + assert referenceList != null; + referenceList.add(ref); + } + } + else { + RefactoringUtil.replaceMovedMemberTypeParameters(aClass, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); + fixReferencesToStatic(aClass, movedMembers); + final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(aClass); + myMembersAfterMove.add(movedElement); + aClass.delete(); + } + } + + private void doMoveField(Set<PsiMember> movedMembers, PsiSubstitutor substitutor, MemberInfo info) { + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + PsiField field = (PsiField)info.getMember(); + field.normalizeDeclaration(); + RefactoringUtil.replaceMovedMemberTypeParameters(field, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); + fixReferencesToStatic(field, movedMembers); + if (myIsTargetInterface) { + PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true); + } + final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(field); + myMembersAfterMove.add(movedElement); + field.delete(); + } + + private void doMoveMethod(Set<PsiMember> movedMembers, PsiSubstitutor substitutor, MemberInfo info) { + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); + PsiMethod method = (PsiMethod)info.getMember(); + PsiMethod sibling = method; + PsiMethod anchor = null; + while (sibling != null) { + sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class); + if (sibling != null) { + anchor = MethodSignatureUtil + .findMethodInSuperClassBySignatureInDerived(method.getContainingClass(), myTargetSuperClass, + sibling.getSignature(PsiSubstitutor.EMPTY), false); + if (anchor != null) { + break; + } + } + } + PsiMethod methodCopy = (PsiMethod)method.copy(); + if (method.findSuperMethods(myTargetSuperClass).length == 0) { + deleteOverrideAnnotationIfFound(methodCopy); + } + boolean isOriginalMethodAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT); + if (myIsTargetInterface || info.isToAbstract()) { + ChangeContextUtil.clearContextInfo(method); + + if (!info.isToAbstract() && !method.hasModifierProperty(PsiModifier.ABSTRACT) && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) { + //pull as default + RefactoringUtil.makeMethodDefault(methodCopy); + isOriginalMethodAbstract = true; + } else { + RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy); + } + + RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); + + myJavaDocPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract); + + final PsiMember movedElement = anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy); + CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject()); + if (styleSettings.INSERT_OVERRIDE_ANNOTATION) { + if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myTargetSuperClass.isInterface() || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) { + new AddAnnotationFix(Override.class.getName(), method).invoke(method.getProject(), null, mySourceClass.getContainingFile()); + } + } + if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myTargetSuperClass.isInterface()) { + if (isOriginalMethodAbstract) { + for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) { + deleteOverrideAnnotationIfFound(oMethod); + } + } + deleteOverrideAnnotationIfFound(method); + } + myMembersAfterMove.add(movedElement); + if (isOriginalMethodAbstract) { + method.delete(); + } + } + else { + if (isOriginalMethodAbstract) { + PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true); + } + RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory); + fixReferencesToStatic(methodCopy, movedMembers); + final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false); + if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + superClassMethod.replace(methodCopy); + } + else { + final PsiMember movedElement = + anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy); + myMembersAfterMove.add(movedElement); + } + method.delete(); + } + } + private PsiSubstitutor upDownSuperClassSubstitutor() { PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(mySourceClass)) { @@ -909,8 +928,8 @@ public class PullUpHelper extends BaseRefactoringProcessor{ return false; } - public static boolean checkedInterfacesContain(Collection<MemberInfo> memberInfos, PsiMethod psiMethod) { - for (MemberInfo memberInfo : memberInfos) { + public static boolean checkedInterfacesContain(Collection<? extends MemberInfoBase<? extends PsiMember>> memberInfos, PsiMethod psiMethod) { + for (MemberInfoBase<? extends PsiMember> memberInfo : memberInfos) { if (memberInfo.isChecked() && memberInfo.getMember() instanceof PsiClass && Boolean.FALSE.equals(memberInfo.getOverrides())) { diff --git a/java/java-impl/src/com/intellij/refactoring/ui/AbstractMemberSelectionPanel.java b/java/java-impl/src/com/intellij/refactoring/ui/AbstractMemberSelectionPanel.java deleted file mode 100644 index 0e9397ad40f2..000000000000 --- a/java/java-impl/src/com/intellij/refactoring/ui/AbstractMemberSelectionPanel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.intellij.refactoring.ui; - -import com.intellij.psi.PsiElement; -import com.intellij.refactoring.classMembers.MemberInfoBase; - -import javax.swing.*; - -/** - * Nikolay.Tropin - * 8/20/13 - */ -public abstract class AbstractMemberSelectionPanel<T extends PsiElement, M extends MemberInfoBase<T>> extends JPanel { - public abstract AbstractMemberSelectionTable<T, M> getTable(); -} diff --git a/java/java-impl/src/com/intellij/refactoring/ui/MemberSelectionPanel.java b/java/java-impl/src/com/intellij/refactoring/ui/MemberSelectionPanel.java index c503a86e9c39..28e0a8800aba 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/MemberSelectionPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/MemberSelectionPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. diff --git a/java/java-impl/src/com/intellij/slicer/DuplicateMap.java b/java/java-impl/src/com/intellij/slicer/DuplicateMap.java index a57dc5f31cb7..426efd11a50a 100644 --- a/java/java-impl/src/com/intellij/slicer/DuplicateMap.java +++ b/java/java-impl/src/com/intellij/slicer/DuplicateMap.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.usageView.UsageInfo; import gnu.trove.THashMap; import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -43,7 +44,7 @@ public class DuplicateMap { }; private final Map<SliceUsage, SliceNode> myDuplicates = new THashMap<SliceUsage, SliceNode>(USAGE_INFO_EQUALITY); - public SliceNode putNodeCheckDupe(final SliceNode node) { + public SliceNode putNodeCheckDupe(@NotNull final SliceNode node) { return ApplicationManager.getApplication().runReadAction(new Computable<SliceNode>() { @Override public SliceNode compute() { diff --git a/java/java-impl/src/com/intellij/slicer/MyColoredTreeCellRenderer.java b/java/java-impl/src/com/intellij/slicer/MyColoredTreeCellRenderer.java index 0e313733653c..c150e0fd8674 100644 --- a/java/java-impl/src/com/intellij/slicer/MyColoredTreeCellRenderer.java +++ b/java/java-impl/src/com/intellij/slicer/MyColoredTreeCellRenderer.java @@ -15,12 +15,20 @@ */ package com.intellij.slicer; +import org.jetbrains.annotations.NotNull; + import javax.swing.*; /** * @author cdr */ public interface MyColoredTreeCellRenderer { - void customizeCellRenderer(SliceUsageCellRenderer renderer, - JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus); + void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer, + @NotNull JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus); } diff --git a/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java b/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java index 106671f22652..8578c91b1a7a 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java +++ b/java/java-impl/src/com/intellij/slicer/SliceDereferenceUsage.java @@ -33,7 +33,7 @@ public class SliceDereferenceUsage extends SliceUsage { } @Override - public void processChildren(Processor<SliceUsage> processor) { + public void processChildren(@NotNull Processor<SliceUsage> processor) { // no children } diff --git a/java/java-impl/src/com/intellij/slicer/forward/SliceFUtil.java b/java/java-impl/src/com/intellij/slicer/SliceForwardUtil.java index ef701971c0d3..364b8539c012 100644 --- a/java/java-impl/src/com/intellij/slicer/forward/SliceFUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceForwardUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.slicer.forward; +package com.intellij.slicer; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; @@ -22,10 +22,6 @@ import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.slicer.SliceDereferenceUsage; -import com.intellij.slicer.SliceManager; -import com.intellij.slicer.SliceUsage; -import com.intellij.slicer.SliceUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import gnu.trove.THashSet; @@ -40,7 +36,7 @@ import java.util.Set; /** * @author cdr */ -public class SliceFUtil { +public class SliceForwardUtil { public static boolean processUsagesFlownFromThe(@NotNull PsiElement element, @NotNull final Processor<SliceUsage> processor, @NotNull final SliceUsage parent) { Pair<PsiElement, PsiSubstitutor> pair = getAssignmentTarget(element, parent); if (pair != null) { diff --git a/java/java-impl/src/com/intellij/slicer/SliceLeafValueClassNode.java b/java/java-impl/src/com/intellij/slicer/SliceLeafValueClassNode.java index 630d1cd483e4..e73da4154084 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceLeafValueClassNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceLeafValueClassNode.java @@ -44,8 +44,8 @@ public class SliceLeafValueClassNode extends SliceLeafValueRootNode { } @Override - public void customizeCellRenderer(SliceUsageCellRenderer renderer, - JTree tree, + public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer, + @NotNull JTree tree, Object value, boolean selected, boolean expanded, diff --git a/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java b/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java index a6a403053284..dee98f84da84 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceLeafValueRootNode.java @@ -40,7 +40,7 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe public SliceLeafValueRootNode(@NotNull Project project, PsiElement leafExpression, SliceNode root, List<SliceNode> children, SliceAnalysisParams params) { - super(project, new SliceUsage(leafExpression, params), root.targetEqualUsages); + super(project, SliceUsage.createRootUsage(leafExpression, params), root.targetEqualUsages); myCachedChildren = children; } @@ -69,8 +69,8 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe } @Override - public void customizeCellRenderer(SliceUsageCellRenderer renderer, - JTree tree, + public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer, + @NotNull JTree tree, Object value, boolean selected, boolean expanded, @@ -99,8 +99,9 @@ public class SliceLeafValueRootNode extends SliceNode implements MyColoredTreeCe @NotNull final SliceUsageCellRenderer renderer) { PsiFile file = element.getContainingFile(); List<TextChunk> result = new ArrayList<TextChunk>(); - ChunkExtractor.getExtractor(element.getContainingFile()).createTextChunks(usage, file.getText(), element.getTextRange().getStartOffset(), element.getTextRange().getEndOffset(), - false, result); + ChunkExtractor.getExtractor(element.getContainingFile()) + .createTextChunks(usage, file.getText(), element.getTextRange().getStartOffset(), element.getTextRange().getEndOffset(), + false, result); for (TextChunk chunk : result) { renderer.append(chunk.getText(), chunk.getSimpleAttributesIgnoreBackground()); diff --git a/java/java-impl/src/com/intellij/slicer/SliceManager.java b/java/java-impl/src/com/intellij/slicer/SliceManager.java index eee7e968bad3..42cac2587988 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceManager.java +++ b/java/java-impl/src/com/intellij/slicer/SliceManager.java @@ -124,7 +124,7 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store SliceAnalysisParams params = handler.askForParams(element, dataFlowToThis, myStoredSettings, dialogTitle); if (params == null) return; - SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), createRootUsage(element, params)); + SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), SliceUsage.createRootUsage(element, params)); createToolWindow(dataFlowToThis, rootNode, false, getElementDescription(null, element, null)); } @@ -179,10 +179,6 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store "</body></html>"; } - public static SliceUsage createRootUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) { - return new SliceUsage(element, params); - } - public void checkCanceled() throws ProcessCanceledException { if (myCanceled) { throw new ProcessCanceledException(); diff --git a/java/java-impl/src/com/intellij/slicer/SliceNode.java b/java/java-impl/src/com/intellij/slicer/SliceNode.java index df114e5f9751..cd79d797e2c0 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceNode.java @@ -20,7 +20,6 @@ import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; @@ -52,6 +51,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate this.targetEqualUsages = targetEqualUsages; } + @NotNull SliceNode copy() { SliceUsage newUsage = getValue().copy(); SliceNode newNode = new SliceNode(getProject(), newUsage, targetEqualUsages); @@ -69,7 +69,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate indicator.start(); } final Collection[] nodes = new Collection[1]; - ((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(new Runnable(){ + ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { @Override public void run() { nodes[0] = getChildrenUnderProgress(ProgressManager.getInstance().getProgressIndicator()); @@ -89,6 +89,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate return index == 0 ? null : (SliceNode)parentChildren.get(index - 1); } + @NotNull protected List<? extends AbstractTreeNode> getChildrenUnderProgress(ProgressIndicator progress) { if (isUpToDate()) return myCachedChildren == null ? Collections.<AbstractTreeNode>emptyList() : myCachedChildren; final List<SliceNode> children = new ArrayList<SliceNode>(); @@ -208,7 +209,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate } @Override - public void customizeCellRenderer(SliceUsageCellRenderer renderer, JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer, @NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { renderer.setIcon(getPresentation().getIcon(expanded)); if (isValid()) { SliceUsage sliceUsage = getValue(); @@ -227,6 +228,7 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate @Override public String toString() { return ApplicationManager.getApplication().runReadAction(new Computable<String>() { + @Override public String compute() { return getValue()==null?"<null>":getValue().toString(); } diff --git a/java/java-impl/src/com/intellij/slicer/SlicePanel.java b/java/java-impl/src/com/intellij/slicer/SlicePanel.java index 7c4000378427..78e8a3e95916 100644 --- a/java/java-impl/src/com/intellij/slicer/SlicePanel.java +++ b/java/java-impl/src/com/intellij/slicer/SlicePanel.java @@ -189,13 +189,13 @@ public abstract class SlicePanel extends JPanel implements TypeSafeDataProvider, @NotNull private JTree createTree() { DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - final Tree tree = new Tree(new DefaultTreeModel(root)){ + final Tree tree = new Tree(new DefaultTreeModel(root))/* { @Override protected void paintComponent(Graphics g) { DuplicateNodeRenderer.paintDuplicateNodesBackground(g, this); super.paintComponent(g); } - }; + }*/; tree.setOpaque(false); tree.setToggleClickCount(-1); diff --git a/java/java-impl/src/com/intellij/slicer/SliceRootNode.java b/java/java-impl/src/com/intellij/slicer/SliceRootNode.java index 5f1a915f6d93..e7b6f1d2529e 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceRootNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceRootNode.java @@ -33,7 +33,7 @@ public class SliceRootNode extends SliceNode { private final SliceUsage myRootUsage; public SliceRootNode(@NotNull Project project, @NotNull DuplicateMap targetEqualUsages, final SliceUsage rootUsage) { - super(project, new SliceUsage(rootUsage.getElement().getContainingFile(), rootUsage.params), targetEqualUsages); + super(project, SliceUsage.createRootUsage(rootUsage.getElement().getContainingFile(), rootUsage.params), targetEqualUsages); myRootUsage = rootUsage; } @@ -42,6 +42,7 @@ public class SliceRootNode extends SliceNode { myCachedChildren = Collections.singletonList(node); } + @NotNull @Override SliceRootNode copy() { SliceUsage newUsage = getValue().copy(); @@ -60,6 +61,7 @@ public class SliceRootNode extends SliceNode { return myCachedChildren; } + @NotNull @Override public List<? extends AbstractTreeNode> getChildrenUnderProgress(ProgressIndicator progress) { return (List<? extends AbstractTreeNode>)getChildren(); @@ -80,8 +82,8 @@ public class SliceRootNode extends SliceNode { @Override - public void customizeCellRenderer(SliceUsageCellRenderer renderer, - JTree tree, + public void customizeCellRenderer(@NotNull SliceUsageCellRenderer renderer, + @NotNull JTree tree, Object value, boolean selected, boolean expanded, diff --git a/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java b/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java index 89360c028f74..de150dde817a 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java +++ b/java/java-impl/src/com/intellij/slicer/SliceTooComplexDFAUsage.java @@ -37,7 +37,7 @@ public class SliceTooComplexDFAUsage extends SliceUsage { } @Override - public void processChildren(Processor<SliceUsage> processor) { + public void processChildren(@NotNull Processor<SliceUsage> processor) { // no children } diff --git a/java/java-impl/src/com/intellij/slicer/SliceUsage.java b/java/java-impl/src/com/intellij/slicer/SliceUsage.java index 21a849068ba9..0942dcc862a0 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUsage.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUsage.java @@ -21,7 +21,6 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiSubstitutor; -import com.intellij.slicer.forward.SliceFUtil; import com.intellij.usageView.UsageInfo; import com.intellij.usages.UsageInfo2UsageAdapter; import com.intellij.util.CommonProcessors; @@ -44,14 +43,18 @@ public class SliceUsage extends UsageInfo2UsageAdapter { params = parent.params; assert params != null; } - public SliceUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) { + private SliceUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) { super(new UsageInfo(element)); myParent = null; this.params = params; mySubstitutor = PsiSubstitutor.EMPTY; } - public void processChildren(Processor<SliceUsage> processor) { + public static SliceUsage createRootUsage(@NotNull PsiElement element, @NotNull SliceAnalysisParams params) { + return new SliceUsage(element, params); + } + + public void processChildren(@NotNull Processor<SliceUsage> processor) { final PsiElement element = getElement(); ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); indicator.checkCanceled(); @@ -76,7 +79,7 @@ public class SliceUsage extends UsageInfo2UsageAdapter { SliceUtil.processUsagesFlownDownTo(element, uniqueProcessor, SliceUsage.this, mySubstitutor); } else { - SliceFUtil.processUsagesFlownFromThe(element, uniqueProcessor, SliceUsage.this); + SliceForwardUtil.processUsagesFlownFromThe(element, uniqueProcessor, SliceUsage.this); } } }); @@ -93,7 +96,7 @@ public class SliceUsage extends UsageInfo2UsageAdapter { SliceUsage copy() { PsiElement element = getUsageInfo().getElement(); - return getParent() == null ? new SliceUsage(element, params) : new SliceUsage(element, getParent(),mySubstitutor); + return getParent() == null ? createRootUsage(element, params) : new SliceUsage(element, getParent(),mySubstitutor); } public PsiSubstitutor getSubstitutor() { diff --git a/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java b/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java index d2fdf1a7b187..c12f62e669b7 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java @@ -18,12 +18,14 @@ package com.intellij.slicer; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.usageView.UsageTreeColors; import com.intellij.usageView.UsageTreeColorsScheme; import com.intellij.usages.TextChunk; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -41,7 +43,7 @@ public class SliceUsageCellRenderer extends ColoredTreeCellRenderer { } @Override - public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { assert value instanceof DefaultMutableTreeNode; DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value; Object userObject = treeNode.getUserObject(); @@ -58,7 +60,7 @@ public class SliceUsageCellRenderer extends ColoredTreeCellRenderer { } } - public void customizeCellRendererFor(SliceUsage sliceUsage) { + public void customizeCellRendererFor(@NotNull SliceUsage sliceUsage) { boolean isForcedLeaf = sliceUsage instanceof SliceDereferenceUsage; TextChunk[] text = sliceUsage.getPresentation().getText(); @@ -83,12 +85,10 @@ public class SliceUsageCellRenderer extends ColoredTreeCellRenderer { break; } } + int methodOptions = PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS | PsiFormatUtilBase.SHOW_CONTAINING_CLASS; String location = method != null - ? PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | - PsiFormatUtil.SHOW_PARAMETERS | - PsiFormatUtil.SHOW_CONTAINING_CLASS, - PsiFormatUtil.SHOW_TYPE, 2) - : aClass != null ? PsiFormatUtil.formatClass(aClass, PsiFormatUtil.SHOW_NAME) : null; + ? PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, methodOptions, PsiFormatUtilBase.SHOW_TYPE, 2) + : aClass != null ? PsiFormatUtil.formatClass(aClass, PsiFormatUtilBase.SHOW_NAME) : null; if (location != null) { SimpleTextAttributes attributes = SimpleTextAttributes.GRAY_ATTRIBUTES; append(" in " + location, attributes); diff --git a/java/java-impl/src/com/intellij/slicer/SliceUtil.java b/java/java-impl/src/com/intellij/slicer/SliceUtil.java index 35b63bff0c95..a689e181f3df 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUtil.java @@ -30,7 +30,6 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.slicer.forward.SliceFUtil; import com.intellij.util.ArrayUtilRt; import com.intellij.util.Processor; import gnu.trove.THashMap; @@ -54,7 +53,7 @@ public class SliceUtil { expression = simplify(expression); PsiElement original = expression; if (expression instanceof PsiReferenceExpression) { - PsiElement element = SliceFUtil.complexify(expression); + PsiElement element = SliceForwardUtil.complexify(expression); if (element instanceof PsiExpression && PsiUtil.isOnAssignmentLeftHand((PsiExpression)element)) { PsiExpression rightSide = ((PsiAssignmentExpression)element.getParent()).getRExpression(); return rightSide == null || handToProcessor(rightSide, processor, parent, parentSubstitutor); @@ -238,9 +237,12 @@ public class SliceUtil { }); } + @NotNull public static SliceUsage createSliceUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) { return new SliceUsage(simplify(element), parent, substitutor); } + + @NotNull public static SliceUsage createTooComplexDFAUsage(@NotNull PsiElement element, @NotNull SliceUsage parent, @NotNull PsiSubstitutor substitutor) { return new SliceTooComplexDFAUsage(simplify(element), parent, substitutor); } diff --git a/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java b/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java index 9e389dda012e..5b4a1f310d3e 100644 --- a/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java +++ b/java/java-impl/src/com/intellij/testIntegration/JavaTestFramework.java @@ -107,6 +107,8 @@ public abstract class JavaTestFramework implements TestFramework { public FileTemplateDescriptor getParametersMethodFileTemplateDescriptor() { return null; } + + public abstract char getMnemonic(); public PsiMethod createSetUpPatternMethod(JVMElementFactory factory) { final FileTemplate template = FileTemplateManager.getInstance().getCodeTemplate(getSetUpMethodFileTemplateDescriptor().getFileName()); diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java index d34a3600d4dc..1185d60a7971 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/CreateTestDialog.java @@ -49,6 +49,7 @@ import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo; import com.intellij.refactoring.util.RefactoringMessageUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.classMembers.MemberInfo; +import com.intellij.testIntegration.JavaTestFramework; import com.intellij.testIntegration.TestFramework; import com.intellij.testIntegration.TestIntegrationUtils; import com.intellij.ui.EditorTextField; @@ -123,6 +124,12 @@ public class CreateTestDialog extends DialogWrapper { for (final TestFramework descriptor : Extensions.getExtensions(TestFramework.EXTENSION_NAME)) { final JRadioButton b = new JRadioButton(descriptor.getName()); + if (descriptor instanceof JavaTestFramework) { + final char mnemonic = ((JavaTestFramework)descriptor).getMnemonic(); + if (mnemonic > -1) { + b.setMnemonic(mnemonic); + } + } myLibraryButtons.add(b); group.add(b); diff --git a/java/java-impl/src/com/intellij/usageView/UsageContextDataflowToPanel.java b/java/java-impl/src/com/intellij/usageView/UsageContextDataflowToPanel.java index 226af43fe3df..b097a8a7e307 100644 --- a/java/java-impl/src/com/intellij/usageView/UsageContextDataflowToPanel.java +++ b/java/java-impl/src/com/intellij/usageView/UsageContextDataflowToPanel.java @@ -122,7 +122,7 @@ public class UsageContextDataflowToPanel extends UsageContextPanelBase { ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND); SliceAnalysisParams params = createParams(element, dataFlowToThis); - SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), SliceManager.createRootUsage(element, params)); + SliceRootNode rootNode = new SliceRootNode(myProject, new DuplicateMap(), SliceUsage.createRootUsage(element, params)); return new SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) { @Override diff --git a/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java b/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java index 0593133e51a1..7e344d26143a 100644 --- a/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java +++ b/java/java-impl/src/com/intellij/usages/impl/rules/MethodGroupingRule.java @@ -50,6 +50,7 @@ public class MethodGroupingRule implements UsageGroupingRule { if (!(usage instanceof PsiElementUsage)) return null; PsiElement psiElement = ((PsiElementUsage)usage).getElement(); PsiFile containingFile = psiElement.getContainingFile(); + if (containingFile == null) return null; InjectedLanguageManager manager = InjectedLanguageManager.getInstance(containingFile.getProject()); PsiFile topLevelFile = manager.getTopLevelFile(containingFile); if (topLevelFile instanceof PsiJavaFile) { diff --git a/java/java-indexing-api/src/com/intellij/psi/search/PsiShortNamesCache.java b/java/java-indexing-api/src/com/intellij/psi/search/PsiShortNamesCache.java index 6854c57b141a..aa0d088fe922 100644 --- a/java/java-indexing-api/src/com/intellij/psi/search/PsiShortNamesCache.java +++ b/java/java-indexing-api/src/com/intellij/psi/search/PsiShortNamesCache.java @@ -120,6 +120,14 @@ public abstract class PsiShortNamesCache { public abstract boolean processMethodsWithName(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope, @NotNull Processor<PsiMethod> processor); + public boolean processAllMethodNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + return ContainerUtil.process(getAllFieldNames(), processor); + } + + public boolean processAllFieldNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + return ContainerUtil.process(getAllFieldNames(), processor); + } + /** * Returns the list of names of all methods in the project and * (optionally) libraries. diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/CompositeShortNamesCache.java b/java/java-indexing-impl/src/com/intellij/psi/impl/CompositeShortNamesCache.java index e6ba22dc5837..517a30098040 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/CompositeShortNamesCache.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/CompositeShortNamesCache.java @@ -117,6 +117,26 @@ public class CompositeShortNamesCache extends PsiShortNamesCache { } @Override + public boolean processAllMethodNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + for (PsiShortNamesCache cache : myCaches) { + if (!cache.processAllMethodNames(processor, scope, filter)) { + return false; + } + } + return true; + } + + @Override + public boolean processAllFieldNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + for (PsiShortNamesCache cache : myCaches) { + if (!cache.processAllFieldNames(processor, scope, filter)) { + return false; + } + } + return true; + } + + @Override public void getAllClassNames(@NotNull HashSet<String> dest) { for (PsiShortNamesCache cache : myCaches) { cache.getAllClassNames(dest); diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/PsiShortNamesCacheImpl.java b/java/java-indexing-impl/src/com/intellij/psi/impl/PsiShortNamesCacheImpl.java index e702d011a0e2..8bc35ce49b3c 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/PsiShortNamesCacheImpl.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/PsiShortNamesCacheImpl.java @@ -122,6 +122,16 @@ public class PsiShortNamesCacheImpl extends PsiShortNamesCache { } @Override + public boolean processAllMethodNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + return StubIndex.getInstance().processAllKeys(JavaStubIndexKeys.METHODS, processor, scope, filter); + } + + @Override + public boolean processAllFieldNames(Processor<String> processor, GlobalSearchScope scope, IdFilter filter) { + return StubIndex.getInstance().processAllKeys(JavaStubIndexKeys.FIELDS, processor, scope, filter); + } + + @Override @NotNull public PsiMethod[] getMethodsByName(@NotNull String name, @NotNull final GlobalSearchScope scope) { Collection<PsiMethod> methods = StubIndex.getInstance().get(JavaStubIndexKeys.METHODS, name, myManager.getProject(), new JavaSourceFilterScope(scope)); diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 94c15638a9ab..4cdb0f312b93 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -109,9 +109,7 @@ public class LambdaUtil { public static boolean isLambdaFullyInferred(PsiLambdaExpression expression, PsiType functionalInterfaceType) { final boolean hasParams = expression.getParameterList().getParametersCount() > 0; if (hasParams || getFunctionalInterfaceReturnType(functionalInterfaceType) != PsiType.VOID) { //todo check that void lambdas without params check - if (hasParams && !checkRawAcceptable(expression, functionalInterfaceType)) { - return false; - } + return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression); } return true; diff --git a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceExpression.java b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceExpression.java index 2d91cd4a7058..1df1441e2ad4 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceExpression.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceExpression.java @@ -35,4 +35,6 @@ public interface PsiMethodReferenceExpression extends PsiReferenceExpression { */ @Nullable PsiType getFunctionalInterfaceType(); + + boolean isExact(); } diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index 01120c2082b4..d72d3d8414a4 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -81,7 +81,7 @@ public class MethodCandidateInfo extends CandidateInfo{ private int getApplicabilityLevelInner() { if (myArgumentTypes == null) return ApplicabilityLevel.NOT_APPLICABLE; - int level = PsiUtil.getApplicabilityLevel(getElement(), getSubstitutor(!Registry.is("enable.graph.inference", false)), myArgumentTypes, myLanguageLevel); + int level = PsiUtil.getApplicabilityLevel(getElement(), getSubstitutor(), myArgumentTypes, myLanguageLevel); if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable()) level = ApplicabilityLevel.NOT_APPLICABLE; return level; } diff --git a/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaDocLexer.java b/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaDocLexer.java index de1e03f30d6d..0592f9e916d8 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaDocLexer.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaDocLexer.java @@ -54,7 +54,7 @@ public class JavaDocLexer extends MergingLexerAdapter { } @Override - public final void start(CharSequence buffer, int startOffset, int endOffset, int initialState) { + public final void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { myBuffer = buffer; myBufferIndex = startOffset; myBufferEndOffset = endOffset; @@ -68,6 +68,7 @@ public class JavaDocLexer extends MergingLexerAdapter { return myState; } + @NotNull @Override public CharSequence getBufferSequence() { return myBuffer; diff --git a/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaLexer.java b/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaLexer.java index db6e5e21aa25..f1c6c19453bb 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaLexer.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/lexer/JavaLexer.java @@ -175,7 +175,7 @@ public class JavaLexer extends LexerBase { } @Override - public final void start(CharSequence buffer, int startOffset, int endOffset, int initialState) { + public final void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { myBuffer = buffer; myBufferArray = CharArrayUtil.fromSequenceWithoutCopying(buffer); myBufferIndex = startOffset; @@ -417,6 +417,7 @@ public class JavaLexer extends LexerBase { return pos; } + @NotNull @Override public CharSequence getBufferSequence() { return myBuffer; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index bc62cc802fad..103b828b1873 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -799,7 +799,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme @Override public void processVariants(@NotNull final PsiScopeProcessor processor) { final OrFilter filter = new OrFilter(); - if (isInCode() && !(getParent() instanceof PsiImportStatement)) { + if (isInCode() && !(getParent() instanceof PsiImportStatement) && !(getParent() instanceof PsiReferenceList)) { filter.addFilter(new AndFilter(ElementClassFilter.METHOD, new NotFilter(new ConstructorFilter()))); filter.addFilter(ElementClassFilter.VARIABLE); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 68bb8b865c92..15aba8821ffe 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.resolve; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.registry.Registry; import com.intellij.pom.java.LanguageLevel; @@ -196,7 +197,16 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { .getSubstitutionForTypeParameter(typeParam, param, arg, isContraVariantPosition, languageLevel); } + private PsiInferenceHelper myTestHelper; + + public void setTestHelper(PsiInferenceHelper testHelper) { + myTestHelper = testHelper; + } + public PsiInferenceHelper getInferenceHelper(LanguageLevel languageLevel) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + return myTestHelper != null ? myTestHelper : new PsiOldInferenceHelper(myManager); + } if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Registry.is("enable.graph.inference", false)) { return new PsiGraphInferenceHelper(myManager); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java new file mode 100644 index 000000000000..4806a51a5dcf --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.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.intellij.psi.impl.source.resolve.graphInference; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FunctionalInterfaceParameterizationUtil { + private static final Logger LOG = Logger.getInstance("#" + FunctionalInterfaceParameterizationUtil.class.getName()); + + public static boolean isWildcardParameterized(@Nullable PsiType classType) { + if (classType == null) return false; + if (classType instanceof PsiIntersectionType) { + for (PsiType type : ((PsiIntersectionType)classType).getConjuncts()) { + if (!isWildcardParameterized(type)) return false; + } + } + if (classType instanceof PsiClassType) { + for (PsiType type : ((PsiClassType)classType).getParameters()) { + if (type instanceof PsiWildcardType || type instanceof PsiCapturedWildcardType) { + return true; + } + } + return false; + } + LOG.error("Unexpected type: " + classType); + return false; + } + + @Nullable + public static PsiType getFunctionalType(@Nullable PsiType psiClassType, PsiLambdaExpression expr) { + if (!expr.hasFormalParameterTypes() || expr.getParameterList().getParametersCount() == 0) return psiClassType; + if (!isWildcardParameterized(psiClassType)) { + return psiClassType; + } + final PsiParameter[] lambdaParams = expr.getParameterList().getParameters(); + if (psiClassType instanceof PsiIntersectionType) { + for (PsiType psiType : ((PsiIntersectionType)psiClassType).getConjuncts()) { + final PsiType functionalType = getFunctionalType(psiType, expr); + if (functionalType != null) return functionalType; + } + return null; + } + + LOG.assertTrue(psiClassType instanceof PsiClassType, "Unexpected type: " + psiClassType); + final PsiType[] parameters = ((PsiClassType)psiClassType).getParameters(); + final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)psiClassType).resolveGenerics(); + PsiClass psiClass = resolveResult.getElement(); + + if (psiClass != null) { + + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); + if (interfaceMethod == null) return null; + + final InferenceSession session = new InferenceSession(PsiSubstitutor.EMPTY); + PsiTypeParameter[] typeParameters = psiClass.getTypeParameters(); + if (typeParameters.length != parameters.length) { + return null; + } + + for (int i = 0; i < typeParameters.length; i++) { + session.addVariable(typeParameters[i], parameters[i]); + } + + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiClass.getProject()); + final PsiParameter[] targetMethodParams = interfaceMethod.getParameterList().getParameters(); + for (int i = 0; i < targetMethodParams.length; i++) { + session.addConstraint(new TypeEqualityConstraint(lambdaParams[i].getType(), targetMethodParams[i].getType())); + } + + final PsiClassType parameterization = elementFactory.createType(psiClass, session.infer()); + if (!isWildcardParameterized(parameterization)) return parameterization; + } + return null; + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index a63e43824986..e1c3d63d8b15 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -174,8 +174,10 @@ public class InferenceIncorporationPhase { private void eqEq(List<PsiType> eqBounds) { for (int i = 0; i < eqBounds.size(); i++) { PsiType sBound= eqBounds.get(i); + if (sBound == null) continue; for (int j = i + 1; j < eqBounds.size(); j++) { final PsiType tBound = eqBounds.get(j); + if (tBound == null) continue; addConstraint(new TypeEqualityConstraint(tBound, sBound)); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index dba4a7289a5e..df785073a6d7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -18,13 +18,17 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.impl.source.resolve.graphInference.constraints.CheckedExceptionCompatibilityConstraint; import com.intellij.psi.impl.source.resolve.graphInference.constraints.ConstraintFormula; import com.intellij.psi.impl.source.resolve.graphInference.constraints.ExpressionCompatibilityConstraint; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeCompatibilityConstraint; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.ArrayUtilRt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,7 +42,6 @@ public class InferenceSession { private Map<PsiTypeParameter, InferenceVariable> myInferenceVariables = new LinkedHashMap<PsiTypeParameter, InferenceVariable>(); private final List<ConstraintFormula> myConstraints = new ArrayList<ConstraintFormula>(); - private final List<ConstraintFormula> myDelayedConstraints = new ArrayList<ConstraintFormula>(); private PsiSubstitutor mySiteSubstitutor; private PsiManager myManager; @@ -46,6 +49,10 @@ public class InferenceSession { private final InferenceIncorporationPhase myIncorporationPhase = new InferenceIncorporationPhase(this); + public InferenceSession(PsiSubstitutor siteSubstitutor) { + mySiteSubstitutor = siteSubstitutor; + } + public InferenceSession(PsiTypeParameter[] typeParams, PsiType[] leftTypes, PsiType[] rightTypes, @@ -75,14 +82,10 @@ public class InferenceSession { if (parameters.length > 0) { for (int i = 0; i < args.length; i++) { - PsiType parameterType = mySiteSubstitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType()); - if (parameterType instanceof PsiEllipsisType) { - if (args.length != parameters.length || args[i] != null && !(args[i].getType() instanceof PsiArrayType)) { - parameterType = ((PsiEllipsisType)parameterType).getComponentType(); - } - } + PsiType parameterType = getParameterType(parameters, args, i, mySiteSubstitutor); if (args[i] != null) { myConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType)); + //myConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType)); } } } @@ -98,11 +101,66 @@ public class InferenceSession { } } + public static boolean isPertinentToApplicability(PsiExpression expr, PsiMethod method) { + if (expr instanceof PsiLambdaExpression) { + if (((PsiLambdaExpression)expr).hasFormalParameterTypes()) return true; + for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)expr)) { + if (!isPertinentToApplicability(expression, method)) return false; + } + if (method.getTypeParameters().length > 0) { + final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expr.getParent()); + if (parent instanceof PsiExpressionList) { + final PsiElement gParent = parent.getParent(); + if (gParent instanceof PsiCallExpression && ((PsiCallExpression)gParent).getTypeArgumentList().getTypeParameterElements().length == 0) { + final int idx = LambdaUtil.getLambdaIdx(((PsiExpressionList)parent), expr); + final PsiParameter[] parameters = method.getParameterList().getParameters(); + PsiType paramType; + if (idx > parameters.length - 1) { + final PsiType lastParamType = parameters[parameters.length - 1].getType(); + paramType = parameters[parameters.length - 1].isVarArgs() ? ((PsiEllipsisType)lastParamType).getComponentType() : lastParamType; + } + else { + paramType = parameters[idx].getType(); + } + final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(paramType); + if (psiClass instanceof PsiTypeParameter && ((PsiTypeParameter)psiClass).getOwner() == method) return false; + } + } + } + return true; + } + if (expr instanceof PsiMethodReferenceExpression) { + return ((PsiMethodReferenceExpression)expr).isExact(); + } + if (expr instanceof PsiParenthesizedExpression) { + return isPertinentToApplicability(((PsiParenthesizedExpression)expr).getExpression(), method); + } + if (expr instanceof PsiConditionalExpression) { + final PsiExpression thenExpression = ((PsiConditionalExpression)expr).getThenExpression(); + if (!isPertinentToApplicability(thenExpression, method)) return false; + final PsiExpression elseExpression = ((PsiConditionalExpression)expr).getElseExpression(); + if (!isPertinentToApplicability(elseExpression, method)) return false; + } + return true; + } + + private static PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, PsiSubstitutor substitutor) { + PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType()); + if (parameterType instanceof PsiEllipsisType) { + if (args.length != parameters.length || PsiPolyExpressionUtil + .isPolyExpression(args[i]) || args[i] != null && !(args[i].getType() instanceof PsiArrayType)) { + parameterType = ((PsiEllipsisType)parameterType).getComponentType(); + } + } + return parameterType; + } + @NotNull public PsiSubstitutor infer() { repeatInferencePhases(); for (InferenceVariable inferenceVariable : myInferenceVariables.values()) { + if (inferenceVariable.isCaptured()) continue; final PsiTypeParameter typeParameter = inferenceVariable.getParameter(); PsiType instantiation = inferenceVariable.getInstantiation(); if (instantiation == PsiType.NULL) { @@ -136,25 +194,60 @@ public class InferenceSession { } } } + + public void addCapturedVariable(PsiTypeParameter param) { + if (myInferenceVariables.containsKey(param)) return; //same method call + final InferenceVariable variable = new InferenceVariable(param); + variable.setCaptured(true); + myInferenceVariables.put(param, variable); + } private void initReturnTypeConstraint(PsiMethod method, PsiCallExpression context) { if (PsiPolyExpressionUtil.isPolyExpression(context) || context instanceof PsiNewExpression && PsiDiamondType.ourDiamondGuard.currentStack().contains(context)) { final PsiType returnType = method.getReturnType(); if (!PsiType.VOID.equals(returnType) && returnType != null) { - final PsiType targetType = PsiPolyExpressionUtil.getTargetType(context);//todo primitive type + PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context); + if (targetType == null) { + final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent()); + if (parent instanceof PsiExpressionList) { + final PsiElement gParent = parent.getParent(); + if (gParent instanceof PsiCallExpression) { + final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList(); + if (argumentList != null) { + final JavaResolveResult resolveResult = ((PsiCallExpression)gParent).resolveMethodGenerics(); + final PsiElement parentMethod = resolveResult.getElement(); + if (parentMethod instanceof PsiMethod) { + final PsiParameter[] parameters = ((PsiMethod)parentMethod).getParameterList().getParameters(); + PsiElement arg = context; + while (arg.getParent() instanceof PsiParenthesizedExpression) { + arg = parent.getParent(); + } + final PsiExpression[] args = argumentList.getExpressions(); + targetType = getParameterType(parameters, args, ArrayUtilRt.find(args, arg), resolveResult.getSubstitutor()); + } + } + } + } else if (parent instanceof PsiConditionalExpression) { + targetType = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent); + } + } if (targetType != null) { - myConstraints.add(new TypeCompatibilityConstraint(targetType, returnType)); + myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context))); } } } } public InferenceVariable getInferenceVariable(PsiType psiType) { + return getInferenceVariable(psiType, true); + } + + public InferenceVariable getInferenceVariable(PsiType psiType, boolean acceptCaptured) { final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(psiType); if (psiClass instanceof PsiTypeParameter) { final InferenceVariable inferenceVariable = myInferenceVariables.get(psiClass); - if (inferenceVariable != null) { + if (inferenceVariable != null && (acceptCaptured || !inferenceVariable.isCaptured())) { return inferenceVariable; } } @@ -162,10 +255,16 @@ public class InferenceSession { } public boolean isProperType(@Nullable PsiType type) { - return collectDependencies(type, null); + return isProperType(type, true); } - public boolean collectDependencies(@Nullable PsiType type, @Nullable final Set<InferenceVariable> dependencies) { + public boolean isProperType(@Nullable PsiType type, boolean acceptCaptured) { + return collectDependencies(type, null, acceptCaptured); + } + + public boolean collectDependencies(@Nullable PsiType type, + @Nullable final Set<InferenceVariable> dependencies, + final boolean acceptCaptured) { if (type == null) return true; final Boolean isProper = type.accept(new PsiTypeVisitor<Boolean>() { @Nullable @@ -191,7 +290,7 @@ public class InferenceSession { @Nullable @Override public Boolean visitClassType(PsiClassType classType) { - final InferenceVariable inferenceVariable = getInferenceVariable(classType); + final InferenceVariable inferenceVariable = getInferenceVariable(classType, acceptCaptured); if (inferenceVariable != null) { if (dependencies != null) { dependencies.add(inferenceVariable); @@ -225,7 +324,7 @@ public class InferenceSession { List<ConstraintFormula> newConstraints = new ArrayList<ConstraintFormula>(); for (int i = myConstraintIdx; i < myConstraints.size(); i++) { ConstraintFormula constraint = myConstraints.get(i); - if (!constraint.reduce(this, newConstraints, myDelayedConstraints)) { + if (!constraint.reduce(this, newConstraints)) { return false; } } @@ -241,7 +340,7 @@ public class InferenceSession { for (List<InferenceVariable> variables : independentVars) { for (InferenceVariable inferenceVariable : variables) { - if (inferenceVariable.getInstantiation() != PsiType.NULL) continue; + if (inferenceVariable.isCaptured() || inferenceVariable.getInstantiation() != PsiType.NULL) continue; final PsiTypeParameter typeParameter = inferenceVariable.getParameter(); try { final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); @@ -253,19 +352,18 @@ public class InferenceSession { } PsiType bound = null; for (PsiType eqBound : eqBounds) { - eqBound = acceptBoundsWithRecursiveDependencies(typeParameter, eqBound); - if (isProperType(eqBound)) { - bound = eqBound; - break; - } + bound = acceptBoundsWithRecursiveDependencies(typeParameter, eqBound); } if (bound != null) { + if (bound instanceof PsiCapturedWildcardType && eqBounds.size() > 1) { + continue; + } inferenceVariable.setInstantiation(bound); } else { PsiType lub = null; for (PsiType lowerBound : lowerBounds) { lowerBound = acceptBoundsWithRecursiveDependencies(typeParameter, lowerBound); - if (isProperType(lowerBound)) { + if (isProperType(lowerBound, false)) { if (lub == null) { lub = lowerBound; } @@ -281,7 +379,7 @@ public class InferenceSession { PsiType glb = null; for (PsiType upperBound : upperBounds) { upperBound = acceptBoundsWithRecursiveDependencies(typeParameter, upperBound); - if (isProperType(upperBound)) { + if (isProperType(upperBound, false)) { if (glb == null) { glb = upperBound; } @@ -307,8 +405,9 @@ public class InferenceSession { } private PsiType acceptBoundsWithRecursiveDependencies(PsiTypeParameter typeParameter, PsiType bound) { - if (PsiPolyExpressionUtil.mentionsTypeParameters(bound, Collections.singleton(typeParameter))) { - return mySiteSubstitutor.put(typeParameter, null).substitute(bound); + if (!isProperType(bound)) { + final PsiSubstitutor substitutor = PsiUtil.resolveClassInType(bound) != typeParameter ? mySiteSubstitutor.put(typeParameter, null) : mySiteSubstitutor; + return substitutor.substitute(bound); } return bound; } @@ -330,4 +429,24 @@ public class InferenceSession { myConstraints.add(constraint); } } + + public Collection<PsiTypeParameter> getTypeParams() { + return myInferenceVariables.keySet(); + } + + public void addVariable(PsiTypeParameter typeParameter, final PsiType parameter) { + InferenceVariable variable = new InferenceVariable(typeParameter); + if (parameter instanceof PsiWildcardType) { + PsiType bound = ((PsiWildcardType)parameter).getBound(); + if (bound != null) { + variable.addBound(bound, ((PsiWildcardType)parameter).isExtends() ? InferenceBound.UPPER : InferenceBound.LOWER); + } else { + variable.addBound(PsiType.getJavaLangObject(typeParameter.getManager(), parameter.getResolveScope()), + InferenceBound.UPPER); + } + } else { + variable.addBound(parameter, InferenceBound.EQ); + } + myInferenceVariables.put(typeParameter, variable); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java index e69f229fe91f..f750e1247728 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java @@ -58,7 +58,8 @@ public class InferenceVariable { list = new ArrayList<PsiType>(); myBounds.put(inferenceBound, list); } - if (!list.contains(classType)) { + final int idx = list.indexOf(classType); + if (idx < 0 || inferenceBound == InferenceBound.EQ && classType instanceof PsiCapturedWildcardType && list.get(idx) != classType) { list.add(classType); return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java index 4a2c4126611e..c27ae4a53916 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java @@ -41,7 +41,7 @@ public class InferenceVariablesOrder { for (InferenceBound inferenceBound : InferenceBound.values()) { for (PsiType bound : var.getBounds(inferenceBound)) { final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>(); - session.collectDependencies(bound, dependencies); + session.collectDependencies(bound, dependencies, true); for (InferenceVariable dependentVariable : dependencies) { final InferenceGraphNode<InferenceVariable> dependency = nodes.get(dependentVariable); if (dependency != null) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiPolyExpressionUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiPolyExpressionUtil.java index 2e425e0fb436..d6a1d46ad336 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiPolyExpressionUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiPolyExpressionUtil.java @@ -82,10 +82,6 @@ public class PsiPolyExpressionUtil { return false; } - public static PsiType getTargetType(@NotNull PsiCallExpression expression) { - return PsiTypesUtil.getExpectedTypeByParent(expression); - } - public static Boolean mentionsTypeParameters(@Nullable PsiType returnType, final Set<PsiTypeParameter> typeParameters) { if (returnType == null) return false; return returnType.accept(new PsiTypeVisitor<Boolean>() { @@ -125,7 +121,7 @@ public class PsiPolyExpressionUtil { private static boolean isInAssignmentOrInvocationContext(PsiExpression expr) { final PsiElement context = expr.getParent(); - return context instanceof PsiExpressionList || isAssignmentContext(expr, context); + return context instanceof PsiExpressionList || context instanceof PsiConditionalExpression || isAssignmentContext(expr, context); } private static boolean isAssignmentContext(PsiExpression expr, PsiElement context) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java new file mode 100644 index 000000000000..19f50e6fd412 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -0,0 +1,164 @@ +/* + * 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.psi.impl.source.resolve.graphInference.constraints; + +import com.intellij.codeInsight.ExceptionUtil; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; +import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * User: anna + */ +public class CheckedExceptionCompatibilityConstraint extends InputOutputConstraintFormula { + private static final Logger LOG = Logger.getInstance("#" + CheckedExceptionCompatibilityConstraint.class.getName()); + private final PsiExpression myExpression; + private final PsiType myT; + + public CheckedExceptionCompatibilityConstraint(PsiExpression expression, PsiType t) { + myExpression = expression; + myT = t; + } + + @Override + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { + if (!PsiPolyExpressionUtil.isPolyExpression(myExpression) || + myExpression instanceof PsiCallExpression) { + return true; + } + if (myExpression instanceof PsiParenthesizedExpression) { + constraints.add(new CheckedExceptionCompatibilityConstraint(((PsiParenthesizedExpression)myExpression).getExpression(), myT)); + return true; + } + if (myExpression instanceof PsiConditionalExpression) { + final PsiExpression thenExpression = ((PsiConditionalExpression)myExpression).getThenExpression(); + if (thenExpression != null) { + constraints.add(new CheckedExceptionCompatibilityConstraint(thenExpression, myT)); + } + final PsiExpression elseExpression = ((PsiConditionalExpression)myExpression).getElseExpression(); + if (elseExpression != null) { + constraints.add(new CheckedExceptionCompatibilityConstraint(elseExpression, myT)); + } + return true; + } + if (myExpression instanceof PsiLambdaExpression || myExpression instanceof PsiMethodReferenceExpression) { + if (LambdaHighlightingUtil.checkInterfaceFunctional(myT) != null) { + return false; + } + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(myT); + if (interfaceMethod == null) { + return false; + } + + final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(myT)); + for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) { + if (!session.isProperType(substitutor.substitute(parameter.getType()))) return false; + } + final PsiType returnType = interfaceMethod.getReturnType(); + LOG.assertTrue(returnType != null, interfaceMethod); + if (!session.isProperType(substitutor.substitute(returnType))) return false; + + final List<PsiType> + expectedThrownTypes = ContainerUtil.map(interfaceMethod.getThrowsList().getReferencedTypes(), new Function<PsiType, PsiType>() { + @Override + public PsiType fun(PsiType type) { + return substitutor.substitute(type); + } + }); + final List<PsiType> expectedNonProperThrownTypes = new ArrayList<PsiType>(); + for (PsiType type : expectedThrownTypes) { + if (!session.isProperType(type)) { + expectedNonProperThrownTypes.add(type); + } + } + + final List<PsiType> thrownTypes = new ArrayList<PsiType>(); + if (myExpression instanceof PsiLambdaExpression) { + //todo + } else { + final PsiElement resolve = ((PsiMethodReferenceExpression)myExpression).resolve(); + if (resolve instanceof PsiMethod) { + for (PsiClassType type : ((PsiMethod)resolve).getThrowsList().getReferencedTypes()) { + if (!ExceptionUtil.isUncheckedException(type)) { + thrownTypes.add(type); + } + } + } + } + + if (expectedNonProperThrownTypes.isEmpty()) { + for (PsiType thrownType : thrownTypes) { + if (!isAddressed(expectedThrownTypes, thrownType)) return false; + } + } else { + final ArrayList<PsiType> expectedProperTypes = new ArrayList<PsiType>(expectedThrownTypes); + expectedProperTypes.retainAll(expectedNonProperThrownTypes); + for (PsiType thrownType : thrownTypes) { + if (!isAddressed(expectedProperTypes, thrownType)) { + for (PsiType expectedNonProperThrownType : expectedNonProperThrownTypes) { + constraints.add(new TypeCompatibilityConstraint(expectedNonProperThrownType, thrownType)); + } + } + } + } + } + + return true; + } + + private static boolean isAddressed(List<PsiType> expectedThrownTypes, PsiType thrownType) { + for (PsiType expectedThrownType : expectedThrownTypes) { + if (TypeConversionUtil.isAssignable(expectedThrownType, thrownType)) { + return true; + } + } + return false; + } + + @Override + protected PsiExpression getExpression() { + return myExpression; + } + + @Override + protected PsiType getT() { + return myT; + } + + @Override + protected InputOutputConstraintFormula createSelfConstraint(PsiType type, PsiExpression expression) { + return new CheckedExceptionCompatibilityConstraint(expression, type); + } + + @Override + protected void collectReturnTypeVariables(InferenceSession session, + PsiExpression psiExpression, + PsiMethod interfaceMethod, + Set<InferenceVariable> result) { + final PsiType returnType = interfaceMethod.getReturnType(); + session.collectDependencies(returnType, result, true); + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ConstraintFormula.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ConstraintFormula.java index 992d875bb535..8dc8ee034cc1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ConstraintFormula.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ConstraintFormula.java @@ -23,5 +23,5 @@ import java.util.List; * User: anna */ public interface ConstraintFormula { - boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints); + boolean reduce(InferenceSession session, List<ConstraintFormula> constraints); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index a0e6a767d8f2..7084538c17c7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -15,18 +15,22 @@ */ package com.intellij.psi.impl.source.resolve.graphInference.constraints; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; +import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl; +import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.NotNull; -import java.util.List; +import java.util.*; /** * User: anna */ -public class ExpressionCompatibilityConstraint implements ConstraintFormula { +public class ExpressionCompatibilityConstraint extends InputOutputConstraintFormula { private PsiExpression myExpression; private PsiType myT; @@ -36,7 +40,7 @@ public class ExpressionCompatibilityConstraint implements ConstraintFormula { } @Override - public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints) { + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (session.isProperType(myT)) { return TypeConversionUtil.areTypesAssignmentCompatible(myT, myExpression); } @@ -69,11 +73,59 @@ public class ExpressionCompatibilityConstraint implements ConstraintFormula { } if (myExpression instanceof PsiCallExpression) { - //todo + final PsiExpressionList argumentList = ((PsiCallExpression)myExpression).getArgumentList(); + if (argumentList != null) { + final Map<PsiElement,Pair<PsiMethod,PsiSubstitutor>> map = MethodCandidateInfo.CURRENT_CANDIDATE.get(); + final Pair<PsiMethod,PsiSubstitutor> pair = map != null ? map.get(argumentList) : null; + final PsiMethod method = pair != null ? pair.first : ((PsiCallExpression)myExpression).resolveMethod(); + PsiType returnType = null; + InferenceSession callSession = null; + if (method != null) { + returnType = method.getReturnType(); + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (returnType != null) { + callSession = new InferenceSession(method.getTypeParameters(), parameters, + argumentList.getExpressions(), + PsiSubstitutor.EMPTY, null, myExpression.getManager()); + + } + } else if (myExpression instanceof PsiNewExpression) { //default constructor + final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)myExpression).getClassOrAnonymousClassReference(); + if (classReference != null) { + final PsiElement psiClass = classReference.resolve(); + if (psiClass instanceof PsiClass) { + returnType = JavaPsiFacade.getElementFactory(argumentList.getProject()).createType((PsiClass)psiClass, PsiSubstitutor.EMPTY); + callSession = new InferenceSession(((PsiClass)psiClass).getTypeParameters(), + PsiParameter.EMPTY_ARRAY, + argumentList.getExpressions(), + PsiSubstitutor.EMPTY, null, myExpression.getManager()); + } + } + } + + if (callSession != null) { + + for (PsiTypeParameter typeParameter : session.getTypeParams()) { + callSession.addCapturedVariable(typeParameter); + } + callSession.addConstraint(new TypeCompatibilityConstraint(myT, returnType)); + final PsiSubstitutor callSubstitutor = callSession.infer(); + + if (myExpression instanceof PsiMethodCallExpression) { + returnType = PsiMethodCallExpressionImpl.captureReturnType((PsiMethodCallExpression)myExpression, method, returnType, callSubstitutor); + } + else { + returnType = callSubstitutor.substitute(returnType); + } + constraints.add(new TypeCompatibilityConstraint(myT, returnType)); //todo primitive types + } + } + return true; } if (myExpression instanceof PsiMethodReferenceExpression) { - //todo + constraints.add(new PsiMethodReferenceCompatibilityConstraint(((PsiMethodReferenceExpression)myExpression), myT)); + return true; } if (myExpression instanceof PsiLambdaExpression) { @@ -104,4 +156,37 @@ public class ExpressionCompatibilityConstraint implements ConstraintFormula { result = 31 * result + myT.hashCode(); return result; } + + @Override + public PsiExpression getExpression() { + return myExpression; + } + + @Override + public PsiType getT() { + return myT; + } + + @Override + protected InputOutputConstraintFormula createSelfConstraint(PsiType type, PsiExpression expression) { + return new ExpressionCompatibilityConstraint(expression, type); + } + + protected void collectReturnTypeVariables(InferenceSession session, + PsiExpression psiExpression, + PsiMethod interfaceMethod, + Set<InferenceVariable> result) { + if (psiExpression instanceof PsiLambdaExpression) { + final PsiType returnType = interfaceMethod.getReturnType(); + if (returnType != PsiType.VOID) { + final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)psiExpression); + for (PsiExpression expression : returnExpressions) { + final Set<InferenceVariable> resultInputVars = createSelfConstraint(returnType, expression).getInputVariables(session); + if (resultInputVars != null) { + result.addAll(resultInputVars); + } + } + } + } + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.java new file mode 100644 index 000000000000..d06538c06b41 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/InputOutputConstraintFormula.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.intellij.psi.impl.source.resolve.graphInference.constraints; + +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; +import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * User: anna + * Date: 9/25/13 + */ +public abstract class InputOutputConstraintFormula implements ConstraintFormula { + + protected abstract PsiExpression getExpression(); + protected abstract PsiType getT(); + protected abstract InputOutputConstraintFormula createSelfConstraint(PsiType type, PsiExpression expression); + protected abstract void collectReturnTypeVariables(InferenceSession session, + PsiExpression psiExpression, + PsiMethod interfaceMethod, + Set<InferenceVariable> result); + + public Set<InferenceVariable> getInputVariables(InferenceSession session) { + final PsiExpression psiExpression = getExpression(); + if (PsiPolyExpressionUtil.isPolyExpression(psiExpression)) { + final PsiType type = getT(); + if (psiExpression instanceof PsiLambdaExpression || psiExpression instanceof PsiMethodReferenceExpression) { + final InferenceVariable inferenceVariable = session.getInferenceVariable(type); + if (inferenceVariable != null) { + return Collections.singleton(inferenceVariable); + } + final PsiType functionalInterfaceType = psiExpression instanceof PsiLambdaExpression + ? ((PsiLambdaExpression)psiExpression).getFunctionalInterfaceType() + : ((PsiMethodReferenceExpression)psiExpression).getFunctionalInterfaceType(); + if (functionalInterfaceType != null) { + final PsiType functionType = + psiExpression instanceof PsiLambdaExpression + ? FunctionalInterfaceParameterizationUtil.getFunctionalType(functionalInterfaceType, (PsiLambdaExpression)psiExpression) + : functionalInterfaceType; + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionType); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); + if (interfaceMethod != null) { + + final Set<InferenceVariable> result = new HashSet<InferenceVariable>(); + final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult); + for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) { + session.collectDependencies(substitutor.substitute(parameter.getType()), result, true); + } + + collectReturnTypeVariables(session, psiExpression, interfaceMethod, result); + + return result; + } + } + } + + if (psiExpression instanceof PsiParenthesizedExpression) { + final PsiExpression expression = ((PsiParenthesizedExpression)psiExpression).getExpression(); + return expression != null ? createSelfConstraint(type, expression).getInputVariables(session) : null; + } + + if (psiExpression instanceof PsiConditionalExpression) { + final PsiExpression thenExpression = ((PsiConditionalExpression)psiExpression).getThenExpression(); + final PsiExpression elseExpression = ((PsiConditionalExpression)psiExpression).getElseExpression(); + final Set<InferenceVariable> thenResult = thenExpression != null ? createSelfConstraint(type, thenExpression).getInputVariables(session) : null; + final Set<InferenceVariable> elseResult = elseExpression != null ? createSelfConstraint(type, elseExpression).getInputVariables(session) : null; + if (thenResult == null) { + return elseResult; + } else if (elseResult == null) { + return thenResult; + } else { + thenResult.addAll(elseResult); + return thenResult; + } + } + } + return null; + } + + + @Nullable + public Set<InferenceVariable> getOutputVariables(Set<InferenceVariable> inputVariables, InferenceSession session) { + if (!PsiPolyExpressionUtil.isPolyExpression(getExpression())) { + final HashSet<InferenceVariable> mentionedVariables = new HashSet<InferenceVariable>(); + session.collectDependencies(getT(), mentionedVariables, true); + mentionedVariables.removeAll(inputVariables); + return mentionedVariables; + } + return null; + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java index 9d9dad46ffc8..d7751754ab8b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java @@ -1,8 +1,8 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints; import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; -import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; import com.intellij.psi.util.PsiUtil; import java.util.List; @@ -20,30 +20,21 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul } @Override - public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints) { - final InferenceVariable inferenceVariable = session.getInferenceVariable(myT); - if (inferenceVariable != null) { - delayedConstraints.add(this); - return true; - } + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (LambdaHighlightingUtil.checkInterfaceFunctional(myT) != null) { return false; } if (myExpression.hasFormalParameterTypes()) { } - final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(myT); + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType( + FunctionalInterfaceParameterizationUtil.getFunctionalType(myT, myExpression)); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); if (interfaceMethod == null) { return false; } - final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(myT)); + final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult); final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); - for (PsiParameter parameter : parameters) { - if (!session.isProperType(parameter.getType())) { - delayedConstraints.add(this); - return true; - } - } final PsiParameter[] lambdaParameters = myExpression.getParameterList().getParameters(); if (lambdaParameters.length != parameters.length) { @@ -53,20 +44,27 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul for (int i = 0; i < lambdaParameters.length; i++) { constraints.add(new TypeEqualityConstraint(lambdaParameters[i].getType(), substitutor.substitute(parameters[i].getType()))); } + } else { + for (PsiParameter parameter : parameters) { + if (!session.isProperType(substitutor.substitute(parameter.getType()))) { + return false; + } + } } final PsiType returnType = interfaceMethod.getReturnType(); if (returnType != null) { + final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(myExpression); if (returnType.equals(PsiType.VOID)) { - if (!myExpression.isVoidCompatible() && !(myExpression.getBody() instanceof PsiExpression)) { + if (!returnExpressions.isEmpty() && !(myExpression.getBody() instanceof PsiExpression)) { return false; } } else { - if (myExpression.isVoidCompatible()) { //not value-compatible + if (returnExpressions.isEmpty()) { //not value-compatible return false; } - for (PsiExpression returnExpressions : LambdaUtil.getReturnExpressions(myExpression)) { - constraints.add(new ExpressionCompatibilityConstraint(returnExpressions, returnType)); + for (PsiExpression returnExpression : returnExpressions) { + constraints.add(new ExpressionCompatibilityConstraint(returnExpression, substitutor.substitute(returnType))); } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java new file mode 100644 index 000000000000..d1de66e453a8 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -0,0 +1,100 @@ +/* + * 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.psi.impl.source.resolve.graphInference.constraints; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; +import com.intellij.psi.util.PsiUtil; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +/** + * User: anna + */ +public class PsiMethodReferenceCompatibilityConstraint implements ConstraintFormula { + private static final Logger LOG = Logger.getInstance("#" + PsiMethodReferenceCompatibilityConstraint.class.getName()); + private final PsiMethodReferenceExpression myExpression; + private final PsiType myT; + + public PsiMethodReferenceCompatibilityConstraint(PsiMethodReferenceExpression expression, PsiType t) { + myExpression = expression; + myT = t; + } + + @Override + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { + if (LambdaHighlightingUtil.checkInterfaceFunctional(myT) != null) { + return false; + } + + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(myT); + if (interfaceMethod == null) { + return false; + } + + final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(myT)); + final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); + for (PsiParameter parameter : parameters) { + if (!session.isProperType(substitutor.substitute(parameter.getType()))) { + return false; + } + } + + final PsiElement resolve = myExpression.resolve(); + if (resolve == null) { + return false; + } + + final PsiType returnType = interfaceMethod.getReturnType(); + LOG.assertTrue(returnType != null, interfaceMethod); + if (PsiType.VOID.equals(returnType)) { + return true; + } + + if (resolve instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)resolve; + final PsiType referencedMethodReturnType; + if (method.isConstructor()) { + final PsiClass containingClass = method.getContainingClass(); + LOG.assertTrue(containingClass != null, method); + referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass); + } + else { + referencedMethodReturnType = method.getReturnType(); + } + LOG.assertTrue(referencedMethodReturnType != null, method); + + if (myExpression.getTypeParameters().length == 0 && + ((PsiMethod)resolve).getTypeParameters().length > 0 && + PsiPolyExpressionUtil.mentionsTypeParameters(returnType, new HashSet<PsiTypeParameter>(Arrays.asList(interfaceMethod.getTypeParameters())))) { + //todo target type constraint + return true; + } + + if (PsiType.VOID.equals(referencedMethodReturnType)) { + return false; + } + + constraints.add(new TypeCompatibilityConstraint(substitutor.substitute(returnType), referencedMethodReturnType)); + } + + return true; + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/SubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/SubtypingConstraint.java index 64c28d1b462f..e2677bf7a6b3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/SubtypingConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/SubtypingConstraint.java @@ -20,7 +20,6 @@ import com.intellij.psi.impl.source.resolve.graphInference.InferenceBound; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; import com.intellij.psi.util.TypeConversionUtil; -import org.jetbrains.annotations.NotNull; import java.util.List; @@ -39,7 +38,7 @@ public class SubtypingConstraint implements ConstraintFormula { } @Override - public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints) { + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (myIsRefTypes) { if (session.isProperType(myS) && session.isProperType(myT)) { if (myT == null || myS == null) return myS == myT; @@ -127,6 +126,11 @@ public class SubtypingConstraint implements ConstraintFormula { } return false; } else { + + if (myS instanceof PsiCapturedWildcardType) { + myS = ((PsiCapturedWildcardType)myS).getWildcard(); + } + if (myS instanceof PsiWildcardType) { final PsiType sBound = ((PsiWildcardType)myS).getBound(); if (sBound != null && ((PsiWildcardType)myS).isSuper()) { @@ -140,9 +144,19 @@ public class SubtypingConstraint implements ConstraintFormula { } return false; } else { + InferenceVariable inferenceVariable = session.getInferenceVariable(myT); if (myS instanceof PsiWildcardType) { - return false; + return inferenceVariable != null && inferenceVariable.isCaptured(); } else { + if (inferenceVariable != null) { + inferenceVariable.addBound(myS, InferenceBound.EQ); + return true; + } + inferenceVariable = session.getInferenceVariable(myS); + if (inferenceVariable != null) { + inferenceVariable.addBound(myT, InferenceBound.EQ); + return true; + } constraints.add(new SubtypingConstraint(myT, myS, true)); return true; } @@ -159,6 +173,9 @@ public class SubtypingConstraint implements ConstraintFormula { SubtypingConstraint that = (SubtypingConstraint)o; if (myIsRefTypes != that.myIsRefTypes) return false; + + if (!myIsRefTypes && myS instanceof PsiCapturedWildcardType && myS != that.myS) return false; + if (myS != null ? !myS.equals(that.myS) : that.myS != null) return false; if (myT != null ? !myT.equals(that.myT) : that.myT != null) return false; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java index 353f03b66a80..cd9ec95f1d0d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeCompatibilityConstraint.java @@ -37,7 +37,7 @@ public class TypeCompatibilityConstraint implements ConstraintFormula { } @Override - public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints) { + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (session.isProperType(myT) && session.isProperType(myS)) { return TypeConversionUtil.isAssignable(myS, myT); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java index a71465653a6f..06e7b2b101ad 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java @@ -38,7 +38,7 @@ public class TypeEqualityConstraint implements ConstraintFormula { } @Override - public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints) { + public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) { if (session.isProperType(myT) && session.isProperType(myS)) { return myT.equals(myS); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerExpressionImpl.java index 4e2300fcf687..80b7e94f972b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerExpressionImpl.java @@ -18,24 +18,23 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; -import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.tree.*; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.ChildRoleBase; +import com.intellij.psi.tree.IElementType; import com.intellij.util.CharTable; import org.jetbrains.annotations.NotNull; -public class PsiArrayInitializerExpressionImpl extends ExpressionPsiElement implements PsiArrayInitializerExpression, Constants { +public class PsiArrayInitializerExpressionImpl extends ExpressionPsiElement implements PsiArrayInitializerExpression { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiArrayInitializerExpressionImpl"); public PsiArrayInitializerExpressionImpl() { - super(ARRAY_INITIALIZER_EXPRESSION); + super(JavaElementType.ARRAY_INITIALIZER_EXPRESSION); } @Override @NotNull public PsiExpression[] getInitializers(){ - return getChildrenAsPsiElements(EXPRESSION_BIT_SET, PsiExpression.ARRAY_FACTORY); + return getChildrenAsPsiElements(ElementType.EXPRESSION_BIT_SET, PsiExpression.ARRAY_FACTORY); } @Override @@ -69,10 +68,10 @@ public class PsiArrayInitializerExpressionImpl extends ExpressionPsiElement impl return null; case ChildRole.LBRACE: - return findChildByType(LBRACE); + return findChildByType(JavaTokenType.LBRACE); case ChildRole.RBRACE: - return findChildByType(RBRACE); + return findChildByType(JavaTokenType.RBRACE); } } @@ -80,17 +79,17 @@ public class PsiArrayInitializerExpressionImpl extends ExpressionPsiElement impl public int getChildRole(ASTNode child) { LOG.assertTrue(child.getTreeParent() == this); IElementType i = child.getElementType(); - if (i == COMMA) { + if (i == JavaTokenType.COMMA) { return ChildRole.COMMA; } - else if (i == LBRACE) { + else if (i == JavaTokenType.LBRACE) { return ChildRole.LBRACE; } - else if (i == RBRACE) { + else if (i == JavaTokenType.RBRACE) { return ChildRole.RBRACE; } else { - if (EXPRESSION_BIT_SET.contains(child.getElementType())) { + if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { return ChildRole.EXPRESSION_IN_LIST; } return ChildRoleBase.NONE; @@ -129,17 +128,17 @@ public class PsiArrayInitializerExpressionImpl extends ExpressionPsiElement impl if (ElementType.EXPRESSION_BIT_SET.contains(first.getElementType())) { final CharTable charTab = SharedImplUtil.findCharTableByTree(this); for (ASTNode child = first.getTreeNext(); child != null; child = child.getTreeNext()) { - if (child.getElementType() == COMMA) break; + if (child.getElementType() == JavaTokenType.COMMA) break; if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { - TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, charTab, getManager()); + TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, charTab, getManager()); super.addInternal(comma, comma, first, Boolean.FALSE); break; } } for (ASTNode child = first.getTreePrev(); child != null; child = child.getTreePrev()) { - if (child.getElementType() == COMMA) break; + if (child.getElementType() == JavaTokenType.COMMA) break; if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { - TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, charTab, getManager()); + TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, charTab, getManager()); super.addInternal(comma, comma, child, Boolean.FALSE); break; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java index 3093099e228a..5091ea053471 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.scope.PsiScopeProcessor; @@ -63,7 +64,7 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi @Nullable @Override public PsiType getFunctionalInterfaceType() { - return LambdaUtil.getFunctionalInterfaceType(this, true); + return FunctionalInterfaceParameterizationUtil.getFunctionalType(LambdaUtil.getFunctionalInterfaceType(this, true), this); } @Override @@ -118,6 +119,6 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi for (PsiParameter parameter : parameters) { if (parameter.getTypeElement() == null) return false; } - return parameters.length > 0; + return true; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java index 1dd74f133dcf..36013c3625a3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java @@ -170,7 +170,7 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements } @Nullable - private static PsiType getResultType(PsiExpression call, + private static PsiType getResultType(PsiMethodCallExpression call, PsiReferenceExpression methodExpression, JavaResolveResult result, @NotNull final LanguageLevel languageLevel) { @@ -196,40 +196,46 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements ret = ((PsiClassType)ret).setLanguageLevel(languageLevel); } if (is15OrHigher) { - final PsiSubstitutor substitutor = result.getSubstitutor(); - PsiType substitutedReturnType = substitutor.substitute(ret); - if (substitutedReturnType == null) return TypeConversionUtil.erasure(ret); - if (PsiUtil.isRawSubstitutor(method, substitutor)) { - final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret); - if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) { - return returnTypeErasure; - } - } - PsiType lowerBound = PsiType.NULL; - if (substitutedReturnType instanceof PsiCapturedWildcardType) { - lowerBound = ((PsiCapturedWildcardType)substitutedReturnType).getLowerBound(); - } else if (substitutedReturnType instanceof PsiWildcardType) { - lowerBound = ((PsiWildcardType)substitutedReturnType).getSuperBound(); - } - if (lowerBound != PsiType.NULL) { //? super - final PsiClass containingClass = method.getContainingClass(); - final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); - final PsiClass childClass = qualifierExpression != null ? PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType()) : null; - if (containingClass != null && childClass != null) { - final PsiType typeInChildClassTypeParams = TypeConversionUtil.getSuperClassSubstitutor(containingClass, childClass, PsiSubstitutor.EMPTY).substitute(ret); - final PsiClass substituted = PsiUtil.resolveClassInClassTypeOnly(typeInChildClassTypeParams); - if (substituted instanceof PsiTypeParameter) { - final PsiClassType[] extendsListTypes = substituted.getExtendsListTypes(); - if (extendsListTypes.length == 1) { - return extendsListTypes[0]; - } - } + return captureReturnType(call, method, ret, result.getSubstitutor()); + } + return TypeConversionUtil.erasure(ret); + } + } + + public static PsiType captureReturnType(PsiMethodCallExpression call, + PsiMethod method, + PsiType ret, + PsiSubstitutor substitutor) { + PsiType substitutedReturnType = substitutor.substitute(ret); + if (substitutedReturnType == null) return TypeConversionUtil.erasure(ret); + if (PsiUtil.isRawSubstitutor(method, substitutor)) { + final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret); + if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) { + return returnTypeErasure; + } + } + PsiType lowerBound = PsiType.NULL; + if (substitutedReturnType instanceof PsiCapturedWildcardType) { + lowerBound = ((PsiCapturedWildcardType)substitutedReturnType).getLowerBound(); + } else if (substitutedReturnType instanceof PsiWildcardType) { + lowerBound = ((PsiWildcardType)substitutedReturnType).getSuperBound(); + } + if (lowerBound != PsiType.NULL) { //? super + final PsiClass containingClass = method.getContainingClass(); + final PsiExpression qualifierExpression = call.getMethodExpression().getQualifierExpression(); + final PsiClass childClass = qualifierExpression != null ? PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType()) : null; + if (containingClass != null && childClass != null) { + final PsiType typeInChildClassTypeParams = TypeConversionUtil.getSuperClassSubstitutor(containingClass, childClass, PsiSubstitutor.EMPTY).substitute(ret); + final PsiClass substituted = PsiUtil.resolveClassInClassTypeOnly(typeInChildClassTypeParams); + if (substituted instanceof PsiTypeParameter) { + final PsiClassType[] extendsListTypes = substituted.getExtendsListTypes(); + if (extendsListTypes.length == 1) { + return extendsListTypes[0]; } } - return PsiImplUtil.normalizeWildcardTypeByPosition(substitutedReturnType, call); } - return TypeConversionUtil.erasure(ret); } + return PsiImplUtil.normalizeWildcardTypeByPosition(substitutedReturnType, call); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 46788578dee6..537ce23c3a77 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -72,6 +72,15 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } @Override + public boolean isExact() { + PsiElement resolve = resolve(); + if (resolve instanceof PsiMethod) { + return !((PsiMethod)resolve).isVarArgs(); + } + return true; + } + + @Override public PsiExpression getQualifierExpression() { final PsiElement qualifier = getQualifier(); return qualifier instanceof PsiExpression ? (PsiExpression)qualifier : null; diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 27e4227b5afb..6992e9f5796e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -51,15 +51,15 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ private static final Logger LOG = Logger.getInstance("#com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver"); private final PsiElement myArgumentsList; - private final PsiType[] myActualParameterTypes; + private PsiType[] myActualParameterTypes; protected LanguageLevel myLanguageLevel; public JavaMethodsConflictResolver(@NotNull PsiExpressionList list, @NotNull LanguageLevel languageLevel) { - this(list, list.getExpressionTypes(), languageLevel); + this(list, null, languageLevel); } public JavaMethodsConflictResolver(@NotNull PsiElement argumentsList, - @NotNull PsiType[] actualParameterTypes, + PsiType[] actualParameterTypes, @NotNull LanguageLevel languageLevel) { myArgumentsList = argumentsList; myActualParameterTypes = actualParameterTypes; @@ -71,7 +71,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (conflicts.isEmpty()) return null; if (conflicts.size() == 1) return conflicts.get(0); - boolean atLeastOneMatch = checkParametersNumber(conflicts, myActualParameterTypes.length, true); + boolean atLeastOneMatch = checkParametersNumber(conflicts, getActualParameterTypes().length, true); if (conflicts.size() == 1) return conflicts.get(0); checkSameSignatures(conflicts); @@ -80,7 +80,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ checkAccessStaticLevels(conflicts, true); if (conflicts.size() == 1) return conflicts.get(0); - checkParametersNumber(conflicts, myActualParameterTypes.length, false); + checkParametersNumber(conflicts, getActualParameterTypes().length, false); if (conflicts.size() == 1) return conflicts.get(0); final int applicabilityLevel = checkApplicability(conflicts); @@ -96,7 +96,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ checkSpecifics(conflicts, applicabilityLevel, myLanguageLevel); if (conflicts.size() == 1) return conflicts.get(0); - checkPrimitiveVarargs(conflicts, myActualParameterTypes.length); + checkPrimitiveVarargs(conflicts, getActualParameterTypes().length); if (conflicts.size() == 1) return conflicts.get(0); checkAccessStaticLevels(conflicts, false); @@ -109,8 +109,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ private void checkLambdaApplicable(@NotNull List<CandidateInfo> conflicts, @NotNull LanguageLevel languageLevel) { if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) return; - for (int i = 0; i < myActualParameterTypes.length; i++) { - PsiType parameterType = myActualParameterTypes[i]; + for (int i = 0; i < getActualParameterTypes().length; i++) { + PsiType parameterType = getActualParameterTypes()[i]; if (parameterType instanceof PsiLambdaExpressionType) { final PsiLambdaExpression lambdaExpression = ((PsiLambdaExpressionType)parameterType).getExpression(); for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext(); ) { @@ -122,7 +122,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (methodParameters.length == 0) continue; final PsiParameter param = i < methodParameters.length ? methodParameters[i] : methodParameters[methodParameters.length - 1]; final PsiType paramType = param.getType(); - if (!LambdaUtil.isAcceptable(lambdaExpression, conflict.getSubstitutor().substitute(paramType), true)) { + if (!LambdaUtil.isAcceptable(lambdaExpression, conflict.getSubstitutor().substitute(paramType), lambdaExpression.hasFormalParameterTypes())) { iterator.remove(); } else { /*todo @@ -141,7 +141,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } } } - checkMoreSpecificReturnType(conflicts, myActualParameterTypes, languageLevel); + checkMoreSpecificReturnType(conflicts, getActualParameterTypes(), languageLevel); } public void checkSpecifics(@NotNull List<CandidateInfo> conflicts, @@ -426,6 +426,14 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ (method.getCurrentFileResolveScope() instanceof PsiImportStaticStatement ? 0 : 1); } + private PsiType[] getActualParameterTypes() { + if (myActualParameterTypes == null) { + LOG.assertTrue(myArgumentsList instanceof PsiExpressionList, myArgumentsList); + myActualParameterTypes = ((PsiExpressionList)myArgumentsList).getExpressionTypes(); + } + return myActualParameterTypes; + } + private enum Specifics { FIRST, SECOND, @@ -489,7 +497,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ ProgressManager.checkCanceled(); PsiType type1 = classSubstitutor1.substitute(types1[i]); PsiType type2 = classSubstitutor2.substitute(types2[i]); - PsiType argType = i < myActualParameterTypes.length ? myActualParameterTypes[i] : null; + PsiType argType = i < getActualParameterTypes().length ? getActualParameterTypes()[i] : null; boolean boxingInFirst = false; if (isBoxingHappened(argType, type1, languageLevel)) { @@ -691,6 +699,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ for (int functionalInterfaceIdx = 0; functionalInterfaceIdx < actualParameterTypes.length; functionalInterfaceIdx++) { final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method); final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict); + if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiLambdaExpressionType) { + final PsiLambdaExpression lambdaExpression = ((PsiLambdaExpressionType)actualParameterTypes[functionalInterfaceIdx]).getExpression(); + if (!lambdaExpression.hasFormalParameterTypes()) { + return Specifics.NEITHER; + } + } if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiLambdaExpressionType || actualParameterTypes[functionalInterfaceIdx] instanceof PsiMethodReferenceType) { if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) { Specifics moreSpecific1 = comparePrimitives(actualParameterTypes[functionalInterfaceIdx], interfaceReturnType, interfaceReturnType1); diff --git a/java/java-tests/testData/codeInsight/completion/normal/NoFieldsInImplements.java b/java/java-tests/testData/codeInsight/completion/normal/NoFieldsInImplements.java new file mode 100644 index 000000000000..bb4a834340df --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/NoFieldsInImplements.java @@ -0,0 +1,9 @@ +public class Doo implements Intf.I<caret> { +} + + + +interface Intf { + int INT_FIELD = 2; + interface Inner {} +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/NoFieldsInImplements_after.java b/java/java-tests/testData/codeInsight/completion/normal/NoFieldsInImplements_after.java new file mode 100644 index 000000000000..ea272a1f909d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/NoFieldsInImplements_after.java @@ -0,0 +1,9 @@ +public class Doo implements Intf.Inner<caret> { +} + + + +interface Intf { + int INT_FIELD = 2; + interface Inner {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AmbiguousTypeParamVsConcrete.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AmbiguousTypeParamVsConcrete.java new file mode 100644 index 000000000000..272fb292d2a3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AmbiguousTypeParamVsConcrete.java @@ -0,0 +1,22 @@ +public class CssPropertyValueImpl extends CssTableValueBase<CssPropertyValue, Object> implements CssPropertyValue { + public CssPropertyValueImpl(final Type type) { + super(type); + } +} + +public abstract class CssTableValueBase<V extends CssTableValue, T> implements CssTableValue<V, T> { + + protected CssTableValueBase(final Type type) { + } + + protected CssTableValueBase(final T value) { + } +} + +enum Type {} + +interface CssTableValue<A, B> { +} + +interface CssPropertyValue extends CssTableValue<CssPropertyValue, Object> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AnnotationsAsPartOfModifierList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AnnotationsAsPartOfModifierList.java new file mode 100644 index 000000000000..3fca0c0f200b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AnnotationsAsPartOfModifierList.java @@ -0,0 +1,9 @@ +@Deprecated @SuppressWarnings("") +<error descr="Class 'Foo' must either be declared abstract or implement abstract method 'run()' in 'Runnable'">public class Foo implements Runnable</error> { + +} + +class F { + @Deprecated @SuppressWarnings("") <error descr="'f()' is already defined in 'F'">void f()</error> {} + @Deprecated @SuppressWarnings("") <error descr="'f()' is already defined in 'F'">void f()</error> {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Autoboxing.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Autoboxing.java new file mode 100644 index 000000000000..9815668ba31f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Autoboxing.java @@ -0,0 +1,69 @@ +public class Autoboxing { + public boolean compare(short s, Integer i) { + return i == s; //OK, i is unboxed + } + + public boolean compare(Short s, Integer i) { + return <error descr="Operator '==' cannot be applied to 'java.lang.Integer', 'java.lang.Short'">i == s</error>; //comparing as references + } + + void f(Integer i) { + switch(i) { + default: + } + } + + { + Object data = 1; + boolean is1 = <error descr="Operator '==' cannot be applied to 'java.lang.Object', 'int'">data == 1</error>; + } + + //IDEADEV-5549: Short and double are convertible + public static double f () { + Short s = 0; + return (double)s; + } + + //IDEADEV-5613 + class DumbTest { + private long eventId; + + public int hashCode() { + return ((Long) eventId).hashCode(); + } + } + + public static void main(String[] args) { + Long l = 0L; + Short s = 0; + + int d = <error descr="Inconvertible types; cannot cast 'java.lang.Long' to 'int'">(int)l</error>; + d = (int)s; + + short t = 0; + Integer d1 = <error descr="Inconvertible types; cannot cast 'short' to 'java.lang.Integer'">(Integer) t</error>; + Byte b = <error descr="Inconvertible types; cannot cast 'short' to 'java.lang.Byte'">(Byte) t</error>; + + } + + { + { + boolean cond = true; + // test for JLS3 bug, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6888770 + Byte B = 0; + byte b = 0; + byte value = cond ? B : b; ///////// + + short s = 0; + Short S = 0; + short rs = cond ? S : s; + + char c = 0; + Character C = 0; + char rc = cond ? C : c; + + boolean bb = cond ? Boolean.FALSE : true; + } + + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AutoboxingConstructors.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AutoboxingConstructors.java new file mode 100644 index 000000000000..12c5332362d6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AutoboxingConstructors.java @@ -0,0 +1,13 @@ +public class Test { + + public Test(Object a) { + } + + public Test(int i) { + this(new Integer(i)); + } + + public Test(long l) { + this(new Long(l)); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AutoboxingMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AutoboxingMethods.java new file mode 100644 index 000000000000..d02099757c94 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/AutoboxingMethods.java @@ -0,0 +1,44 @@ +public class Autoboxing { + void method(int i) { + System.out.println("i = " + i); + } + + void method(Integer integer) { + System.out.println("integer = " + integer); + } + + void m1(Integer integer) { } + void m2(int i) { } + + { + method(10); + method(new Integer(10)); + m1(10); + m1(new Integer(10)); + m2(10); + m2(new Integer(10)); + } +} +public class Autoboxing1 { + void method(String s, int i) { + System.out.println("i = " + i); + } + + void method(String s, Object o) { + System.out.println("integer = " + o); + } + + { + method("abc", new Integer(10)); + method("abc", 10); + } +} + +class BoxingConflict { + public static void main(String[] args) { + add<error descr="Ambiguous method call: both 'BoxingConflict.add(long, Long)' and 'BoxingConflict.add(Long, Long)' match">(0L, 0L)</error>; + } + + public static void add(long k, Long v) { } + public static void add(Long k, Long v) { } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/BooleanInferenceFromIfCondition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/BooleanInferenceFromIfCondition.java new file mode 100644 index 000000000000..44fbeef42671 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/BooleanInferenceFromIfCondition.java @@ -0,0 +1,12 @@ +public class Main { + public <T> T getAttribute() {return null;} + public <T> T getAttribute(T def) {return null;} + + { + if (getAttribute()) {} + + while (getAttribute()) {} + do {} while (getAttribute()); + for(int i = 0; getAttribute(); i++); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/BoxingSpecific.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/BoxingSpecific.java new file mode 100644 index 000000000000..382f4e7d099b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/BoxingSpecific.java @@ -0,0 +1,7 @@ +import java.util.*; + +abstract class A { + void computeCostIfNeeded(Map<Object, Integer> costMap) { + Math.min(costMap.get(null), 1); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CaptureTopLevelWildcardsForConditionalExpression.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CaptureTopLevelWildcardsForConditionalExpression.java new file mode 100644 index 000000000000..86c2e40fcdd0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CaptureTopLevelWildcardsForConditionalExpression.java @@ -0,0 +1,6 @@ +import java.util.*; +class Bug { + void foo(Double d) { + List<Class<?>> list = Arrays.asList(d == null ? Object.class : d.getClass()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CaptureWildcardsInTypeCasts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CaptureWildcardsInTypeCasts.java new file mode 100644 index 000000000000..9bd704bd12f8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CaptureWildcardsInTypeCasts.java @@ -0,0 +1,8 @@ +import java.util.Collection; + +class Foo { + private void test() { + Object x = null; + ((java.util.Collection<?>)x).add<error descr="'add(capture<?>)' in 'java.util.Collection' cannot be applied to '(java.lang.String)'">("")</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardAssignments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardAssignments.java new file mode 100644 index 000000000000..08761a681886 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/CapturedWildcardAssignments.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2012 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. + */ + +import java.util.*; + +public class Test { + public static void bar() { + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends java.util.Iterator>>', required: 'java.lang.Class<? extends java.util.Iterator<?>>'">Class<? extends Iterator<?>> c = foo();</error> + } + + public static Class<? extends Iterator> foo() { + return null; + } +} + +class Example { + static List<? extends AbstractTreeNode> treeNodes = null; + + public static void main(String[] args) { + for (AbstractTreeNode<String> treeNode : treeNodes) { + + } + } + +} +class AbstractTreeNode<T> {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ClassInheritance.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ClassInheritance.java new file mode 100644 index 000000000000..1a4e80f95827 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ClassInheritance.java @@ -0,0 +1,122 @@ +class D implements I<I>{ +} +class DT<T> implements I<T>{ +} + +interface I <T> { +} + +<error descr="'I' cannot be inherited with different type arguments: 'I' and 'D'">class CCC extends D implements I<D></error> { +} +abstract class CCC2<T> extends DT<T> implements I<T> { +} + +class a extends b<d, c> implements c<d, c<c,c>>, d<b<c<c,c>,d>> {} +public class b<K,V> implements c<K, c<V,V>> { } +interface c<K,V> extends d<b<V,K>> {} +interface d<K> {} + +// extending final classes in bounds +class C<T extends String> { + <E extends Integer> void f() {} +} + +class GenericExtendItself<T, U extends T> +{ + GenericExtendItself<Object,Object> foo; +} + + +//////////////////// +public abstract class ZZZZ<E> { + public abstract E getElement(); +} +abstract class Z<E> extends ZZZZ<E> {} +class Z2 extends Z<Integer> { + public Integer getElement() { + return null; + } +} +///////////////// +class BaseC <E> { + E remove(){ + return null; + } +} + +class DerivedC extends BaseC<String> { + public String remove() { + String s = super.remove(); + return null; + } +} + +/// raw in the multiple supers +interface Int<T> { + AClass<T> f(); +} +abstract class AClass<T> implements Int<T> { + public abstract AClass<T> f(); +} + +class MyClass extends AClass implements Int{ + public AClass f() { + return null; + } +} + +class A<T>{ + A(){} + A(T t){} + + { + new A<A>(new A()){}; + } +} + +//IDEADEV-4733: this overriding is OK +class Outer<T> +{ + public class Inner + { + private final T t; + + public Inner(T t) { this.t = t; } + + public T getT() { return t; } + + public String toString() { return t.toString(); } + } +} + +class Other extends Outer<String> +{ + public class Ither extends Outer<String>.Inner + { + public Ither() + { + super("hello"); //valid super constructor call + } + } +} + +//end of //IDEADEV-4733 +interface AI { +} +interface BI { +} +abstract class AbstractClass<T> { + AbstractClass(Class<T> clazz) { + } +} +class ConcreteClass extends AbstractClass<AI> { + ConcreteClass() { + super(AI.class); + } + class InnerClass extends AbstractClass<BI> { + InnerClass() { + super(BI.class); // + } + } +} +/////////////////////// diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ConditionalExpression.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ConditionalExpression.java new file mode 100644 index 000000000000..88c1d57fc7bb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ConditionalExpression.java @@ -0,0 +1,21 @@ +import java.util.TreeMap; +import java.util.HashMap; +import java.util.Map; + +class Test { + boolean f () { + return false; + } + + Boolean g (int i) { + //This is OK thanks to boxing f() + return i > 0 ? f () : null; + } + + { + Object values = new Object(); + //IDEADEV-1756: this should be OK + final Map<Object,Object> newValues = true ? new TreeMap<Object,Object>() : new HashMap<Object,Object>(); + newValues.get(values); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ContinueInferenceAfterFirstRawResult.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ContinueInferenceAfterFirstRawResult.java new file mode 100644 index 000000000000..eeab573a57a1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ContinueInferenceAfterFirstRawResult.java @@ -0,0 +1,23 @@ +import java.util.*; + +class Test { + + List<String> getList(Function<Object, String> function) { + /* + * When the first argument below is a raw type it turns red because IDEA thinks the return + * type is Collection<>. javac and Eclipse don't care + */ + return transform(new ArrayList(), new ArrayList<String>(), function); + } + + <R, S, T extends Collection<S>> T transform(Iterable<? extends R> oldCollection, T newCollection, Function<R, S> function) { + for (R r : oldCollection) { + newCollection.add(function.apply(r)); + } + return newCollection; + } + + interface Function<X, Y> { + Y apply(X input); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ConvertibleTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ConvertibleTypes.java new file mode 100644 index 000000000000..572ef4a2f301 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ConvertibleTypes.java @@ -0,0 +1,90 @@ +import java.util.Collection; +import java.util.ArrayList; + +interface YO<<warning descr="Type parameter 'T' is never used">T</warning>> {} +interface YO1 extends YO<String> {} +interface YO2 extends YO<Integer> {} + +public class ConvertibleTest { + + YO2 bar (YO1 s) { + return <error descr="Inconvertible types; cannot cast 'YO1' to 'YO2'">(YO2) s</error>; + } +} + + +//IDEA-1097 +interface Interface1 {} +interface Interface2 {} + +class Implementation implements Interface1 {} + +public class InconvertibleTypesTest <E extends Interface2> +{ + E thing; + + public E getThing() { + return thing; + } + + Implementation foo(InconvertibleTypesTest<? extends Interface1> i2) { + //This is a valid cast from intersection type + return (Implementation) i2.getThing(); + } +} + +class MyCollection extends ArrayList<Integer> {} +class Tester { + Collection<String> x(MyCollection l) { + return <error descr="Inconvertible types; cannot cast 'MyCollection' to 'java.util.Collection<java.lang.String>'">(Collection<String>) l</error>; + } +} + + +class IDEADEV3978 { + class Constructor<T> { + Class<T> getDeclaringClass() { + return null; + } + } + public static void foo(Constructor<?> constructor) { + if(constructor.getDeclaringClass() == String.class) { //captured wildcard is convertible + System.out.println("yep"); + } + } +} + +class C2<T> { + void f(T t) { + if (t instanceof Object[]) return; + } +} + +class Casting { + void f(Object o) + { + if (o instanceof int[]) return; + + Object obj1 = (Object)true; f(obj1); + Object ob = (Number)1; f(ob); + Object ob2 = (Object)1; f(ob2); + + } + + public static <T> T convert(Class<T> clazz, Object obj) { + if (obj == null) return null; + if (String[].class == clazz) + return <warning descr="Unchecked cast: 'java.lang.String[]' to 'T'">(T) parseArray(obj)</warning>; + return null; + } + + private static String[] parseArray(Object obj) { + return obj.toString().split(","); + } +} + +class CastPrimitiveToTypeParam<T> { + T foo() { + return <error descr="Inconvertible types; cannot cast 'int' to 'T'">(T)1</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DeepConflictingReturnTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DeepConflictingReturnTypes.java new file mode 100644 index 000000000000..0477aeefdd3e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DeepConflictingReturnTypes.java @@ -0,0 +1,21 @@ +class W { + Object f() { + return 0; + } +} + +class WW extends W { + String f() { + return null; + } +} + +interface IQ { + void f(); +} + + +<error descr="'f()' in 'WW' clashes with 'f()' in 'IQ'; attempting to use incompatible return type">class WWW extends WW implements IQ</error> { + +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DifferentTypeParamsInOverloadedMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DifferentTypeParamsInOverloadedMethods.java new file mode 100644 index 000000000000..4feabc994633 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DifferentTypeParamsInOverloadedMethods.java @@ -0,0 +1,28 @@ +import java.util.*; +class Nav { + interface Sized {} + interface Stream<<warning descr="Type parameter 'T' is never used">T</warning>> { } + + private static<U, T extends Sized & Iterable<U>> Stream<U> stream(T entity, int flags) { + System.out.println(entity); + System.out.println(flags); + return null; + } + + private static<U, T extends Iterable<U>> Stream<U> <warning descr="Private method 'stream(T, int)' is never used">stream</warning>(T entity, int flags) { + System.out.println(entity); + System.out.println(flags); + return null; + } + + static class A<T> implements Iterable<T>, Sized { + public Iterator<T> iterator() { + return null; + } + } + + public static void main(String[] args) { + Stream<String> aStream = stream(new A<String>(), 0); + System.out.println(aStream); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DisableCastingToNestedWildcards.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DisableCastingToNestedWildcards.java new file mode 100644 index 000000000000..9c076abce2ac --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DisableCastingToNestedWildcards.java @@ -0,0 +1,32 @@ +import java.util.List; + +public class Test { + + interface P { + + } + + public abstract class AP implements P { + + } + + public class AP1 extends AP { + + } + + public class AP2 extends AP { + + } + + private static final List<Class<AP1>> AP_LIST = listOf(AP1.class); + + + private static <T> List<T> listOf(T... ts) { + return null; + } + + public static void test() { + List<Class<? extends AP>> apList1 = <error descr="Inconvertible types; cannot cast 'java.util.List<java.lang.Class<Test.AP1>>' to 'java.util.List<java.lang.Class<? extends Test.AP>>'">(List<Class<? extends AP>>) AP_LIST</error>; + List<Class<? super AP1>> apList2 = <error descr="Inconvertible types; cannot cast 'java.util.List<java.lang.Class<Test.AP1>>' to 'java.util.List<java.lang.Class<? super Test.AP1>>'">(List<Class<? super AP1>>) AP_LIST</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DisableWithinBoundsCheckForSuperWildcards.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DisableWithinBoundsCheckForSuperWildcards.java new file mode 100644 index 000000000000..703c3776ed69 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DisableWithinBoundsCheckForSuperWildcards.java @@ -0,0 +1,15 @@ +import java.util.Comparator; + +public class Main2 { + static class OfRef<T> { + public OfRef() { + this((Comparator<? super T>) naturalOrder()); + } + + public OfRef(Comparator<? super T> comparator) { + } + static <K extends Comparable<? super K>> Comparator<K> naturalOrder() { + return null; + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DoNotAcceptLowerBoundIfRaw.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DoNotAcceptLowerBoundIfRaw.java new file mode 100644 index 000000000000..b132d7418269 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/DoNotAcceptLowerBoundIfRaw.java @@ -0,0 +1,17 @@ +import java.util.*; + +class Test { + interface Condition<K> {} + class IOC<M> implements Condition {} + + static <T> List<T> filter(T[] c, Condition<? super T> con) { + return null; + } + + interface OE {} + interface LOE extends OE {} + + void foo(OE[] es, IOC<LOE> con) { + List<LOE> l = filter(es, con); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Enum.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Enum.java new file mode 100644 index 000000000000..027ada4fa3d3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Enum.java @@ -0,0 +1,205 @@ +enum Operation { + X; + static int s = 0; + public static final String constS = ""; + Operation() { + int i = <error descr="It is illegal to access static member 's' from enum constructor or instance initializer">Operation.s</error>; + i = <error descr="It is illegal to access static member 's' from enum constructor or instance initializer">s</error>; + <error descr="It is illegal to access static member 's' from enum constructor or instance initializer">s</error> = 0; + final int x = Integer.MAX_VALUE; + String co = constS; + // TODO: unclear + //Operation o = X; + } + static { + int i = Operation.s; + i = s; + s = 0; + final int x = Integer.MAX_VALUE; + String co = constS; + // TODO: unclear + //Operation o = X; + } + { + int i = <error descr="It is illegal to access static member 's' from enum constructor or instance initializer">Operation.s</error>; + i = <error descr="It is illegal to access static member 's' from enum constructor or instance initializer">s</error>; + <error descr="It is illegal to access static member 's' from enum constructor or instance initializer">s</error> = 0; + final int x = Integer.MAX_VALUE; + String co = constS; + // TODO: unclear + //Operation o = X; + + Operation ooo = <error descr="Enum types cannot be instantiated">new Operation()</error>; + } + + <error descr="'values()' is already defined in 'Operation'">void values()</error> {} + void values(int i) {} + void valueOf() {} + <error descr="'valueOf(String)' is already defined in 'Operation'">void valueOf(String s)</error> {} +} + +class exte extends <error descr="Cannot inherit from final 'Operation'">Operation</error> { +} + +class use { + void f(Operation op) { + switch(op) { + case <error descr="An enum switch case label must be the unqualified name of an enumeration constant">Operation.X</error>: break; + } + switch(op) { + case X: break; + } + switch(op) { + case <error descr="Duplicate label 'X'">X</error>: break; + case <error descr="Duplicate label 'X'">X</error>: break; + } + } +} + +enum pubCtr { + X(1); + <error descr="Modifier 'public' not allowed here">public</error> pubCtr(int i) {} +} +enum protCtr { + X(1); + <error descr="Modifier 'protected' not allowed here">protected</error> protCtr(int i) {} +} +<error descr="Modifier 'final' not allowed here">final</error> enum Fin { Y } +<error descr="Modifier 'abstract' not allowed here">abstract</error> enum Abstr { } + +enum params<error descr="Enum may not have type parameters"><T></error> { +} + +enum OurEnum { + A, B, C; + + OurEnum() { + } + + { + Enum<OurEnum> a = <error descr="It is illegal to access static member 'A' from enum constructor or instance initializer">A</error>; + OurEnum enumValue = <error descr="It is illegal to access static member 'B' from enum constructor or instance initializer">B</error>; + switch (enumValue) { + } + + switch (enumValue) { + case A: + break; + } + } +} + +enum TestEnum +{ + A(<error descr="Illegal forward reference">B</error>), B(A); + TestEnum(TestEnum other) { + <error descr="Call to super is not allowed in enum constructor">super(null, 0)</error>; + } +} + +<error descr="Class 'abstr' must either be declared abstract or implement abstract method 'run()' in 'Runnable'">enum abstr implements Runnable</error> { +} + +//this one is OK, enum constants are checked instead of enum itself +enum abstr1 implements Runnable { + A { + public void run() {} + }; +} + +class X extends <error descr="Classes cannot directly extend 'java.lang.Enum'">Enum</error> { + public X(String name, int ordinal) { + super(name, ordinal); + } +} + +enum StaticInEnumConstantInitializer { + AN { + <error descr="Inner classes cannot have static declarations"><error descr="Modifier 'static' not allowed here">static</error></error> class s { } + private <error descr="Inner classes cannot have static declarations">static</error> final String t = String.valueOf(1); + }; +} + +interface Barz { + void baz(); +} + +enum Fooz implements Barz { + <error descr="Class 'Fooz' must implement abstract method 'baz()' in 'Barz'">FOO</error>; +} + +/////////////////////// +class sss { + void f() { + <error descr="Enum must not be local">enum EEEE</error> { EE, YY }; + } +} + +////////////////////// +//This code is OK +enum PowerOfTen { + ONE(1),TEN(10), + HUNDRED(100) { + public String toString() { + return Integer.toString(super.val); + } + }; + + private final int val; + + PowerOfTen(int val) { + this.val = val; + } + + public String toString() { + return name().toLowerCase(); + } + + public static void main(String[] args) { + System.out.println(ONE + " " + TEN + " " + HUNDRED); + } +} + +//IDEADEV-8192 +enum MyEnum { + X1, X2; + + private static MyEnum[] values = values(); + + public static void test() { + + for (MyEnum e : values) { // values is colored red + e.toString(); + } + } +} +//end of IDEADEV-8192 + +class EnumBugIDEADEV15333 { + public enum Type { one, to } + Type type = Type.one; + public void main() { + switch(type){ + case one: + Object one = new Object(); + } + } +} + +class NestedEnums { + enum E1 { } + + class C2 { + <error descr="Inner classes cannot have static declarations">enum E2</error> { } + } + + static class C3 { + enum E3 { } + } + + { + new C3() { + <error descr="Inner classes cannot have static declarations">enum E2</error> { } + }; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Enum56239.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Enum56239.java new file mode 100644 index 000000000000..28e844a96bf5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Enum56239.java @@ -0,0 +1,34 @@ +enum IDEA56239 { + A, B() { + { + System.out.println(<error descr="It is illegal to access static member 'A' from enum constructor or instance initializer">A</error>); + System.out.println(<error descr="It is illegal to access static member 'FOO' from enum constructor or instance initializer">FOO</error>); + System.out.println(FOO1); + System.out.println(<error descr="It is illegal to access static member 'C' from enum constructor or instance initializer">C</error>); + } + }, C(<error descr="Illegal forward reference">D</error>), D; + + public static String FOO = ""; + public static final String FOO1 = ""; + + IDEA56239() { + } + + IDEA56239(IDEA56239 t) { + System.out.println(<error descr="It is illegal to access static member 'A' from enum constructor or instance initializer">A</error>); + System.out.println(<error descr="It is illegal to access static member 'FOO' from enum constructor or instance initializer">FOO</error>); + System.out.println(FOO1); + } + + { + System.out.println(<error descr="It is illegal to access static member 'A' from enum constructor or instance initializer">A</error>); + System.out.println(<error descr="It is illegal to access static member 'FOO' from enum constructor or instance initializer">FOO</error>); + System.out.println(FOO1); + } + + void foo() { + System.out.println(A); + System.out.println(FOO); + System.out.println(FOO1); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java new file mode 100644 index 000000000000..1abae6b17a2d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java @@ -0,0 +1,24 @@ +<error descr="Modifier 'abstract' not allowed here">abstract</error> enum OurEnum { + <error descr="Class 'Anonymous class derived from OurEnum' must implement abstract method 'foo()' in 'OurEnum'">A</error> { + }, + <error descr="'OurEnum' is abstract; cannot be instantiated">B</error>, + C { + void foo() {} + } + ; + + abstract void foo(); +} + +enum xxx { + <error descr="'xxx' is abstract; cannot be instantiated">X</error>, + <error descr="Class 'Anonymous class derived from xxx' must implement abstract method 'f()' in 'xxx'">Y</error> { + }; + + abstract void f(); +} + +enum ok { + X { void f() {} }; + abstract void f(); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ErasureTypeParameterBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ErasureTypeParameterBound.java new file mode 100644 index 000000000000..ffa889735ef5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ErasureTypeParameterBound.java @@ -0,0 +1,9 @@ +interface Foo<T> { + public <A extends T, B extends A> void bar(Class<A> key, B value); +} + +class FooImpl implements Foo<String>{ + public <A extends String, B extends A> void bar(Class<A> key, B value) { + + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Exceptions.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Exceptions.java new file mode 100644 index 000000000000..039cfe64b491 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Exceptions.java @@ -0,0 +1,23 @@ +class C <T extends Exception> { + void foo () throws T {} + void bar () { + <error descr="Unhandled exception: T">foo ();</error> + } + + <T extends Error> void goo() { + try { + int i = 12; + } catch (<error descr="Cannot catch type parameters">T</error> ex) { + } + } +} + +//IDEADEV-4169: no problem here +interface Blub { + public <E extends Throwable> void Switch() throws E; +} + +class Blib implements Blub { + public <E extends Throwable> void Switch() throws E { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ExplicitMethodParameters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ExplicitMethodParameters.java new file mode 100644 index 000000000000..22c3b7ed7856 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ExplicitMethodParameters.java @@ -0,0 +1,20 @@ +import java.util.*; + +class Foo { + <T> void foo() {} + <T1 extends List, T2> void foo1() {} + void bar() {} + <T> void xyz(T l) {} + + { + foo(); + this.<String>foo(); + this.<error descr="Wrong number of type arguments: 2; required: 1"><String, Integer></error>foo(); + this.<String>bar(); + this.<String, Integer>bar(); + this.<<error descr="Type parameter 'java.lang.String' is not within its bound; should implement 'java.util.List'">String</error>, Integer>foo1(); + this.<String>xyz<error descr="'xyz(java.lang.String)' in 'Foo' cannot be applied to '(java.lang.Integer)'">(Integer.valueOf("27"))</error>; + ArrayList list = new <String>ArrayList<String>(); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FailedInferenceWithBoxing.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FailedInferenceWithBoxing.java new file mode 100644 index 000000000000..7e690fd4789a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FailedInferenceWithBoxing.java @@ -0,0 +1,12 @@ +class Test { + public <T> T doStuff() { + return null; + } + public boolean test() { + return doStuff(); + } + + public Boolean test1() { + return doStuff(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Fields.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Fields.java new file mode 100644 index 000000000000..4b9dffc1dccd --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Fields.java @@ -0,0 +1,10 @@ +import java.util.*; + +class C { + static final List EMPTY = new ArrayList(0); + + void m() { + List<String> list = C.<error descr="Reference parameters are not allowed here"><String></error>EMPTY; + System.out.println(list); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FixedFailedInferenceWithBoxing.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FixedFailedInferenceWithBoxing.java new file mode 100644 index 000000000000..7e690fd4789a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FixedFailedInferenceWithBoxing.java @@ -0,0 +1,12 @@ +class Test { + public <T> T doStuff() { + return null; + } + public boolean test() { + return doStuff(); + } + + public Boolean test1() { + return doStuff(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FlattenIntersectionType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FlattenIntersectionType.java new file mode 100644 index 000000000000..7fa937d1f1d5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/FlattenIntersectionType.java @@ -0,0 +1,16 @@ +interface BusinessEntity<E extends BusinessEntity<E>> { +} + +interface EntityId<E extends BusinessEntity> { + E getEntity(); +} + +public class MyTest { + <T extends BusinessEntity<T>> T getEntity(EntityId<T> defaultValue) { + return getEntityID(defaultValue).getEntity(); + } + + public <P extends EntityId<?>> P getEntityID(P defaultValue) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ForeachTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ForeachTypes.java new file mode 100644 index 000000000000..bd06d92a3b5b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ForeachTypes.java @@ -0,0 +1,29 @@ +class a { + void f(int[] c) { + for (int i:c) {} + for (<error descr="Incompatible types. Found: 'int', required: 'char'">char i:c</error>) {} + for (double i:c) {} + double[] db = null; + for (<error descr="Incompatible types. Found: 'double', required: 'int'">int i:db</error>) {} + for (double i:db) {} + + java.util.List list = null; + for (<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">String i:list</error>) {} + for (Object o:list) {} + + java.util.List<Integer> ct = null; + for (Number n:ct) {} + for (Object n:ct) {} + for (Integer n:ct) {} + for (<error descr="Incompatible types. Found: 'java.lang.Integer', required: 'java.lang.String'">String i:ct</error>) {} + for (<error descr="Incompatible types. Found: 'java.lang.Integer', required: 'java.util.List<java.lang.Integer>'">java.util.List<Integer> i:ct</error>) {} + + Object o = null; + for (Object oi: (Iterable)o) {} + + + for (<error descr="Incompatible types. Found: 'double', required: 'int'">int i:db</error>) { + for (<error descr="Incompatible types. Found: 'java.lang.Object', required: 'int'">int p: list</error>) {} + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/GenericExtendException.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/GenericExtendException.java new file mode 100644 index 000000000000..b9c5d5aba92f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/GenericExtendException.java @@ -0,0 +1,4 @@ +class T extends Exception {} +class E<T> extends <error descr="Generic class may not extend 'java.lang.Throwable'">Error</error> {} +class M<T2 extends Exception> extends <error descr="Generic class may not extend 'java.lang.Throwable'">T</error> {} +class Ex<X,Y> extends <error descr="Generic class may not extend 'java.lang.Throwable'">Throwable</error> {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/GenericsOverrideMethodInRawInheritor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/GenericsOverrideMethodInRawInheritor.java new file mode 100644 index 000000000000..b0a6f187f25b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/GenericsOverrideMethodInRawInheritor.java @@ -0,0 +1,9 @@ +import java.util.List; + +<error descr="'method(List<String>)' in 'Implementation' clashes with 'method(List<String>)' in 'IfcWithGenericMethod'; both methods have same erasure, yet neither overrides the other">class Implementation implements IfcWithGenericMethod</error> { + public void method(final List<String> strings) {} +} + +interface IfcWithGenericMethod<T> { + void method(List<String> strings); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA103760.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA103760.java new file mode 100644 index 000000000000..e4d05f070410 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA103760.java @@ -0,0 +1,9 @@ +import java.util.*; +public class MyList extends ArrayList {} + +public class Test { + public void test() { + List<? super List> list = new ArrayList<List>(); + list.add(new MyList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104100.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104100.java new file mode 100644 index 000000000000..e854f4ac59ab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104100.java @@ -0,0 +1,7 @@ +public class TestGenericMap<A extends Comparable<A>, B extends Comparable<B>> +{ + public TestGenericMap<B, A> inverse() + { + return new TestGenericMap<>(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104160.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104160.java new file mode 100644 index 000000000000..92e5b57c39e4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104160.java @@ -0,0 +1,13 @@ +import java.util.*; +class Test<T> { + public static void foo(<error descr="'Test.this' cannot be referenced from a static context">T</error> t) {} + public void bar(T t) {} + + static class A extends ArrayList<<error descr="'Test.this' cannot be referenced from a static context">T</error>> { + static void boo(<error descr="'Test.this' cannot be referenced from a static context">T</error> t){} + } + + class B extends ArrayList<T> { + void foo(T r){} + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104992.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104992.java new file mode 100644 index 000000000000..5e468424d18f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA104992.java @@ -0,0 +1,17 @@ +import java.util.Collection; +import java.util.Set; + +class FooObject<T> {} +class FooId<T extends FooObject> {} + +interface Bar { + <T extends FooObject, I extends FooId<? extends T>> T get(I key); + <T extends FooObject, I extends FooId<? extends T>> Collection<T> get(Collection<I> keys); +} + +public class Target { + void foo(Bar bar) { + final Set<FooId<?>> keys = null; + final Collection<FooObject> values = bar.get(keys); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA105695.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA105695.java new file mode 100644 index 000000000000..8b1a9622af96 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA105695.java @@ -0,0 +1,10 @@ +import java.util.Map; + +public class Test { + void bar(Prop p) { + Map<? extends String, ? extends String> map = <error descr="Inconvertible types; cannot cast 'Prop' to 'java.util.Map<? extends java.lang.String,? extends java.lang.String>'">(Map<? extends String, ? extends String>)p</error>; + } +} + +abstract class Hashtble<K,V> implements Map<K,V> {} +abstract class Prop extends Hashtble<Object, Object>{} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA105846.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA105846.java new file mode 100644 index 000000000000..04d39bd4c2ce --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA105846.java @@ -0,0 +1,6 @@ +class MyClass { + public static void main(Class<? extends MyClass> clazz){ + clazz = (Class<? extends MyClass>) clazz.getSuperclass(); + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? super capture<? extends MyClass>>>', required: 'java.lang.Class<? extends MyClass>'">clazz = clazz.getSuperclass()</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA106964.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA106964.java new file mode 100644 index 000000000000..5745a60e4c09 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA106964.java @@ -0,0 +1,12 @@ +import java.io.Serializable; + +public abstract class Test { + + abstract <T> T test(Class<T> cls); + + abstract <T> T test(Serializable type); + + private void call(){ + <error descr="Incompatible types. Found: 'java.lang.String[]', required: 'java.lang.String'">String s = test(String[].class);</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107440.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107440.java new file mode 100644 index 000000000000..21073ff0cd9b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107440.java @@ -0,0 +1,18 @@ +class GoodCodeRed { + static class ClassA { + } + + static class Pair<T, N> { + } + + <T extends ClassA, M extends T, N extends Number> void max(final M object, Pair<T, N> attribute, final N cnt) { + } + + <T extends ClassA, M extends T, N extends String> void max(final M object, Pair<T, N> attribute, final N str) { + } + + + { + max(new ClassA(), new Pair<ClassA, Integer>(), 1); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107654.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107654.java new file mode 100644 index 000000000000..7af6110553db --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107654.java @@ -0,0 +1,3 @@ +class X<A extends X<A>> { + static class Y<B extends Y> extends X<<error descr="Type parameter 'B' is not within its bound; should extend 'X<B>'">B</error>> {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107782.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107782.java new file mode 100644 index 000000000000..4beb3ffde901 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107782.java @@ -0,0 +1,15 @@ +public class Test { + { + final MyResult hello = parseXML(new Parser()); + } + public <R, P extends AbstractParser & Result<R>> R parseXML(P parser) { + R result = null; + return result; + } +} +class MyResult {} + +class AbstractParser {} +interface Result<T> {} +class Parser extends AbstractParser implements Result {} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107957.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107957.java new file mode 100644 index 000000000000..1228be1a48b7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA107957.java @@ -0,0 +1,37 @@ +class Test1 { + + private static final Foo<Boolean> test = new Foo().method(Boolean.TRUE); + + public static void main(String[] args) { + System.out.println(test); + } + + public static class Foo<T> { + public Foo<Boolean> method(boolean arg) { + return null; + } + + public <T extends Enum<T>> Foo<T> method(T arg) { + return null; + } + } +} + +class Test2 { + + private static final Foo<Boolean> test = Foo.method(Boolean.TRUE); + + public static void main(String[] args) { + System.out.println(test); + } + + public static class Foo<T> { + public static Foo<Boolean> method(boolean arg) { + return null; + } + + public static <T extends Enum<T>> Foo<T> method(T arg) { + return null; + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA108287.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA108287.java new file mode 100644 index 000000000000..e717d2d2d558 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA108287.java @@ -0,0 +1,9 @@ +class Foo<T> { + static class Nested {}; +} +class Bar extends Foo<<error descr="Nested is not accessible in current context">Bar.Nested</error>> {} + +interface FooI<T> { + interface Nested {}; +} +interface BarI extends FooI<<error descr="Nested is not accessible in current context">BarI.Nested</error>> {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA109556.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA109556.java new file mode 100644 index 000000000000..4701229903f1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA109556.java @@ -0,0 +1,9 @@ +class Base { } +class Extended extends Base {} + +class Test<T extends Base> { + <T extends Base, U extends T> void test(T x, Class<U> test) {} + { + test(new Extended(), Base.class); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA109875.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA109875.java new file mode 100644 index 000000000000..d799ba286e09 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA109875.java @@ -0,0 +1,13 @@ +import java.util.Collections; +import java.util.Set; + +public class Test<Y> { + + public static <K> Test<K> doTest(K k){ + return null; + } + + public static void main(String[] args) { + Test.<Set<String>>doTest(Collections.emptySet()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110568.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110568.java new file mode 100644 index 000000000000..ed9eedd55331 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110568.java @@ -0,0 +1,20 @@ +import java.util.Collection; + +public class IncorrectError extends NarrowClass { + public Collection<String> bar() { + return super.doStuff(); + } +} + +interface Interface { + Collection<String> doStuff(); +} + +class NarrowClass extends BaseClass implements Interface { +} + +class BaseClass { + public Collection doStuff() { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110869.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110869.java new file mode 100644 index 000000000000..acc0272de2da --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110869.java @@ -0,0 +1,12 @@ +class A { +} + +abstract class B { + public <T extends A> T getA(Class<T> aClass) { + return null; + } + + void foo(Class<?> aClass) { + A a = <error descr="Inferred type 'capture<?>' for type parameter 'T' is not within its bound; should extend 'A'">getA(aClass)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110947.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110947.java new file mode 100644 index 000000000000..5f7ac80942a2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA110947.java @@ -0,0 +1,17 @@ +interface Result {} + +interface Command<R extends Result> {} + +interface Procedure<C extends Command<Result>> { +} + +abstract class ProcedureService { + abstract <C extends Command<Result>> Class<? extends Procedure<Command<Result>>> getProcedure(Class<C> cmd); + + public <C extends Command<Result>> void execute(Class<? extends Command> aClass) { + Class<Procedure<Command<Result>>> procedureClass = getProcedure(aClass); + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends Command>>', required: 'java.lang.Class<Command>'">Class<Command> c = aClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends Command>>', required: 'java.lang.Class<C>'">Class<C> c1 = aClass;</error> + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA111085.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA111085.java new file mode 100644 index 000000000000..e67e0d3d77c5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA111085.java @@ -0,0 +1,20 @@ +import java.io.*; +import java.util.List; + +class Main { + public <T> T foo(String str, Class<T> classOfT) { + return null; + } + + public <T> T foo(String str, Serializable typeOfT) { + return null; + } + + { + asList(foo("", String[].class)); + } + + public static <T> List<T> asList(T... a) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA112122.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA112122.java new file mode 100644 index 000000000000..bb1e1abba0b3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA112122.java @@ -0,0 +1,16 @@ +class Cast<T> implements SemElement { + + { + final SemKey<? extends Cast> key = null; + final Cast semElement = getSemElement(key); + } + + public <T extends SemElement> T getSemElement(SemKey<T> key) { + return null; + } + + + class SemKey<T extends SemElement> {} +} + +interface SemElement {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA113225.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA113225.java new file mode 100644 index 000000000000..7b4bbaba7fa3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA113225.java @@ -0,0 +1,11 @@ +import java.io.Serializable; + +public class Test { + public <T extends Serializable> void foo(byte[] data) { + T foo = (T) data; + } + + public <T extends Serializable & Runnable> void bar(byte[] data) { + T bar = <error descr="Inconvertible types; cannot cast 'byte[]' to 'T'">(T) data</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA18425.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA18425.java new file mode 100644 index 000000000000..7a496b293a2f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA18425.java @@ -0,0 +1,15 @@ +public abstract class BiFunction<A,B> { + public abstract B apply(A a); + public abstract A unapply(B b); + public BiFunction<B,A> flip() { + return new BiFunction<B, A>() { + public A apply(B b) { + return BiFunction.this.unapply(b); + } + + public B unapply(A a) { + return BiFunction.this.apply(a); + } + }; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA20244.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA20244.java new file mode 100644 index 000000000000..ee5235ad87fe --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA20244.java @@ -0,0 +1,23 @@ +import java.util.Collection; +class Test { + public static final UnaryFunction<Object, Object, RuntimeException> unaryFunction = new UnaryFunction<Object, Object, RuntimeException>() { + public Object execute(Object o) throws RuntimeException { + return null; + } + }; + + public static <A, B, X extends Throwable> void someMethod() { + transformCollection(null, unaryFunction, null); + } + + public static <A, B, X extends Throwable> void transformCollection(Collection<? extends A> input, UnaryFunction<A, B, X> transform, Collection<? super B> output) throws X { + for (A a : input) { + B b = transform.execute(a); + output.add(b); + } + } +} + +interface UnaryFunction<A, B, X extends Throwable> { + public B execute(A a) throws X; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA20573.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA20573.java new file mode 100644 index 000000000000..22bd7a39c8a9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA20573.java @@ -0,0 +1,26 @@ +public class GoodCodeIsRed { + + public void test() { + FileIF file = new FileImpl(); + file.getInputStream(); + } +} + +class FileImpl implements FileIF { + + public void getInputStream() { + } + +} + +interface FileIF extends BasicFileIF, DataSource { +} + +interface BasicFileIF { + void getInputStream(); +} + + +interface DataSource { + void getInputStream() throws java.io.IOException; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21597.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21597.java new file mode 100644 index 000000000000..368992438e26 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21597.java @@ -0,0 +1,7 @@ +interface Foo<A> {} +interface Bar extends Foo<Boolean> {} +class FooFactory { + public <A> Foo<A> getFoo() { + return (Foo<A>) new Bar() {}; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21602.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21602.java new file mode 100644 index 000000000000..217e1fde531b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21602.java @@ -0,0 +1,17 @@ +import java.util.Collection; +import java.util.Collections; + +public class IDEABug { + + static class ClassA { + static <T> void sayHello(Collection<? extends T> msg) {} + } + + static class ClassB extends ClassA { + <error descr="'sayHello(Collection<? extends T>)' in 'IDEABug.ClassB' clashes with 'sayHello(Collection<? extends T>)' in 'IDEABug.ClassA'; both methods have same erasure, yet neither hides the other">static <T extends String> void sayHello(Collection<? extends T> msg)</error> {} + } + + public static void main(String[] args) { + ClassB.sayHello(Collections.<String>emptyList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21602_7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21602_7.java new file mode 100644 index 000000000000..217e1fde531b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA21602_7.java @@ -0,0 +1,17 @@ +import java.util.Collection; +import java.util.Collections; + +public class IDEABug { + + static class ClassA { + static <T> void sayHello(Collection<? extends T> msg) {} + } + + static class ClassB extends ClassA { + <error descr="'sayHello(Collection<? extends T>)' in 'IDEABug.ClassB' clashes with 'sayHello(Collection<? extends T>)' in 'IDEABug.ClassA'; both methods have same erasure, yet neither hides the other">static <T extends String> void sayHello(Collection<? extends T> msg)</error> {} + } + + public static void main(String[] args) { + ClassB.sayHello(Collections.<String>emptyList()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA22005.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA22005.java new file mode 100644 index 000000000000..78aad3c656f0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA22005.java @@ -0,0 +1,13 @@ +class Test { + interface Foo<T> { + void boo(T t); + } + + private static void f(Foo<?>... fs) { + fs[0].boo<error descr="'boo(capture<?>)' in 'Test.Foo' cannot be applied to '(java.lang.String)'">("hey!")</error>; + } + + private static void f1(Foo<? extends String>... fs) { + fs[0].boo<error descr="'boo(capture<? extends java.lang.String>)' in 'Test.Foo' cannot be applied to '(java.lang.String)'">("hey!")</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA22079.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA22079.java new file mode 100644 index 000000000000..f3b25c959fd5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA22079.java @@ -0,0 +1,18 @@ +import java.util.List; + +public class SubClass extends BaseClass<String> { + public static void main(String[] args) { + new SubClass().method(null); + } + + @Override + public void method(List list) {} +} + +class BaseClass<E> implements EntityListListener<E> { + public void method(List list) {} +} + +interface EntityListListener<E> { + public void method(List<E> list); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA27080.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA27080.java new file mode 100644 index 000000000000..c5f2696f7eb0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA27080.java @@ -0,0 +1,9 @@ +abstract class TypeToken<T> { + private <T> TypeToken<T> tt(Class<T> t) { return null; } + private <T> void checkedTestInexactSupertype(TypeToken<T> expectedSuperclass, TypeToken<? extends T> type) {} + TypeToken<? super Integer> ft = null; + + { + checkedTestInexactSupertype(ft, tt(Integer.class)); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA27185.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA27185.java new file mode 100644 index 000000000000..73800a6801e1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA27185.java @@ -0,0 +1,13 @@ +import java.io.Serializable; +interface A<T extends Serializable> +{ + <S extends T> S foo(S s); +} +class B implements A<Number> +{ + @Override + public <S extends Number> S foo(S s) + { + return s; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA55510.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA55510.java new file mode 100644 index 000000000000..f85901d45f81 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA55510.java @@ -0,0 +1,22 @@ +abstract class IdeaBugTest<M extends IdeaBugTest.Mapping> +{ + static class Mapping {} +} + +class BugTestSub extends IdeaBugTest<<error descr="SubMapping is not accessible in current context">BugTestSub.SubMapping</error>> +{ + public abstract static class SubMapping extends Mapping {} +} + +class BugTestSub1 extends IdeaBugTest<BugTestSub1.SubMapping> +{ + public abstract static class SubMapping extends IdeaBugTest.Mapping {} //fqn here +} + +class AbstractSettings { + interface State {} +} +interface SomeInterface<T> {} +class Settings extends AbstractSettings implements SomeInterface<Settings.MyState> { + static class MyState implements State {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57259.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57259.java new file mode 100644 index 000000000000..10f9e8706702 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57259.java @@ -0,0 +1,8 @@ +class A<T extends A.B> { + class B extends A<B> {} +} + +class C<T> { + class D extends C<T> {} + <T extends C<String>.D> void foo(){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57264.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57264.java new file mode 100644 index 000000000000..485126b2aede --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57264.java @@ -0,0 +1,17 @@ +class A1<T> {} +class B1<T extends A1<? super A1<? super T>>>{ + { + T a = null; + <error descr="Incompatible types. Found: 'T', required: 'A1<? super T>'">A1<? super T> b = a;</error> + } +} + +class A<T> {} +class B<T extends A<? super A<? super T>>> { + + void bar(T x){ + foo(x); + } + void foo(A<? super T> x){} + void foo(Object x){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57265.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57265.java new file mode 100644 index 000000000000..787606b8a926 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57265.java @@ -0,0 +1,5 @@ +class A<T> { + class B<S> { + <error descr="Improper formed type; some type parameters are missing">A<T>.B</error> x; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57271.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57271.java new file mode 100644 index 000000000000..25b6c9c3c279 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57271.java @@ -0,0 +1,9 @@ +abstract class A<S> { + abstract <T> T foo(T x, T y); + + { + A<? extends A<? extends Throwable>> a = null; + A<? extends A<?>> b = null; + foo(a, b); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57272.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57272.java new file mode 100644 index 000000000000..343d6678f038 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57272.java @@ -0,0 +1,8 @@ +abstract class A<S> { + abstract <T extends A<? extends Throwable>> T foo(T y); + + { + A<?> a = null; + <error descr="Inferred type 'A<capture<?>>' for type parameter 'T' is not within its bound; should extend 'A<? extends java.lang.Throwable>'">foo(a)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57275.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57275.java new file mode 100644 index 000000000000..934d10748306 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57275.java @@ -0,0 +1,13 @@ +abstract class A { + abstract <S, T extends Iterable<S>> void foo(); + + { + foo(); + } +} + +class X{ + <T extends Enum<T>> void foo(){ + foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57284.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57284.java new file mode 100644 index 000000000000..a9dc4c23c386 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57284.java @@ -0,0 +1,6 @@ +abstract class A<S> { + abstract <T extends S> void foo(); + void bar(A<? super Exception> x){ + x.<<error descr="Type parameter 'String[]' is not within its bound; should extend 'capture<? super java.lang.Exception>'">String[]</error>>foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57285.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57285.java new file mode 100644 index 000000000000..c420eb9d94f0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57285.java @@ -0,0 +1,12 @@ +package pck; + +abstract class A<S> { + S y; + void bar(A<? extends int[]> x){ + Object obj = <error descr="Array type expected; found: 'capture<? extends int[]>'">x.y</error>[0]; + } + + void baz(A<? super int[]> x){ + Object obj = <error descr="Array type expected; found: 'capture<? super int[]>'">x.y</error>[0]; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57286.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57286.java new file mode 100644 index 000000000000..737870579aaa --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57286.java @@ -0,0 +1,6 @@ +class A<T> { + <S extends A<? extends T>> void foo(){} + void bar(A<?> a){ + a.<<error descr="Type parameter 'A' is not within its bound; should extend 'A<capture<?>>'">A<?></error>>foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57289.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57289.java new file mode 100644 index 000000000000..eb64128e7448 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57289.java @@ -0,0 +1,8 @@ +class C<T> { + void foo(C<C<?>> x) { + C<Object> c = bar(x); + } + <T> C<T> bar(C<? super C<T>> x){ + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57307.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57307.java new file mode 100644 index 000000000000..8f9ffe6eef74 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57307.java @@ -0,0 +1,10 @@ +class C<<warning descr="Type parameter 'T' is never used">T</warning>>{} +class A<<warning descr="Type parameter 'S' is never used">S</warning>,<warning descr="Type parameter 'T' is never used">T</warning>> {} +class B<S,T extends C<S>> extends A<S,T> { + void foo(B<?,?> x){ + bar(x); + } + <S, T> void bar(A<S,T> x){ + System.out.println(x); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57308.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57308.java new file mode 100644 index 000000000000..154c1439e4e2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57308.java @@ -0,0 +1,13 @@ +class A<T> {} + +interface IA{ + <T> void foo(A<? extends T[]> x); +} +interface IB{ + <T> int foo(A<? extends T> x); +} +class C { + <<error descr="'foo(A<? extends T>)' in 'IB' clashes with 'foo(A<? extends T[]>)' in 'IA'; both methods have same erasure, yet neither overrides the other"></error><error descr="'foo(A<? extends T>)' in 'IB' clashes with 'foo(A<? extends T[]>)' in 'IA'; both methods have same erasure, yet neither overrides the other"></error>T extends IA & IB> void bar(T x, A<String[]> y){ + <error descr="Incompatible types. Found: 'void', required: 'int'">int z = x.foo(y);</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57309.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57309.java new file mode 100644 index 000000000000..ffb43170e8c2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57309.java @@ -0,0 +1,9 @@ +class A<S> { + void bar(A<? super Exception> x, A<? super Throwable> y){ + foo(x, y); + } + + <T> T foo(A<? super T> x, A<? super T> y){ + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57310.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57310.java new file mode 100644 index 000000000000..41a80a8f30e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57310.java @@ -0,0 +1,9 @@ +class A<T> { + Exception[] bar(A<? super Exception[]> x, A<? super Throwable[]> y){ + return this.foo(x, y); + } + + <T> T foo(A<? super T> x, A<? super T> y){ + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57311.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57311.java new file mode 100644 index 000000000000..a566b5b0cf60 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57311.java @@ -0,0 +1,11 @@ +class A<T> { + A<A<? extends T>> foo(){ + return null; + } + + void bar(A<?> x){ + baz<error descr="'baz(A<A<?>>)' in 'A' cannot be applied to '(A<A<capture<?>>>)'">(x.foo())</error>; + } + + <S> void baz(A<A<? extends S>> x){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57312.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57312.java new file mode 100644 index 000000000000..b60c9786285c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57312.java @@ -0,0 +1,11 @@ +class A<T> { + A<A<? super A<T>>> foo(){ + return null; + } + + void bar(A<?> x){ + baz(x.foo()); + } + + <S> void baz(A<A<? super A<S>>> x){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57315.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57315.java new file mode 100644 index 000000000000..d8558722d26e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57315.java @@ -0,0 +1,4 @@ +class A<K>{ + void foo(A<A<A<String>>> b){ bar(b); } + <U, S extends A<U>, T extends A<S>> void bar(A<T> a){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57325.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57325.java new file mode 100644 index 000000000000..b4933e8fcdc1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57325.java @@ -0,0 +1,12 @@ +interface IA<T> { + IA<? extends T> foo(); +} + +class A { + void baz(IA<? extends Throwable> x) { + bar(x.foo()); + } + + <T extends Throwable> void bar(IA<T> a) { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57334.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57334.java new file mode 100644 index 000000000000..068f8d95d0a7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57334.java @@ -0,0 +1,41 @@ +abstract class A<T, S> { + abstract <T> void foo(A<? extends T, ? extends T> x); + void bar(A<? extends Throwable, ? extends Exception> x){ + foo(x); + } +} + +abstract class A0<T, S> { + abstract <T> void foo(A0<? extends T, ? extends T> x); + void bar(A0<? extends Exception, ? extends Throwable> x){ + foo(x); + } +} + +abstract class A1<T, S> { + abstract <T> void foo(A1<? extends T, ? extends T> x); + void bar(A1<? extends Throwable, Exception> x){ + foo(x); + } +} + +abstract class A10<T, S> { + abstract <T> void foo(A10<? extends T, ? extends T> x); + void bar(A10<Throwable, Exception> x){ + foo(x); + } +} + +abstract class A2<T, S> { + abstract <T> void foo(A2<? super T, ? super T> x); + void bar(A2<? super Exception, ? super Throwable> x){ + foo(x); + } +} + +abstract class A20<T, S> { + abstract <T> void foo(A20<? super T, ? super T> x); + void bar(A20<? super Throwable, ? super Exception> x){ + foo(x); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57339.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57339.java new file mode 100644 index 000000000000..01d694a65f15 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57339.java @@ -0,0 +1,7 @@ +abstract class A { + abstract <T extends Iterable & Cloneable> void foo(); +} + +abstract class B extends A{ + abstract <T extends Cloneable & Iterable> void foo(); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57340.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57340.java new file mode 100644 index 000000000000..7bbba7bc65fc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57340.java @@ -0,0 +1,26 @@ +class A<T, S> { +} + +class B<L> { + A<L, L> foo() { + return null; + } + + void bar(B<?> b, A<?, ?> foo1) { + baz(b.foo()); + A<?, ?> foo = b.foo(); + baz<error descr="'baz(A<K,K>)' in 'B' cannot be applied to '(A<capture<?>,capture<?>>)'">(foo)</error>; + baz<error descr="'baz(A<K,K>)' in 'B' cannot be applied to '(A<capture<?>,capture<?>>)'">(foo1)</error>; + } + + <K> void baz(A<K, K> a) { + } +} + + + +class C<T,S>{} +class D<T> extends C<T,T> { + void foo(D<?> x){ bar(x); } + <T> void bar(C<T,T> x){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57346.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57346.java new file mode 100644 index 000000000000..e4bfd479d32c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57346.java @@ -0,0 +1,5 @@ + +class D<T> { + void foo(D<D<?>> x){ this.bar(x); } + <T extends Throwable> void bar(D<? super D<T>> x){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57378.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57378.java new file mode 100644 index 000000000000..31e47fa1f0a5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57378.java @@ -0,0 +1,9 @@ +interface IA { + <T extends Cloneable & Iterable> void foo(T x); + <T extends Iterable & Cloneable> void foo(T x); +} + +abstract class A<T extends Throwable> { + abstract <T extends Comparable<?> & Iterable> void foo(T x, A<?> y); + abstract <T extends Iterable & Comparable<?>> void foo(T x, A<? extends Throwable> y); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57391.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57391.java new file mode 100644 index 000000000000..dfc34f84189f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57391.java @@ -0,0 +1,7 @@ +abstract class B<T> { + abstract <S extends T> void foo(T x, S y); +} + +class A extends B<String> { + void foo(String x, String y) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57410.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57410.java new file mode 100644 index 000000000000..19e90a314f89 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57410.java @@ -0,0 +1,10 @@ + +interface IA { + <T> void a(Iterable<String> x); +} + +interface IB { + <T> void a(Iterable x); +} + +<error descr="'a(Iterable)' in 'IB' clashes with 'a(Iterable<String>)' in 'IA'; both methods have same erasure, yet neither overrides the other">abstract class C implements IA, IB</error> {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57411.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57411.java new file mode 100644 index 000000000000..89aea4a65223 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57411.java @@ -0,0 +1,18 @@ +class A<S> { + <T> T foo(T x, S y){ + return x; + } +} + +class B<S> extends A<S> { + Object foo(Object x, Object y){ + return x; + } +} + +<error descr="'foo(T, S)' in 'A' clashes with 'foo(Object, Object)' in 'B'; both methods have same erasure, yet neither overrides the other">class C extends B<String></error> { + @Override + <T> T foo(T x, String y) { + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'T'">return super.foo(x, y);</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java new file mode 100644 index 000000000000..699a60db6d01 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57413.java @@ -0,0 +1,7 @@ +class A<T> { + <T extends A<T>> void foo(T x){} + + void bar(A<?> x){ + foo<error descr="'foo(T)' in 'A' cannot be applied to '(A<capture<?>>)'">(x)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57439.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57439.java new file mode 100644 index 000000000000..d0063b559f65 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57439.java @@ -0,0 +1,43 @@ +class A<T> {} + +class B<T> extends A<A<T>> { + void bar(B<?> b, B<? extends String> eb, B<? super String> sb, B<String> s) { + foo(b); + foo(eb); + foo(sb); + foo(s); + + <error descr="Inferred type 'capture<?>' for type parameter 'T' is not within its bound; should extend 'java.lang.String'">foo1(b)</error>; + foo1(eb); + <error descr="Inferred type 'capture<? super java.lang.String>' for type parameter 'T' is not within its bound; should extend 'java.lang.String'">foo1(sb)</error>; + foo1(s); + + foo2(b); + foo2(eb); + foo2(sb); + foo2(s); + + foo3<error descr="'foo3(A<A<?>>)' in 'B' cannot be applied to '(B<capture<?>>)'">(b)</error>; + foo3<error descr="'foo3(A<A<? extends java.lang.String>>)' in 'B' cannot be applied to '(B<capture<? extends java.lang.String>>)'">(eb)</error>; + foo3<error descr="'foo3(A<A<?>>)' in 'B' cannot be applied to '(B<capture<? super java.lang.String>>)'">(sb)</error>; + foo3<error descr="'foo3(A<A<? extends java.lang.String>>)' in 'B' cannot be applied to '(B<java.lang.String>)'">(s)</error>; + + foo4<error descr="'foo4(A<A<? super T>>)' in 'B' cannot be applied to '(B<capture<?>>)'">(b)</error>; + foo4<error descr="'foo4(A<A<? super T>>)' in 'B' cannot be applied to '(B<capture<? extends java.lang.String>>)'">(eb)</error>; + foo4<error descr="'foo4(A<A<? super java.lang.String>>)' in 'B' cannot be applied to '(B<capture<? super java.lang.String>>)'">(sb)</error>; + foo4<error descr="'foo4(A<A<? super java.lang.String>>)' in 'B' cannot be applied to '(B<java.lang.String>)'">(s)</error>; + + foo5(b); + foo5(eb); + foo5(sb); + foo5(s); + } + + + <T> void foo(A<A<T>> x) {} + <T extends String> void foo1(A<A<T>> x) {} + <T> void foo2(A<? extends A<T>> x) {} + <T> void foo3(A<A<? extends T>> x) {} + <T> void foo4(A<A<? super T>> x) {} + <T> void foo5(A<? super A<T>> x) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57446.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57446.java new file mode 100644 index 000000000000..9cd9f2a0baff --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57446.java @@ -0,0 +1,7 @@ +abstract class A<T>{ + abstract void foo(T x); + class B extends A<B> { + @Override + void foo(A<T>.B x) {} + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57482.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57482.java new file mode 100644 index 000000000000..0f88cf3c0c40 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57482.java @@ -0,0 +1,9 @@ +class C<T>{ + static class D{ + class E{ + <error descr="'C.this' cannot be referenced from a static context">T</error> x; + } + } +} + +class T{} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57484.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57484.java new file mode 100644 index 000000000000..4e2aff70f544 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57484.java @@ -0,0 +1,7 @@ +abstract class C{ + abstract <T> T foo(T x, T y); + + { + Long s = (Long) foo(1,1L); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57485.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57485.java new file mode 100644 index 000000000000..5ab00da7e757 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57485.java @@ -0,0 +1,9 @@ +abstract class A{ + abstract <S extends Number & Comparable<?>, T extends Number & Comparable<? extends S>> T foo( + Comparable<? extends T> x, + Comparable<? extends T> y); + + { + foo(1, 1L); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57486.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57486.java new file mode 100644 index 000000000000..a3c16dd186b6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57486.java @@ -0,0 +1,8 @@ +class B<T,S>{} +abstract class A<T> { + abstract B<T,T> foo(); + <T> void baz(B<T,T> b){} + void bar(A<?> a){ + baz(a.foo()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57492.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57492.java new file mode 100644 index 000000000000..62d81386d388 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57492.java @@ -0,0 +1,17 @@ +abstract class A<T>{ + abstract <S> S foo(S x, S y); + <S extends Number & Comparable<? extends Number>> void baz(A<S> a){} + + void bar(A<Long> x, A<Integer> y){ + baz<error descr="'baz(A<S>)' in 'A' cannot be applied to '(A<capture<? extends java.lang.Number & java.lang.Comparable<? extends java.lang.Comparable<?>>>>)'">(foo(x, y))</error>; + } +} + +abstract class A1<T>{ + abstract <S> S foo(S x, S y); + <T extends Number & Comparable<?>, S extends Number & Comparable<? extends T>> void baz(A1<S> a){} + + void bar(A1<Long> x, A1<Integer> y){ + baz<error descr="'baz(A1<S>)' in 'A1' cannot be applied to '(A1<capture<? extends java.lang.Number & java.lang.Comparable<? extends java.lang.Comparable<?>>>>)'">(foo(x, y))</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57493.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57493.java new file mode 100644 index 000000000000..f344fd83cbc4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57493.java @@ -0,0 +1,8 @@ +abstract class A<T>{ + abstract <S> S foo(S x, S y); + <S extends Number & Comparable<?>> void baz(A<S> a){} + + void bar(A<Long> x, A<Integer> y){ + baz<error descr="'baz(A<S>)' in 'A' cannot be applied to '(A<capture<? extends java.lang.Number & java.lang.Comparable<? extends java.lang.Comparable<?>>>>)'">(foo(x, y))</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57494.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57494.java new file mode 100644 index 000000000000..38bafca27f55 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57494.java @@ -0,0 +1,16 @@ +import java.util.*; +abstract class A { + abstract <T> T baz(List<? super List<? super T>> a); + + void bar(List<List<?>> x){ + String s = baz(x); + } +} + +abstract class A1{ + abstract <T> T baz(List<? super T> a); + + void bar(List<?> x){ + String o = baz<error descr="'baz(java.util.List<? super T>)' in 'A1' cannot be applied to '(java.util.List<capture<?>>)'">(x)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57495.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57495.java new file mode 100644 index 000000000000..63f8c9199382 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57495.java @@ -0,0 +1,9 @@ +import java.util.*; +interface C<T> extends List<List<T>>{} +abstract class A { + abstract <T> T baz(List<? super List<? super T>> a); + + void bar(C<?> x){ + baz<error descr="'baz(java.util.List<? super java.util.List<? super T>>)' in 'A' cannot be applied to '(C<capture<?>>)'">(x)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57496.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57496.java new file mode 100644 index 000000000000..e33bb5328270 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57496.java @@ -0,0 +1,11 @@ +interface I<T>{} +interface A extends I<A[]>{} +interface B extends I<B[]>{} + +abstract class c{ + abstract <T> T baz(T x, T y); + + void bar(A x, B y){ + baz(x, y); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57509.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57509.java new file mode 100644 index 000000000000..59251593cd56 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57509.java @@ -0,0 +1,9 @@ +import java.util.List; + +abstract class X { + abstract <T> void copy(List<T> dest, List<? extends T> src); + + void foo(List<? super Throwable> x, List<? extends Exception> y){ + copy(x, y); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java new file mode 100644 index 000000000000..5d1507f69558 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java @@ -0,0 +1,6 @@ +class C<T extends C<? extends C<? extends T>>>{ + void foo(C<?> x){ + bar<error descr="'bar(C<T>)' in 'C' cannot be applied to '(C<capture<?>>)'">(x)</error>; + } + <T extends C<? extends T>> void bar(C<T> x){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57534.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57534.java new file mode 100644 index 000000000000..ea3e242fa54c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57534.java @@ -0,0 +1,15 @@ +abstract class C{ + abstract <T extends Cloneable> void foo(T x); + abstract <T extends Object & Cloneable> void foo(T x); + void bar(Cloneable x){ + foo<error descr="Ambiguous method call: both 'C.foo(Cloneable)' and 'C.foo(Cloneable)' match">(x)</error>; + } +} + +abstract class D { + abstract <T extends Iterable<? extends Exception>> void foo(T x); + abstract <T extends Object & Iterable<? super Exception>> void foo(T x); + void bar(Iterable<Exception> x){ + foo<error descr="Ambiguous method call: both 'D.foo(Iterable<Exception>)' and 'D.foo(Iterable<Exception>)' match">(x)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57539.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57539.java new file mode 100644 index 000000000000..196929487d73 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57539.java @@ -0,0 +1,13 @@ +class E<T> { + Class<T[]> o = <error descr="Cannot select from a type variable">T[]</error>.class; +} + +class MyClass<T> { + Class<T[]> getTs() { + return <error descr="Cannot select from a type variable">T[]</error>.class; + } + + public static void main(String[] args) { + new MyClass<String>().getTs(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57557.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57557.java new file mode 100644 index 000000000000..8f482f957540 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57557.java @@ -0,0 +1,7 @@ +abstract class A { + abstract void foo(Enum<?> x); +} + +class B extends A { + void foo(Enum<? extends Enum<?>> x) { } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57563.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57563.java new file mode 100644 index 000000000000..183736232a93 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57563.java @@ -0,0 +1,7 @@ +class C { + void foo(){} +} + +class D extends C{ + <error descr="'foo()' in 'D' clashes with 'foo()' in 'C'; both methods have same erasure, yet neither hides the other">static <T> void foo()</error>{} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57650.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57650.java new file mode 100644 index 000000000000..cfbc4135b8da --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57650.java @@ -0,0 +1,7 @@ +abstract class A { + abstract <T> T foo(); + + { + int x = foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57667.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57667.java new file mode 100644 index 000000000000..d56af09bffd3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57667.java @@ -0,0 +1,7 @@ +class A { + <T> A(T x) {} + + { + new <<error descr="Actual type argument and inferred type contradict each other">String</error>>A(1); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57668.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57668.java new file mode 100644 index 000000000000..65efaee0edda --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57668.java @@ -0,0 +1,17 @@ +class A { + <T> A() {} + + { + new <<error descr="Type argument cannot be of primitive type">int</error>>A(); + } +} + +class B<T> { + { + new B<<error descr="Type argument cannot be of primitive type">int</error>>(); + B.<<error descr="Type argument cannot be of primitive type">int</error>>m(); + } + + <S> void m(){} + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57877.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57877.java new file mode 100644 index 000000000000..87c943033b1f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57877.java @@ -0,0 +1,8 @@ +import java.util.*; + +class Test { + { + Object obj = new Object(); + Set<Class<?>> types = Collections.singleton(obj.getClass()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA63291.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA63291.java new file mode 100644 index 000000000000..077eb2d77acc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA63291.java @@ -0,0 +1,57 @@ +import java.util.Comparator; +import java.util.Set; + +public class CastError { + public void foo(Comparator<? super byte[]> comparator) throws Exception { + MyComparator comparator1 = (MyComparator) comparator; + } + + public void foo1(Comparator<byte[]> comparator) throws Exception { + MyComparator comparator1 = (MyComparator) comparator; + } + + public void foo2(Comparator<? extends byte[]> comparator) throws Exception { + MyComparator comparator1 = (MyComparator) comparator; + } + + public void foo3(Comparator<? super String[]> comparator) throws Exception { + MyComparator comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Comparator<capture<? super java.lang.String[]>>' to 'MyComparator'">(MyComparator) comparator</error>; + } + + public void foo4(Comparator<? extends String[]> comparator) throws Exception { + MyComparator comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Comparator<capture<? extends java.lang.String[]>>' to 'MyComparator'">(MyComparator) comparator</error>; + } + + public void foo5(Comparator<?> comparator) throws Exception { + MyComparator comparator1 = (MyComparator) comparator; + } + + //--||--||--||--||--||--||--||--||--||--||--||--||--||--||--||--||--||--||-- + + public void sfoo(Set<Comparator<? super byte[]>> comparator) throws Exception { + Set<MyComparator> comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Set<java.util.Comparator<? super byte[]>>' to 'java.util.Set<MyComparator>'">(Set<MyComparator>) comparator</error>; + } + + public void sfoo1(Set<Comparator<byte[]>> comparator) throws Exception { + Set<MyComparator> comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Set<java.util.Comparator<byte[]>>' to 'java.util.Set<MyComparator>'">(Set<MyComparator>) comparator</error>; + } + + public void sfoo2(Set<Comparator<? extends byte[]>> comparator) throws Exception { + Set<MyComparator> comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Set<java.util.Comparator<? extends byte[]>>' to 'java.util.Set<MyComparator>'">(Set<MyComparator>) comparator</error>; + } + + public void sfoo3(Set<Comparator<? super String[]>> comparator) throws Exception { + Set<MyComparator> comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Set<java.util.Comparator<? super java.lang.String[]>>' to 'java.util.Set<MyComparator>'">(Set<MyComparator>) comparator</error>; + } + + public void sfoo4(Set<Comparator<? extends String[]>> comparator) throws Exception { + Set<MyComparator> comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Set<java.util.Comparator<? extends java.lang.String[]>>' to 'java.util.Set<MyComparator>'">(Set<MyComparator>) comparator</error>; + } + + public void sfoo5(Set<Comparator<?>> comparator) throws Exception { + Set<MyComparator> comparator1 = <error descr="Inconvertible types; cannot cast 'java.util.Set<java.util.Comparator<?>>' to 'java.util.Set<MyComparator>'">(Set<MyComparator>) comparator</error>; + } +} + +abstract class MyComparator implements Comparator<byte[]> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA65066.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA65066.java new file mode 100644 index 000000000000..3078f601d777 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA65066.java @@ -0,0 +1,19 @@ +import java.util.List; + +class Generics { + public static void main( String[] args ) { + Outer<? extends List<? extends Nested<?>>, ?> var = OuterImpl.create(); //marked red + } + + private static interface Outer<I, O> { + } + + private static class OuterImpl<T> implements Outer<T, T> { + public static <T> OuterImpl<T> create() { + return new OuterImpl<T>(); + } + } + + private static class Nested<T> { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA66311.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA66311.java new file mode 100644 index 000000000000..659d8fa750fc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA66311.java @@ -0,0 +1,21 @@ +import java.util.*; + +class ErasureTest { + <error descr="'toArrayDouble(List<? extends Number>)' clashes with 'toArrayDouble(List<double[]>)'; both methods have same erasure">public static double[] toArrayDouble(List<? extends Number> v)</error> { + return null; + } + + public static double[][] toArrayDouble(List<double[]> v) { + return null; + } +} + +class ErasureTest1 { + <error descr="'toArrayDouble(List<? extends Number>)' clashes with 'toArrayDouble(List)'; both methods have same erasure">public static double[] toArrayDouble(List<? extends Number> v)</error> { + return null; + } + + public static double[][] toArrayDouble(List v) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA66311_16.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA66311_16.java new file mode 100644 index 000000000000..f95898afb480 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA66311_16.java @@ -0,0 +1,31 @@ +import java.util.*; + +class ErasureTest { + <error descr="'toArrayDouble(List<? extends Number>)' clashes with 'toArrayDouble(List<double[]>)'; both methods have same erasure">public static double[] toArrayDouble(List<? extends Number> v)</error> { + return null; + } + + public static double[][] toArrayDouble(List<double[]> v) { + return null; + } +} + +class ErasureTest1 { + <error descr="'toArrayDouble(List<? extends Number>)' clashes with 'toArrayDouble(List)'; both methods have same erasure">public static double[] toArrayDouble(List<? extends Number> v)</error> { + return null; + } + + public static double[][] toArrayDouble(List v) { + return null; + } +} + +class ErasureTest2 { + <error descr="'toArrayDouble(List<? extends Number>)' clashes with 'toArrayDouble(List<String>)'; both methods have same erasure">public static double[] toArrayDouble(List<? extends Number> v)</error> { + return null; + } + + public static double[] toArrayDouble(List<String> v) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67570.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67570.java new file mode 100644 index 000000000000..98e7c6b07cdb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67570.java @@ -0,0 +1,21 @@ +interface A1 +{ + String foo(); +} + +interface B1 +{ + Object foo(); +} + +class C1<T extends B1 & A1> { + void bar(T x) { + String foo = x.foo(); + } +} + +class C2<T extends A1 & B1> { + void bar(T x) { + String foo = x.foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67571.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67571.java new file mode 100644 index 000000000000..b0cd45c96f23 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67571.java @@ -0,0 +1,17 @@ +interface A +{ + abstract <T> void foo(); +} + +interface B +{ + abstract <T,S> void foo(); +} + +class C<<error descr="'foo()' in 'B' clashes with 'foo()' in 'A'; both methods have same erasure, yet neither overrides the other"></error>T extends A & B> +{ + void bar(T x) + { + x.foo<error descr="Ambiguous method call: both 'A.foo()' and 'B.foo()' match">()</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67577.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67577.java new file mode 100644 index 000000000000..ff1a04f25121 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67577.java @@ -0,0 +1,7 @@ +class X<T>{} + +class A<T,S extends X<T>> {} + +class C { + void foo(A<?, <error descr="Type parameter 'X' is not within its bound; should extend 'X<?>'">X</error>> a){ } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67584.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67584.java new file mode 100644 index 000000000000..e5c5b453abd7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67584.java @@ -0,0 +1,11 @@ +abstract class A +{ + abstract void foo(); +} + +interface B +{ + abstract void foo(); +} + +abstract class C extends A implements B { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67597.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67597.java new file mode 100644 index 000000000000..26240adcb8e4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67597.java @@ -0,0 +1,4 @@ +class A<T> +{ + T x = <error descr="Inconvertible types; cannot cast 'int' to 'T'">(T) 1</error>; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67599.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67599.java new file mode 100644 index 000000000000..67d49ac5a772 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67599.java @@ -0,0 +1,8 @@ +abstract class A<T, S extends T> +{ + abstract S bar(); + void foo(A<Cloneable[], ? extends Throwable[]> a) + { + int x = a.bar().length; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67667.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67667.java new file mode 100644 index 000000000000..35e4ed23fd45 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67667.java @@ -0,0 +1,8 @@ +import java.util.Collection; +import java.util.List; + +interface A +{ + <S extends Cloneable & Comparable<?>> void foo(S x); + <S extends Comparable<?> & Cloneable> void foo(S x); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67672.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67672.java new file mode 100644 index 000000000000..918e55059654 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67672.java @@ -0,0 +1,7 @@ +import java.util.Collection; +import java.util.List; + +interface A +{ + <<error descr="'add(E)' in 'java.util.List' clashes with 'add(E)' in 'java.util.Collection'; both methods have same erasure, yet neither overrides the other"></error><error descr="'add(E)' in 'java.util.List' clashes with 'add(E)' in 'java.util.Collection'; both methods have same erasure, yet neither overrides the other"></error>T extends List<?> & Collection<? extends Cloneable>> void foo(T x); +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java new file mode 100644 index 000000000000..7f206bbee52b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java @@ -0,0 +1,11 @@ +import java.util.List; + +interface B<T extends Cloneable> { + void foo(List<? super T> x); +} + +class D { + void bar(B<?> x, List<?> y) { + x.foo<error descr="'foo(java.util.List<? super capture<? extends java.lang.Cloneable>>)' in 'B' cannot be applied to '(java.util.List<capture<?>>)'">(y)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67681.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67681.java new file mode 100644 index 000000000000..b5abcb60a0ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67681.java @@ -0,0 +1,33 @@ + +interface A<T> { } + +class B<T> implements A<T> {} + +class C { + void bar(A<A<?>> x){ + B<A<String>> y = <error descr="Inconvertible types; cannot cast 'A<A<?>>' to 'B<A<java.lang.String>>'">(B<A<String>>) x</error>; + } +} + +//----------------------- +interface A2<T> { } + +class B2<T> implements A2<T> {} + +class C2 { + void bar(A2<A2> x){ + B2<A2<?>> y = <error descr="Inconvertible types; cannot cast 'A2<A2>' to 'B2<A2<?>>'">(B2<A2<?>>) x</error>; + } +} + +//----------------------- +interface A3<T> { } + +class B3<T> implements A3<T> {} + +class C3 { + <T> void bar(A3<A3<T>> x){ + A3<A3<?>> y = <error descr="Inconvertible types; cannot cast 'A3<A3<T>>' to 'A3<A3<?>>'">(A3<A3<?>>) x</error>; + + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67682.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67682.java new file mode 100644 index 000000000000..4a48242d2df1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67682.java @@ -0,0 +1,15 @@ +import java.util.List; + +abstract class B { + <T> void foo(List<List<String>[]> x) { + Object y1 = <error descr="Inconvertible types; cannot cast 'java.util.List<java.util.List<java.lang.String>[]>' to 'java.util.List<java.util.List<T>[]>'">(List<List<T>[]>)x</error>; + } + + <T> void foo1(List<List<List<String>>[]> x) { + Object y1 = <error descr="Inconvertible types; cannot cast 'java.util.List<java.util.List<java.util.List<java.lang.String>>[]>' to 'java.util.List<java.util.List<java.util.List<T>>[]>'">(List<List<List<T>>[]>)x</error>; + } + + <T> void foo2(List<String[]> x) { + Object y1 = <error descr="Inconvertible types; cannot cast 'java.util.List<java.lang.String[]>' to 'java.util.List<T[]>'">(List<T[]>)x</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67744.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67744.java new file mode 100644 index 000000000000..9914b1f21517 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67744.java @@ -0,0 +1,16 @@ +import java.util.List; + +abstract class B { + abstract <T> T[] foo(List<? super List<T>> x); + abstract <T> T foo0(List<? super List<T>> x); + abstract <T> T[] foo1(List<? extends List<T>> x); + abstract <T> T[] foo2(List<List<? super List<T>>> x); + + void bar(List<List<?>> x, List<List<List<?>>> y){ + foo(x) [0] = ""; + foo1<error descr="'foo1(java.util.List<? extends java.util.List<T>>)' in 'B' cannot be applied to '(java.util.List<java.util.List<?>>)'">(x)</error> [0] = ""; + foo2<error descr="'foo2(java.util.List<java.util.List<? super java.util.List<java.lang.Object>>>)' in 'B' cannot be applied to '(java.util.List<java.util.List<java.util.List<?>>>)'">(y)</error> [0] = ""; + + String s = foo0(x); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67798.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67798.java new file mode 100644 index 000000000000..fb420fba1e44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67798.java @@ -0,0 +1,6 @@ +class A<T> { + { + class T extends A<T> {} + } + class T extends A<T> {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67835.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67835.java new file mode 100644 index 000000000000..ce887c64b0b0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67835.java @@ -0,0 +1,10 @@ +import java.util.List; + +class B { + void bar(List<String> x){ + foo(x); + } + <T> T foo(List<? super T> x){ + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67843.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67843.java new file mode 100644 index 000000000000..c459ab3421f6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67843.java @@ -0,0 +1,10 @@ +import java.util.List; + +class B{ + public static void bar(){ + <error descr="Inferred type 'java.util.List<java.lang.Comparable>' for type parameter 'T' is not within its bound; should implement 'java.util.List<java.lang.Comparable<java.util.List<java.lang.Comparable>>>'">foo(null)</error>.get(0).compareTo(null); + } + static <T extends List<Comparable<T>>> T foo(T x) { + return x; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67861.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67861.java new file mode 100644 index 000000000000..1feb516e6b0f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67861.java @@ -0,0 +1,8 @@ +abstract class C { + <T> void foo(Object s){ } + abstract String foo(String s); + + { + this.<String>foo("").toLowerCase(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67865.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67865.java new file mode 100644 index 000000000000..ab7d8cf9cc2d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67865.java @@ -0,0 +1,11 @@ +import java.util.*; + +abstract class A { + static <T> void foo(List<T> x) { } + static <T extends List<?>> void foo(Collection<T> x) { } + public static void main(String[] args){ + List<List<String>> x = null; + foo<error descr="Ambiguous method call: both 'A.foo(List<List<String>>)' and 'A.foo(Collection<List<String>>)' match">(x)</error>; + foo<error descr="Ambiguous method call: both 'A.foo(List<Object>)' and 'A.foo(Collection<List<?>>)' match">(null)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67998.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67998.java new file mode 100644 index 000000000000..4db4fe052189 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67998.java @@ -0,0 +1,22 @@ +class TestClass { + public final class TestMapper<X> { + + public <U, T extends Mapping<X, U>> T mapType() { + SimpleMapping<X, U> mapping = new SimpleMapping<X, U>(); + return (T) mapping; //This is reports "Inconvertible types; cannot cast TestClass.SimpleMapping<X,U> to 'T'" + } + } + private final class SimpleMapping<X, U> implements Mapping<X, U> {} + public interface Mapping<F, U> {} +} +class TestClass1 { + public final class TestMapper<X> { + + public <U, T extends Mapping<X, U>> T mapType() { + Mapping<X, U> mapping = new SimpleMapping<X, U>(); //Changed type to interface + return (T) mapping; + } + } + private final class SimpleMapping<X, U> implements Mapping<X, U> {} + public interface Mapping<F, U> {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA70370.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA70370.java new file mode 100644 index 000000000000..a1c9331d6568 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA70370.java @@ -0,0 +1,13 @@ +class Devk1 { + public void main(String args[]) { + foo(); + } + + private void <warning descr="Private method 'foo(java.lang.Object...)' is never used">foo</warning>(Object... objects) { + System.out.println("OBJECTS" + objects); + } + + private void foo(int... ints) { + System.out.println("INTS" + ints); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA72912.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA72912.java new file mode 100644 index 000000000000..c57bbb50b07d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA72912.java @@ -0,0 +1,16 @@ +import java.util.*; + +public class Test<T> +{ + List<Collection<T>> getList () + { + return new ArrayList<Collection<T>> (); + } + + public void test1 (Test<T> arg) + { + List<Collection<T>> result = arg.getList (); + result.add <error descr="'add(java.util.Collection<T>)' in 'java.util.List' cannot be applied to '(java.util.HashMap<java.lang.Integer,java.lang.Integer>)'">(new HashMap<Integer, Integer> ())</error>; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA74899.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA74899.java new file mode 100644 index 000000000000..8723829cd137 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA74899.java @@ -0,0 +1,11 @@ +import java.util.Collections; +import java.util.Map; + +public class IDEA74899 { + void foo() { + Map<String, String> m = Collections.emptyMap(); + if (<error descr="Operator '==' cannot be applied to 'java.util.Map<java.lang.String,java.lang.String>', 'java.util.Map<java.lang.Object,java.lang.Object>'">m == Collections.emptyMap()</error>) { + return; + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA76283.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA76283.java new file mode 100644 index 000000000000..a221d1b13de2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA76283.java @@ -0,0 +1,49 @@ +import java.util.*; +public class IDEA76283 { +} + +interface Parametrized<T extends Number> { +} + +class Bug1<T extends Number> { + <I extends Number> Parametrized<I> foo(Parametrized<I> param) { + return null; + } + + void bug1(Parametrized<? super T> param) { + foo(param); + } + + void bug2(Set<Parametrized<? extends Number>> parametrizeds) { + Set<Parametrized<?>> items = parametrizeds; + } + + void bug3(Set<Parametrized<?>> parametrizeds) { + Set<Parametrized<?>> items = parametrizeds; + } + + void bug4(Set<Parametrized<<error descr="Type parameter '? extends String' is not within its bound; should extend 'java.lang.Number'">? extends String</error>>> parametrizeds) { + <error descr="Incompatible types. Found: 'java.util.Set<Parametrized<? extends java.lang.String>>', required: 'java.util.Set<Parametrized<?>>'">Set<Parametrized<?>> items = parametrizeds;</error> + } + + void bug5(Set<Parametrized<? extends Integer>> parametrizeds) { + <error descr="Incompatible types. Found: 'java.util.Set<Parametrized<? extends java.lang.Integer>>', required: 'java.util.Set<Parametrized<?>>'">Set<Parametrized<?>> items = parametrizeds;</error> + } + + void bug6(Set<Parametrized<? super Number>> parametrizeds) { + <error descr="Incompatible types. Found: 'java.util.Set<Parametrized<? super java.lang.Number>>', required: 'java.util.Set<Parametrized<?>>'">Set<Parametrized<?>> items = parametrizeds;</error> + } + + void bug7(Set<Parametrized<? super Integer>> parametrizeds) { + <error descr="Incompatible types. Found: 'java.util.Set<Parametrized<? super java.lang.Integer>>', required: 'java.util.Set<Parametrized<?>>'">Set<Parametrized<?>> items = parametrizeds;</error> + } + + void bug8(Set<Parametrized<<error descr="Type parameter '? super String' is not within its bound; should extend 'java.lang.Number'">? super String</error>>> parametrizeds) { + <error descr="Incompatible types. Found: 'java.util.Set<Parametrized<? super java.lang.String>>', required: 'java.util.Set<Parametrized<?>>'">Set<Parametrized<?>> items = parametrizeds;</error> + } + + void bug9(Set<Parametrized<<error descr="Type parameter '? super Object' is not within its bound; should extend 'java.lang.Number'">? super Object</error>>> parametrizeds) { + <error descr="Incompatible types. Found: 'java.util.Set<Parametrized<? super java.lang.Object>>', required: 'java.util.Set<Parametrized<?>>'">Set<Parametrized<?>> items = parametrizeds;</error> + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA77128.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA77128.java new file mode 100644 index 000000000000..cc889ab5df03 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA77128.java @@ -0,0 +1,11 @@ +import java.util.*; +class A { + public static void main(String[] args) { + List<String> strings = new ArrayList<>(); + + List<? super Integer> list = new ArrayList<>(); + list.addAll<error descr="'addAll(java.util.Collection<? extends capture<? super java.lang.Integer>>)' in 'java.util.List' cannot be applied to '(java.util.List<java.lang.String>)'">(strings)</error>; + + System.out.println(list.toString()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA77991.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA77991.java new file mode 100644 index 000000000000..688806bc5dc0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA77991.java @@ -0,0 +1,26 @@ +class Test { + static { + Class<Test> testClass = get(Test.class); + foo(testClass); + Test f = foo(testClass); + } + + static <E> Class<E> get(Class<? super E> value) { + return null; + } + + static <E> E foo(Class<? super E> value) { + return null; + } +} + +class Comp { + public static <T> boolean equal(T arg1, T arg2) { + return false; + } + + void foo(String s, Object o) { + if (equal(s, o)) { + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA80386.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA80386.java new file mode 100644 index 000000000000..3587f4f125b0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA80386.java @@ -0,0 +1,33 @@ +import java.util.List; + +public class IDEA80386 { + void foo(Class<List> listClass) { + <error descr="Incompatible types. Found: 'java.lang.Class<java.util.List>', required: 'java.lang.Class<? extends java.util.List<?>>'">Class<? extends List<?>> cls = listClass;</error> + Class < ?extends List > cls1 = listClass; + <error descr="Incompatible types. Found: 'java.lang.Class<java.util.List>', required: 'java.lang.Class<? extends java.util.List<? extends java.util.List<?>>>'">Class<? extends List<? extends List<?>>> cls2 = listClass;</error> + Class<? super List<?>> clsS = listClass; + Class<? super List> clsS1 = listClass; + } + + void fooE(Class<? extends List> listClass) { + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends java.util.List>>', required: 'java.lang.Class<? extends java.util.List<?>>'">Class<? extends List<?>> cls = listClass;</error> + Class<? extends List> cls1 = listClass; + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends java.util.List>>', required: 'java.lang.Class<? extends java.util.List<? extends java.util.List<?>>>'">Class<? extends List<? extends List<?>>> cls2 = listClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends java.util.List>>', required: 'java.lang.Class<? super java.util.List<?>>'">Class<? super List<?>> clsS = listClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends java.util.List>>', required: 'java.lang.Class<? super java.util.List>'">Class<? super List> clsS1 = listClass;</error> + } + + void fooS(Class<? super List> listClass) { + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? super java.util.List>>', required: 'java.lang.Class<? extends java.util.List<?>>'">Class<? extends List<?>> cls1 = listClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? super java.util.List>>', required: 'java.lang.Class<? extends java.util.List<? extends java.util.List<?>>>'">Class<? extends List<? extends List<?>>> cls2 = listClass;</error> + Class<? super List<?>> clsS = listClass; + Class<? super List> clsS1 = listClass; + } + + void fooU(Class<?> listClass) { + <error descr="Incompatible types. Found: 'java.lang.Class<capture<?>>', required: 'java.lang.Class<? extends java.util.List<?>>'">Class<? extends List<?>> cls1 = listClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<?>>', required: 'java.lang.Class<? extends java.util.List<? extends java.util.List<?>>>'">Class<? extends List<? extends List<?>>> cls2 = listClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<?>>', required: 'java.lang.Class<? super java.util.List<?>>'">Class<? super List<?>> clsS = listClass;</error> + <error descr="Incompatible types. Found: 'java.lang.Class<capture<?>>', required: 'java.lang.Class<? super java.util.List>'">Class<? super List> clsS1 = listClass;</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA86875.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA86875.java new file mode 100644 index 000000000000..c5a65df099ab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA86875.java @@ -0,0 +1,11 @@ +interface Base<E> {} +interface Base2<E> {} + +class A<E extends Cloneable> { + <P, K extends Base<E>&Base2<P>> void m(K k, P p) { + E e = null; + m(k, e); + } + + void m(Base<E> k, E e) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA87860.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA87860.java new file mode 100644 index 000000000000..540ec4e4195d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA87860.java @@ -0,0 +1,11 @@ +interface A { + <T extends Exception> void foo() throws T; + <T extends Exception> void bar() throws Exception; + void baz() throws Exception; +} + +interface B<T extends Throwable> extends A { + void foo() throws <error descr="'foo()' in 'B' clashes with 'foo()' in 'A'; overridden method does not throw 'T'">T</error>; + void bar() throws <error descr="'bar()' in 'B' clashes with 'bar()' in 'A'; overridden method does not throw 'java.lang.Throwable'">Throwable</error>; + void baz() throws <error descr="'baz()' in 'B' clashes with 'baz()' in 'A'; overridden method does not throw 'java.lang.Throwable'">Throwable</error>; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA88895.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA88895.java new file mode 100644 index 000000000000..cf59c1df00e3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA88895.java @@ -0,0 +1,26 @@ +import java.util.Iterator; + +public class WildcardGenericAndPrivateField { + + private Object field; + + public Iterator<? extends WildcardGenericAndPrivateField> iterator() { + return null; + } + + public void methodDoesNotCompile() { + Iterator<? extends WildcardGenericAndPrivateField> iterator = iterator(); + while ( iterator.hasNext() ) { + Object o = iterator.next().<error descr="'field' has private access in 'WildcardGenericAndPrivateField'">field</error>; + } + } + + public void methodCompiles() { + Iterator<? extends WildcardGenericAndPrivateField> iterator = iterator(); + while ( iterator.hasNext() ) { + WildcardGenericAndPrivateField next = iterator.next(); + Object o = next.field; + } + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA89771.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA89771.java new file mode 100644 index 000000000000..f3a04de113f2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA89771.java @@ -0,0 +1,3 @@ +public @interface MyAnnotation { + Class<? extends Enum<?>> enumClass() default <error descr="Incompatible types. Found: 'java.lang.Class<java.lang.Enum>', required: 'java.lang.Class<? extends java.lang.Enum<?>>'">Enum.class</error>; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA89801.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA89801.java new file mode 100644 index 000000000000..aa8ba27e8514 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA89801.java @@ -0,0 +1,7 @@ +import java.util.*; +class Test { + { + Map<Number, String> map1 = null; + Map<Integer, String> map2 = <error descr="Inconvertible types; cannot cast 'java.util.Map<java.lang.Number,java.lang.String>' to 'java.util.Map<java.lang.Integer,java.lang.String>'">(Map<Integer, String>) map1</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA90802.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA90802.java new file mode 100644 index 000000000000..c679ed80deb2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA90802.java @@ -0,0 +1,24 @@ +import java.util.*; + +interface VcsRoot { +} + +interface SVcsRoot extends VcsRoot { +} + +interface A { + List<? extends VcsRoot> getVcsRoots(); +} + +interface B { + List<SVcsRoot> getVcsRoots(); +} + +interface F1 extends A, B { +} + +class G { + void f(F1 o) { + SVcsRoot r = o.getVcsRoots().get(0); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java new file mode 100644 index 000000000000..ff29729bc977 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java @@ -0,0 +1,25 @@ +class Test { + interface A<T> { + void _(T... t); + } + + static void foo(final A<?> bar) { + bar._(""); + } + static void foo1(final A<? extends String> bar) { + bar._(""); + } + + static void foo2(final A<? extends Integer> bar) { + bar._<error descr="'_(capture<? extends java.lang.Integer>...)' in 'Test.A' cannot be applied to '(java.lang.String)'">("")</error>; + } + + + public static void main(String[] args) { + foo(new A<Integer>() { + public void _(final Integer... t) { + + } + }); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA92022.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA92022.java new file mode 100644 index 000000000000..d8d49f9b3d91 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA92022.java @@ -0,0 +1,23 @@ +class GetClassClient { + public void use() { + Class<? extends LocalGeneric> v1 = null; + Class<? extends LocalGeneric<Object>> v2 = null; + v1 = v2; + <error descr="Incompatible types. Found: 'java.lang.Class<capture<? extends GetClassClient.LocalGeneric>>', required: 'java.lang.Class<? extends GetClassClient.LocalGeneric<java.lang.Object>>'">v2 = v1</error>; + } + + public static class LocalGeneric<T> { + } +} + + +interface Comparable<T extends Comparable<T>> {} +class List<T> {} + +class Foo implements Comparable<Foo> { + public static void main(String[] args){ + List<? extends Foo> list = null; + List<? extends Comparable> c = null; + c = list; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA94011.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA94011.java new file mode 100644 index 000000000000..6d5cdfa2af0b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA94011.java @@ -0,0 +1,21 @@ +import java.util.*; +class Test { + + class Parent { } + + interface Consumer<T> { } + + interface MyConsumer<T extends Parent> extends Consumer<T> { } + + + public void test(Set<MyConsumer> set) { + @SuppressWarnings("unchecked") + Map<Parent, MyConsumer<Parent>> map = create<error descr="'create(java.util.Set<T>)' in 'Test' cannot be applied to '(java.util.Set<Test.MyConsumer>)'">(set)</error>; + + } + + public <S, T extends Consumer<S>> Map<S, T> create(Set<T> consumers) { + return null; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA97276.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA97276.java new file mode 100644 index 000000000000..625d70622fb8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA97276.java @@ -0,0 +1,17 @@ +interface Interf<X extends Interf> {} +class SomeClass { + static <I extends Interf<? super I>> Class<I> someMethod(I i) { return null; } +} + +interface OtherInterf<I1 extends Interf, I2 extends Interf> {} +interface ImmutableSet<S> {} + +class SomeOtherClass { + static ImmutableSet<Class<? extends OtherInterf<?, ?>>> someOtherMethod() { + return <error descr="Inconvertible types; cannot cast 'ImmutableSet<java.lang.Class<? extends OtherInterf>>' to 'ImmutableSet<java.lang.Class<? extends OtherInterf<?,?>>>'">(ImmutableSet<Class<? extends OtherInterf<?, ?>>>)aux(OtherInterf.class)</error>; + } + + static <T> ImmutableSet<Class<? extends T>> aux(Class<T> t) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA97888.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA97888.java new file mode 100644 index 000000000000..93e12176436c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA97888.java @@ -0,0 +1,23 @@ +import java.util.*; +import java.io.File; +class Foo { + public Collection<BuildTarget<?>> getDependencies(LayoutElementBuilderService builder, JpsPackagingElement element, TargetOutputIndex outputIndex) { + return builder.getDependencies(element, outputIndex); + } +} + +class BuildTarget<R extends BuildRootDescriptor> {} + +interface TargetOutputIndex { + Collection<BuildTarget<?>> getTargetsByOutputFile(File file); +} + +class BuildRootDescriptor {} + +class LayoutElementBuilderService<E extends JpsPackagingElement> { + public Collection<? extends BuildTarget<?>> getDependencies(E element, TargetOutputIndex outputIndex) { + return Collections.emptyList(); + } +} + +class JpsPackagingElement {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA98421.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA98421.java new file mode 100644 index 000000000000..28ac86b92c9a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA98421.java @@ -0,0 +1,11 @@ +class Outer { + class Inner { + public <T> Inner(T t) { } + } + + class Other extends Outer.Inner { + public Other() { + new Outer().<Object>super("Hi"); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA99061.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA99061.java new file mode 100644 index 000000000000..11afc6c936e3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA99061.java @@ -0,0 +1,11 @@ +class Test { + { + String a = cast("str"); + Integer[] b = cast(new Integer[0]); + Object[] c = cast(new Object[0]); + } + + private <T> T cast(Object obj) { + return (T)obj; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA99347.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA99347.java new file mode 100644 index 000000000000..9c4922400b7d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA99347.java @@ -0,0 +1,12 @@ +interface Errors { + java.util.Collection<java.lang.String> getErrorMessages(); + +} + +class Test extends AbstrClass implements Errors { +} + + +abstract class AbstrClass { + public java.util.Collection getErrorMessages() {return null;} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV10459.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV10459.java new file mode 100644 index 000000000000..f3185c8fbad8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV10459.java @@ -0,0 +1,31 @@ +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** @noinspection UnusedDeclaration*/ +public class GenericsTest98 { + public static void main(String[] args) throws Exception{ + List<Movable<? extends Serializable>> list = new ArrayList<Movable<? extends Serializable>> (); + Factory factory = Factory.newInstance(); + // Doesn't compile, but Idea doesn't complain + Mover<? extends Serializable> mover = factory.getNew<error descr="'getNew(java.util.List<? extends Movable<T>>)' in 'Factory' cannot be applied to '(java.util.List<Movable<? extends java.io.Serializable>>)'">(list)</error>; + } +} + +abstract class Factory { + public static Factory newInstance(){ + return null; + } + + // This should actually be + // public abstract <T extends Serializable> Mover<T> getNew (List<? extends Movable<? extends T>> source); + public abstract <T extends Serializable> Mover<T> getNew (List<? extends Movable<T>> source); +} + +/** @noinspection UnusedDeclaration*/ +interface Movable<T extends Serializable> extends Serializable { +} + +/** @noinspection UnusedDeclaration*/ +interface Mover<T extends Serializable> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV12951.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV12951.java new file mode 100644 index 000000000000..03cd4b6e61d2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV12951.java @@ -0,0 +1,29 @@ +class ClassExt { + + /** @noinspection UnusedDeclaration*/ + public static <T, P1, P2> T newInstance(Class<T> clazz, + Class<? super P1> t1, P1 p1, + Class<? super P2> t2, P2 p2) { + return null; + } + + +} + +abstract class TKey<T> { + + protected abstract Class<T> getType(); +} + + +class GoodIsRed6 { + + + public static <TK extends TKey<?>> TK createClone(TK tkey, String key) { + + + Class<TK> clazz = null; + + return ClassExt.newInstance(clazz, String.class, key, Class.class, tkey.getType()); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV13011.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV13011.java new file mode 100644 index 000000000000..77b1de425025 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV13011.java @@ -0,0 +1,29 @@ +/** @noinspection UnusedDeclaration*/ +class LimitedPool<T> { + private int capacity; + private final ObjectFactory<T> factory; + private Object[] storage; + private int index = 0; + + public LimitedPool(final int capacity, ObjectFactory<T> factory) { + this.capacity = capacity; + this.factory = factory; + storage = new Object[capacity]; + } + + interface ObjectFactory<T> { + T create(); + void cleanup(T t); + } + + public T alloc() { + if (index >= capacity) return factory.create(); + + if (storage[index] == null) { + storage[index] = factory.create(); + } + + <error descr="Incompatible types. Found: 'java.lang.Object[]', required: 'T'">return storage;</error> + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java new file mode 100644 index 000000000000..77cf1dbfaea8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java @@ -0,0 +1,18 @@ +/** @noinspection UnusedDeclaration*/ +interface TestIF2<T> extends TestIF3<T> {} + +/** @noinspection UnusedDeclaration*/ +interface TestIF<T extends TestIF2<? extends Test2>> { + void run(T o1); +} + +/** @noinspection UnusedDeclaration*/ +interface TestIF3<T> {} + +class Test2 {} + +class Test { + public void test(TestIF<?> testIF) { + testIF.run<error descr="'run(capture<? extends TestIF2<? extends Test2>>)' in 'TestIF' cannot be applied to '()'">()</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14103.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14103.java new file mode 100644 index 000000000000..77e6bb02bdc4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14103.java @@ -0,0 +1,52 @@ +class TestGenerics { + + static interface EnumInterface { + public String getSomething(); + } + + static enum Enum1 implements EnumInterface { + A("alpha"), + B("beta"), + G("gamme"), + ; + private String text; + + Enum1(String text) { + this.text = text; + } + + public String getSomething() { + return text; + } + } + + static class TestBase<I extends Enum<I> & EnumInterface> { + + protected final void add(Eval eval) { + eval.hashCode(); + } + + abstract class Eval { + private I enumI; + + public Eval(I enumI) { + this.enumI = enumI; + } + + public final void doSomething() { + System.out.println(enumI.getSomething()); + } + } + + } + + + + + class Test1 extends TestBase<Enum1> { + + public Test1() { + add(new Eval(Enum1.A) {}); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java new file mode 100644 index 000000000000..774a2efdae03 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java @@ -0,0 +1,29 @@ +import java.util.ArrayList; +import java.util.Collections; + +class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> { + R r; + + public SortTest(R r) { + this.r = r; + } + + public int compareTo(SortTest<R> o) { + return r.compareTo(o.r); + } + + public static void main(String[] args) { + ArrayList<SortTest<?>> list = new ArrayList<SortTest<?>>(); + SortTest<?> t1 = new SortTest<String>(""); + list.add(t1); + SortTest<?> t2 = new SortTest<Integer>(0); + list.add(t2); + <error descr="Inferred type 'SortTest<?>' for type parameter 'T' is not within its bound; should implement 'java.lang.Comparable<? super SortTest<?>>'">Collections.sort(list)</error>; + t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>; + + //this should be OK + SortTest<?>[] arr = new SortTest<?>[0]; + arr[0] = new SortTest<String>(""); + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV23157.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV23157.java new file mode 100644 index 000000000000..eef25427db32 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV23157.java @@ -0,0 +1,10 @@ +import java.util.List; +import java.util.Arrays; + +public class ZZZ { + + List<Class<?>> f(Class<?>[] exceptionTypes) { + List<Class<?>> nd = Arrays.asList(exceptionTypes); + return nd; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV24166.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV24166.java new file mode 100644 index 000000000000..c1952d1119a9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV24166.java @@ -0,0 +1,49 @@ +import java.util.*; + +interface TypesafeMap<BASE> { + + @SuppressWarnings({"UnusedDeclaration"}) + public interface Key<BASE,VALUE> { } + + public <VALUE, KEY extends Key<BASE,VALUE>> + boolean has(Class<KEY> key); + + public <VALUE, KEY extends Key<BASE,VALUE>> + VALUE get(Class<KEY> key); + + public <VALUEBASE, VALUE extends VALUEBASE, KEY extends Key<BASE,VALUEBASE>> + VALUE set(Class<KEY> key, VALUE value); + + public <VALUE, KEY extends Key<BASE,VALUE>> + VALUE remove(Class<KEY> key); + + public Set<Class<?>> keySet(); + + public <VALUE, KEY extends Key<CoreMap, VALUE>> + boolean containsKey(Class<KEY> key); +} + + +interface CoreMap extends TypesafeMap<CoreMap> { } + +interface CoreAnnotation<V> + extends TypesafeMap.Key<CoreMap, V> { + + public Class<V> getType(); +} + + +class CoreMaps { + + public static <K,V> Map<K,V> toMap(Collection<CoreMap> coremaps, + Class<CoreAnnotation<K>> keyKey, Class<CoreAnnotation<V>> valueKey) { + + Map<K,V> map = new HashMap<K,V>(); + for (CoreMap cm : coremaps) { + map.put(cm.get(keyKey), cm.get(valueKey)); + } + + return map; + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV57343.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV57343.java new file mode 100644 index 000000000000..fb7e477b8cb4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV57343.java @@ -0,0 +1,6 @@ +class D<T> { + void foo(D<?> x){ + bar<error descr="'bar(D<? extends T>, D<? super T>)' in 'D' cannot be applied to '(D<capture<?>>, D<capture<?>>)'">(x,x)</error>; + } + <T> void bar(D<? extends T> x, D<? super T> y){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV7337.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV7337.java new file mode 100644 index 000000000000..bc89597e7eb5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV7337.java @@ -0,0 +1,74 @@ +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Comparator; + + +class TestIDEA +{ + + public static class Test1<Type extends List & Serializable> + { + public void process(Serializable s) + { + } + public void process(Type t) + { + } + } + + public static class Test2 extends Test1<ArrayList> + { + public void process(Serializable s) + { + super.process(s); + } + + public void process(ArrayList t) + { + super.process(t); // this call is OK resolving to parameterized method in super + } + } + + public static void main(String[] args) + { + Test2 test=new Test2(); + ArrayList list=new ArrayList(); + test.process(list); + test.process((Serializable)list); + } +} + +class Key<T> { + Object add(T v) { + return v; + } +} + +class WKey<W, T> extends Key<T> { + + W add(T v) { + return null; + } +} + +class IBug { + + public static <W, T> void addItem(WKey<W, T> key, T v) { + key.add(v); // --> demetra draw this in red, see attachment + } +} + +//IDEADEV-7698 +abstract class Collator implements Comparator<Object> { + public abstract int compare(String source, String target); + + public int compare(Object o1, Object o2) { + return compare((String)o1, (String)o2); + } + + public void foo(Collator c) { + c.compare("foo", "bar"); + } +} +//end of //IDEADEV-7698 diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IllegalForwardReferenceInTypeParameterDefinition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IllegalForwardReferenceInTypeParameterDefinition.java new file mode 100644 index 000000000000..31cdb6137873 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IllegalForwardReferenceInTypeParameterDefinition.java @@ -0,0 +1,2 @@ +class A<T extends S, S> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IllegalGenericTypeInInstanceof.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IllegalGenericTypeInInstanceof.java new file mode 100644 index 000000000000..52871e84f273 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IllegalGenericTypeInInstanceof.java @@ -0,0 +1,53 @@ +class A<T> { + public void foo(Object object) { + if (object instanceof <error descr="Illegal generic type for instanceof">B</error>) {} + if (object instanceof A.B) {} + if (object instanceof A<?>.B) {} + if (object instanceof A<?>) {} + if (object instanceof <error descr="Illegal generic type for instanceof">A<String></error>) {} + if (object instanceof A) {} + if (object instanceof A[]) {} + if (object instanceof <error descr="Illegal generic type for instanceof">B[]</error>) {} + if (object instanceof A.B[]) {} + } + + private class B { + } +} + +class A1 { + public void foo(Object object) { + if (object instanceof B1) {} + if (object instanceof A1.B1) {} + if (object instanceof B1[]) {} + } + + private class B1 { + } +} + +class BreakpointTree<TP> { + void foo(Node node) { + if (node instanceof BNode<?>) { + + } + } + + static class BNode<B extends XBreakpoint<?>> extends Node{} +} +class Node {} +class XBreakpoint<SR>{} + +public class GenericInnerClass<E> { + private void problem( Base base ) { + if ( base instanceof First) {} + } + + private class Base { + } + + private class First<T> extends Base { + } + +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ImplementAnnotation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ImplementAnnotation.java new file mode 100644 index 000000000000..bbe1e30338ac --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ImplementAnnotation.java @@ -0,0 +1,15 @@ +import java.lang.annotation.Annotation; + +public @interface Foo { + String id(); +} + +class Bar implements Foo { + public String id() { + return null; + } + + public Class<? extends Annotation> annotationType() { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InaccessibleThroughWildcard.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InaccessibleThroughWildcard.java new file mode 100644 index 000000000000..cc6471949e12 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InaccessibleThroughWildcard.java @@ -0,0 +1,13 @@ +class JavacConfiguration { + private final String mySettings = ""; + + public static void foo(Class<? extends JavacConfiguration> aClass) { + Object o = getService(aClass).<error descr="'mySettings' has private access in 'JavacConfiguration'">mySettings</error>; + JavacConfiguration configuration = getService(aClass); + String string = configuration.mySettings; + } + + public static <T> T getService(Class<T> serviceClass) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IncompatibleReturnType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IncompatibleReturnType.java new file mode 100644 index 000000000000..3a8d3b069afb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IncompatibleReturnType.java @@ -0,0 +1,20 @@ +abstract class F<A, B> { + public abstract B f(A a); + + public final F<A, P1<B>> lazy() { + return new F<A, P1<B>>() { + public P1<B> f(final A a) { + return null; + } + }; + } + + private class TestClient<A, B> extends F<A, P1<B>> { + public P1<B> f(final A a) { + return null; + } + } +} + +class P1<T> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InconvertibleTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InconvertibleTypes.java new file mode 100644 index 000000000000..752453e5cd5f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InconvertibleTypes.java @@ -0,0 +1,8 @@ +import java.util.*; + +class Test { + void foo(){ + Properties properties = System.getProperties(); + final Map<String, String> systemProperties = <error descr="Inconvertible types; cannot cast 'java.util.Properties' to 'java.util.Map<java.lang.String,java.lang.String>'">(Map<String, String>) properties</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithBounds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithBounds.java new file mode 100644 index 000000000000..626821e39f18 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithBounds.java @@ -0,0 +1,61 @@ +import java.util.*; + +class CLS { + static <V extends String> void bar (V v) {} + + static void foo () { + <error descr="Inferred type 'java.lang.Object' for type parameter 'V' is not within its bound; should extend 'java.lang.String'">bar(new Object())</error>; + } +} +////////////////////////////// +public abstract class ZZZ<K> { + public abstract <T extends String> ZZZ<T> get(); +} +class Z2<K> extends ZZZ<K> { + public <T extends String> Z2<T> get() { + return null; + } + void f() { + Z2 z2 = get(); + } +} +///////////////// +abstract class LeastRecentlyUsedCache { +interface Callable<V> { + V call() throws Exception; +} + + <E extends A> Callable<E> e(E e) { + return null; + } + <T extends B> Callable<T> f(boolean b, final T t) { + return b ? e(t) : new Callable<T>() { + public T call() throws Exception { + return t; + } + }; + } + + void ff() { + + } + + class A {} + class B extends A {} +} +////////////////////////// +public class BadCodeGreen<T, C extends Collection<? extends T>> { + public BadCodeGreen(C c, T t) { + c.add<error descr="'add(capture<? extends T>)' in 'java.util.Collection' cannot be applied to '(T)'">(t)</error>; + } +} +//////////////////////////// +abstract class A { + public abstract <T extends List<?>> T create(); +} +class B extends A { + public <T extends List<?>> T create() { + return null; + } +} +/////////////////////////// diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithBoxingCovariant.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithBoxingCovariant.java new file mode 100644 index 000000000000..453f82b26d8f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithBoxingCovariant.java @@ -0,0 +1,16 @@ +import java.util.*; + +class Test { + static class Pair<A, B> { + Pair(A a, B b) { + } + + static <A, B> Pair<A, B> create(A a, B b) { + return new Pair<A, B>(a, b); + } + } + + public static void getWordsWithOffset(String s, int startInd, final List<Pair<String, Integer>> res) { + res.add(Pair.create(s, startInd)); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithSuperBounds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithSuperBounds.java new file mode 100644 index 000000000000..d68f90786e9b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithSuperBounds.java @@ -0,0 +1,16 @@ +public class ExampleProblem { + <T> void asserting(T t, Simple<T> l){ + } + + <K> Simple<? super K> comp(K k){ + return null; + } + + public void main(String[] args) { + asserting(0, comp(0)); + } +} + +class Simple<SST>{ + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithUpperBoundPromotion.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithUpperBoundPromotion.java new file mode 100644 index 000000000000..8b2aabe285a7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InferenceWithUpperBoundPromotion.java @@ -0,0 +1,30 @@ + +public class NestedGenericGoodCodeIsRed { + + public void main( String[] args ) { + satisfiesAllOf(isPositive(), isEqualTo(10.9)); + satisfiesAllOf(isPositive(), isEqualTo(10)); + + Number num = null; + satisfiesAllOf(isPositive(), isEqualTo(num)); + + this.<Number>satisfiesAllOf(isPositive(), isEqualTo(10)); + } + + + public interface Predicate<T> { + + } + + public <ALL> void satisfiesAllOf( Predicate<? super ALL> first, Predicate<? super ALL> second ) { + } + + public <POSITIVE extends Number> Predicate<POSITIVE> isPositive() { + return null; + } + + public <EQUALTO extends Number> Predicate<EQUALTO> isEqualTo( EQUALTO target ) { + return null; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritFromTypeParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritFromTypeParameter.java new file mode 100644 index 000000000000..cfad53ef4076 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritFromTypeParameter.java @@ -0,0 +1,2 @@ +class C<T> extends <error descr="Class cannot inherit from its type parameter">T</error> +{} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java new file mode 100644 index 000000000000..2adff2f8f495 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java @@ -0,0 +1,24 @@ +interface IA<T> {} +interface IB<T> extends IA<T> {} + +class A { + <<error descr="'IA' cannot be inherited with different type arguments: 'java.lang.Integer' and 'java.lang.String'"></error>T extends IA<Integer> & IB<String>> void foo(){} +} + + + +interface IA1<T> {} +interface IB1<T> extends IA1<T> {} + +class A1 { + <<error descr="'IA1' cannot be inherited with different type arguments: 'java.lang.Object' and 'capture<?>'"></error>T extends IA1<Object> & IB1<?>> void foo(){} +} + +interface IA2<T> {} +interface IB2<T> extends IA2<T[]> {} + +class A2 { + <T extends IA2<Object[]> & IB2<?>> void foo(){} +} + + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InnerClassRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InnerClassRef.java new file mode 100644 index 000000000000..f13329204fe2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InnerClassRef.java @@ -0,0 +1,19 @@ +import java.util.*; +import Node.Details; + +public class Node<E> { + public class Details { + public E data; + } + public Details addNode(Node<E> child) { + return new Details(); + } +} + +class Test { + public static void main(String[] args) { + Map<String, Details> m = null; + Map<String, Node.Details> sorted1; + sorted1 = m; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InstanceClassInStaticContextAccess.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InstanceClassInStaticContextAccess.java new file mode 100644 index 000000000000..dcfad56b17ba --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InstanceClassInStaticContextAccess.java @@ -0,0 +1,62 @@ +class MyTest<K> { + + class A<T> { + } + + //not an error in java 8?! + static class C<T extends <error descr="'MyTest.this' cannot be referenced from a static context">A<String></error>> { + } + + static <T extends <error descr="'MyTest.this' cannot be referenced from a static context">A<String></error>> void bar() { + } + + static class B { + { + B.<<error descr="'MyTest.this' cannot be referenced from a static context">A</error>>bar(); + <error descr="'MyTest.this' cannot be referenced from a static context">A</error> a; + } + + static <T extends <error descr="'MyTest.this' cannot be referenced from a static context">A<String></error>> void bar() { + } + + void v(C<<error descr="'MyTest.this' cannot be referenced from a static context">A<String></error>> c) { + } + } +} + +class MyTest1 { + + class A<T> { + } + + static class C<T extends A<String>> { + } + + static <T extends A<String>> void bar() { + } + + static class B { + { + B.<A>bar(); + A a = <error descr="'MyTest1.this' cannot be referenced from a static context">new A()</error>; + } + + static <T extends A<String>> void bar() { + } + + void v(C<A<String>> c) { + } + } +} + +class MyTest2<T> { + static class A { + private MyTest2 myTest; + + public Object foo() { + return myTest.new Bar(); + } + } + + class Bar {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IntersectionTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IntersectionTypes.java new file mode 100644 index 000000000000..48bb90c3777e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IntersectionTypes.java @@ -0,0 +1,221 @@ +import java.io.*; +import java.util.*; + +class Test { + <T> List<T> asList (T... ts) { + ts.hashCode(); + return null; + } + + void foo() { + List<Class<? extends Serializable>> l = <warning descr="Unchecked generics array creation for varargs parameter">this.asList</warning>(String.class, Integer.class); + l.size(); + List<? extends Object> objects = this.asList(new String(), new Integer(0)); + objects.size(); + } +} + +//SUN BUG ID 5034571 +interface I1 { + void i1(); +} + +class G1 <T extends I1> { + T get() { return null; } +} + +interface I2 { + void i2(); +} + +class Main { + void f2(G1<? extends I2> g1) { + g1.get().i1(); // this should be OK + g1.get().i2(); // this should also be OK + } +} + +//IDEADEV4200: this code is OK +interface I11 { + String i1(); +} + +interface I21 { + String i2(); +} + +interface A<T> { + T some(); +} + +interface B<T extends I11 & I21> extends A<T> { + +} + +class User { + + public static void main(B<?> test) { + System.out.println(test.some().i1()); + System.out.println(test.some().i2()); + } +} +/* + * Copyright 2000-2011 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. + */ + +//end of IDEADEV4200 + +//IDEADEV-4214 +interface Keyable<K> { + /** + * @return the key for the instance. + */ + public K getKey(); +} + +abstract class Date implements java.io.Serializable, Cloneable, Comparable<Date> { + +} + +class Maps { + public static class MapEntry<K, V> implements Map.Entry<K, V> { + K k; + V v; + + public K getKey() { + return k; + } + + public V getValue() { + return v; + } + + public V setValue(V value) { + return v = value; + } + + public MapEntry(K k, V v) { + this.k = k; + this.v = v; + } + } + + public static <K, V> Map.Entry<K, V> entry(K key, V value) { + return new MapEntry<K, V>(key, value); + } + + public static <K, V> Map<K, V> asMap(Map.Entry<? extends K, ? extends V> ... <warning descr="Parameter 'entries' is never used">entries</warning>) { + return null; + } + + public static <K, V extends Keyable<K>> Map<K, V> asMap(V ... <warning descr="Parameter 'entries' is never used">entries</warning>) { + return null; + } +} + +class Client { + void f(Date d) { + //this call should be OK + <warning descr="Unchecked generics array creation for varargs parameter">Maps.asMap</warning>(Maps.entry(fieldName(), "Test"), + Maps.entry(fieldName(), 1), + Maps.entry(fieldName(), d)); + } + + String fieldName() { + return null; + } +} +//end of IDEADEV-4214 + +class IDEADEV25515 { + static <T> List<T> asList (T... ts) { + ts.hashCode(); + return null; + } + + public static final + List<Class<? extends Serializable>> SIMPLE_TYPES = +<warning descr="Unchecked generics array creation for varargs parameter">asList</warning>(String.class, Integer.class ,Long.class, Double.class, /*Date.class,*/ +Boolean.class, Boolean.TYPE /*,String[].class */ /*,BigDecimal.class*/); + + + public static final List<Class<? extends Serializable>> SIMPLE_TYPES_INFERRED = + <warning descr="Unchecked generics array creation for varargs parameter">asList</warning>(String.class, Integer.class ,Long.class, Double.class, /*Date.class,*/ + Boolean.class, Boolean.TYPE ,String[].class /*,BigDecimal.class*/); + + +} +/////////////////////// +class Axx { + <T extends Runnable> T a() { + String s = a(); + s.hashCode(); + return null; + } +} +/////////////// +interface L {} +public class MaximalType { + public static <T> T getParentOfType(Class<? extends T>... classes) { + classes.hashCode(); + return null; + } + { + <warning descr="Unchecked generics array creation for varargs parameter">getParentOfType</warning>(M2.class, M.class); + } +} +class M extends MaximalType implements L{} +class M2 extends MaximalType implements L{} +///////////// + + +class IDEA67676 { + interface I<<warning descr="Type parameter 'T' is never used">T</warning>> {} + interface A<T> extends I<A<T>>{} + interface Com2<T, U> { + void foo(T t, U u); + } + interface Com1<T> { + void foo(T t); + } + + abstract class X { + abstract <T> T foo(T x, T y); + + void bar(A<A2> x, A<B2> y) { + A<? extends Com2<? extends Com2<?, ?>, ? extends Com2<?, ?>>> f = foo(x, y); + f.hashCode(); + } + + void boo(A<A3> x, A<B3> y) { + A<? extends Com2<? extends Com2<?, ?>, ? extends Com2<?, ?>>> f = foo(x, y); + f.hashCode(); + } + + void baz(A<A1> x, A<B1> y) { + A<? extends Com1<? extends Com1<?>>> f = foo(x, y); + f.hashCode(); + } + } + + abstract class A1 implements Com1<A1> {} + abstract class B1 implements Com1<B1> {} + + abstract class A2 implements Com2<A2, A2> {} + abstract class B2 implements Com2<B2, B2> {} + + abstract class A3 implements Com2<A3, B3> {} + abstract class B3 implements Com2<B3, A3> {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodCallOnRawTypesExtended.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodCallOnRawTypesExtended.java new file mode 100644 index 000000000000..42e1c4219c30 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodCallOnRawTypesExtended.java @@ -0,0 +1,17 @@ +import java.util.Collections; +import java.util.List; + +class Bar { + private List<Property> getChildren(Property property, PropertiesContainer c) { + return property.getChildren(c); + } + + static class PropertiesContainer<M extends Property> {} + +} + +class Property<K> { + public List<? extends Property<K>> getChildren(K container) { + return Collections.emptyList(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodCallParamsOnRawType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodCallParamsOnRawType.java new file mode 100644 index 000000000000..e399e5a54e48 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodCallParamsOnRawType.java @@ -0,0 +1,32 @@ +class TestOnRawType { + public static void main(String[] args) { + new FooGenerator().process(TestOnRawType.class); + new FooGenerator().process(AFoo.class); + new FooGenerator().process(MFoo.class); + new FooGenerator<String>().process<error descr="'process(java.lang.Class<TestOnRawType.AFoo>)' in 'TestOnRawType.FooGenerator' cannot be applied to '(java.lang.Class<TestOnRawType>)'">(TestOnRawType.class)</error>; + new FooGenerator<String>().process(AFoo.class); + new FooGenerator<String>().process<error descr="'process(java.lang.Class<TestOnRawType.AFoo>)' in 'TestOnRawType.FooGenerator' cannot be applied to '(java.lang.Class<TestOnRawType.MFoo>)'">(MFoo.class)</error>; + } + + static class AFoo {} + static class MFoo extends AFoo {} + static class FooGenerator<T> { + public void process(Class<AFoo> cls) { + } + } +} + +class TestNonGenericType { + public static void main(String[] args) { + new FooGenerator().process<error descr="'process(java.lang.Class<TestNonGenericType.AFoo>)' in 'TestNonGenericType.FooGenerator' cannot be applied to '(java.lang.Class<TestNonGenericType>)'">(TestNonGenericType.class)</error>; + new FooGenerator().process(AFoo.class); + new FooGenerator().process<error descr="'process(java.lang.Class<TestNonGenericType.AFoo>)' in 'TestNonGenericType.FooGenerator' cannot be applied to '(java.lang.Class<TestNonGenericType.MFoo>)'">(MFoo.class)</error>; + } + + static class AFoo {} + static class MFoo extends AFoo {} + static class FooGenerator { + public void process(Class<AFoo> cls) { + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodSignatureEquality.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodSignatureEquality.java new file mode 100644 index 000000000000..cabf948d0413 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/MethodSignatureEquality.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2010 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. + */ +import java.io.*; +class Test { + interface InterfA { + <T extends Cloneable & Iterable> void foo(T x); + + <T extends Iterable & Cloneable> void foo(T x); + } + + class ANotSame { + <T extends Cloneable & Iterable> void foo(T x){} + + <T extends Iterable & Cloneable> void foo(T x){} + } + + class BNotSame extends ANotSame { + @Override + <T extends Cloneable & Iterable> void foo(T x){} + } + + abstract class A<T extends Throwable> { + abstract <T extends Comparable<?> & Serializable> void foo(T x, A<?> y); + + abstract <T extends Serializable & Comparable<?>> void foo(T x, A<? extends Cloneable> y); + } + + /* abstract class B<T extends Throwable> { + abstract <T extends Comparable<?> & Serializable> void foo(T x, B<?> y); + + abstract <T extends Serializable & Comparable<?>> void foo(T x, B<? extends Throwable> y); + } + + + abstract class C<T extends Throwable & Serializable> { + abstract <T extends Comparable<?> & Serializable> void foo(T x, C<? extends Serializable> y); + + abstract <T extends Serializable & Comparable<?>> void foo(T x, C<? extends Throwable> y); + }*/ + + abstract class D<T extends Throwable & Runnable> { + <error descr="'foo(T, D<? extends Runnable>)' clashes with 'foo(T, D<? extends Throwable>)'; both methods have same erasure">abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Runnable> y)</error>; + + abstract <T extends Serializable & Comparable<?>> void foo(T x, D<? extends Throwable> y); + } + + + interface IA {} + interface IB {} + void testExtendsOrder() { + class E<T extends IA & IB> { + <error descr="'foo(E<? extends IA>)' clashes with 'foo(E<? extends IB>)'; both methods have same erasure">void foo(E<? extends IA> x)</error> {} + void foo(E<? extends IB> x) {} + } + } + + abstract class F<T extends Throwable> { + <error descr="'foo(F<?>)' is already defined in 'Test.F'">abstract void foo(F<?> y)</error>; + + <error descr="'foo(F<? extends Throwable>)' is already defined in 'Test.F'">abstract void foo(F<? extends Throwable> y)</error>; + } +} + +class Ao {} + +class Bo extends Ao {} + +class SettingsEditor<T> { +} + +abstract class RunConfigurationExtension<T extends Ao> { + protected abstract <P extends T> SettingsEditor<P> createEditor(final P configuration); +} + +class F extends RunConfigurationExtension<Bo> { + + @Override + protected <P extends Bo> SettingsEditor<P> createEditor(P configuration) { + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Methods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Methods.java new file mode 100644 index 000000000000..d0f994e48b76 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Methods.java @@ -0,0 +1,38 @@ +import java.util.*; + +interface Base { +} + +class Derived implements Base { +} + +class X { + void method(int i, Base b) { } + void method(int i, Derived b) { } + + { + Derived d = new Derived(); + method(10, d); + } +} + +class Temp<T> {} + +class A { + <error descr="'A(T)' clashes with 'A(T)'; both methods have same erasure">public <T extends Temp<String>> A(T list)</error> {} + public <T extends Temp<Integer>> A(T list) {} +} +class B { + public <T extends A> B(T list) {} + public <T extends Temp<Integer>> B(T list) {} +} + + + +////////////////////////////////////////// +class IdeaBug { + + static <T> T cloneMe(T arg) throws CloneNotSupportedException { + return (T) arg.<error descr="'clone()' has protected access in 'java.lang.Object'">clone</error>(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/NoInferenceFromTypeCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/NoInferenceFromTypeCast.java new file mode 100644 index 000000000000..636556d55ced --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/NoInferenceFromTypeCast.java @@ -0,0 +1,23 @@ +import java.util.Collections; +import java.util.List; +import java.util.Set; + + +interface A {} + +interface B extends A {} + +class Foo { + public <TA extends A> List<TA> getAs() { + return (List<TA>) getBs(); + } + + public <T extends B> List<T> getBs() { + return null; + } + + void foo(Set<String> s) {} + { + foo(<error descr="Inconvertible types; cannot cast 'java.util.Set<java.lang.Object>' to 'java.util.Set<java.lang.String>'">(Set<String>)Collections.emptySet()</error>); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/OverrideAtLanguageLevel6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/OverrideAtLanguageLevel6.java new file mode 100644 index 000000000000..d83cf659d8a9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/OverrideAtLanguageLevel6.java @@ -0,0 +1,13 @@ +interface I { + void f(); +} +interface II extends I { + @Override + void f(); +} +class C implements I { + @Override + public void f() { + + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/OverrideWithMoreSpecificReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/OverrideWithMoreSpecificReturn.java new file mode 100644 index 000000000000..c2f68775cbfb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/OverrideWithMoreSpecificReturn.java @@ -0,0 +1,15 @@ +import java.util.List; + +interface ExampleInterface { + public List exampleMethod(); +} + +class ExampleSuperClass { + public List<String> exampleMethod() { + return null; + } +} + + +public class ExampleSubClass extends ExampleSuperClass implements ExampleInterface { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ParameterizedParameterBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ParameterizedParameterBound.java new file mode 100644 index 000000000000..50e117be1e84 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ParameterizedParameterBound.java @@ -0,0 +1,6 @@ +import java.util.*; +class ParamHolder<T extends List<String>> {} +class HolderUsage { + public void fail(ParamHolder<<error descr="Type parameter 'java.util.List' is not within its bound; should extend 'java.util.List<java.lang.String>'">List</error>> p) { } + public void success(ParamHolder<ArrayList<String>> p) { } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/PrivateInnerClassRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/PrivateInnerClassRef.java new file mode 100644 index 000000000000..5647b1d1230f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/PrivateInnerClassRef.java @@ -0,0 +1,30 @@ +import java.util.Comparator; + +public abstract class A implements <error descr="'A.B' has private access in 'A'">Comparator<A.B></error> { + + private static class B { + } + + private interface I extends Comparator<I>{} + private interface I1 extends Comparator<I>{} +} + +//abstract class C implements error descr="'C.D' has private access in 'C'">C.D error { +// private static class D {} +//} + +class JSReferenceSet { + static class MyResolver implements JSResolveUtil.Resolver<M> {} + class M extends JSResolveUtil.F {} +} +class JSResolveUtil { + static interface Resolver<T extends F> {} + static class F {} +} + + +class TestIDEA62515 { + public static interface Model<T> {} + public class Inner {} + public static class Foo implements Model<Inner> {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Raw.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Raw.java new file mode 100644 index 000000000000..25ef68287332 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Raw.java @@ -0,0 +1,177 @@ +import java.util.ArrayList; + +class Reference<<warning descr="Type parameter 'T' is never used">T</warning>> { +} +class WeakReference<T> extends Reference<T> { +} +class Item<<warning descr="Type parameter 'Key' is never used">Key</warning>, T> extends WeakReference<T> { + { + Reference<T> ref = null; + Item item = (Item) ref; + equals(item); + } +} + +// assign raw to generic are allowed +class a<E> { + void f(a<E> t){ + t.hashCode(); + } +} +class b { + a<b> f(a raw) { + a<?> unbound = raw; + raw = unbound; + + a<Integer> generic = <warning descr="Unchecked assignment: 'a' to 'a<java.lang.Integer>'">raw</warning>; + <warning descr="Unchecked call to 'f(a<E>)' as a member of raw type 'a'">raw.f</warning>(raw); + <warning descr="Unchecked call to 'f(a<E>)' as a member of raw type 'a'">raw.f</warning>(generic); + generic.f(<warning descr="Unchecked assignment: 'a' to 'a<java.lang.Integer>'">raw</warning>); + generic.f(generic); + generic.f<error descr="'f(a<java.lang.Integer>)' in 'a' cannot be applied to '(a<java.lang.String>)'">(new a<String>())</error>; + generic = <warning descr="Unchecked assignment: 'a' to 'a<java.lang.Integer>'">raw</warning>; + + + return <warning descr="Unchecked assignment: 'a' to 'a<b>'">raw</warning>; + } +} + +class List<T> { + <V> V[] toArray (V[] vs) { return vs; } + void add(T t) { + t.hashCode(); + } +} + +class c { + /*String[] f () { + List l = new List(); + error descr="Incompatible types. Found: 'java.lang.Object[]', required: 'java.lang.String[]'">return l.toArray (new String[0]);</error + }*/ + + String[] g () { + List<String> l = new List<String>(); + return l.toArray (new String[0]); + } +} + +class d { + class Y <<warning descr="Type parameter 'T' is never used">T</warning>> { + } + + class Z <<warning descr="Type parameter 'T' is never used">T</warning>> extends Y<Y> { + } + + class Pair <X> { + void foo(Y<? extends X> y) { + y.hashCode(); + } + } + + Pair<Z> pair; + + void bar(Y<? extends Y> y) { + pair.foo<error descr="'foo(d.Y<? extends d.Z>)' in 'd.Pair' cannot be applied to '(d.Y<capture<? extends d.Y>>)'">(y)</error>; + } +} + +class e { + String foo () { + MyList myList = new MyList(); + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">return myList.get(0);</error> + } + + static class MyList<<warning descr="Type parameter 'T' is never used">T</warning>> extends ArrayList<String>{ + } +} + +class ccc { + static Comparable<? super ccc> f() { + return <warning descr="Unchecked assignment: 'java.lang.Comparable' to 'java.lang.Comparable<? super ccc>'">new Comparable () { + public int compareTo(final Object o) { + return 0; + } + }</warning>; + } +} + +class ddd<COMP extends ddd> { + COMP comp; + ddd foo() { + return comp; //no unchecked warning is signalled here + } +} + +class G1<T> { + T t; +} +class G2<T> { + T t; + + static ArrayList<G1> f() { + return null; + } +} + +class Inst { + static void f () { + G2<G1<String>> g2 = new G2<G1<String>>(); + for (<warning descr="Unchecked assignment: 'G1' to 'G1<java.lang.String>'">G1<String> g1</warning> : g2.f()) { + g1.toString(); + } + } +} + +class A111<T> { + T t; + <V> V f(V v) { + return v; + } + + String g(A111 a) { + //noinspection unchecked + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">return a.f("");</error> + } +} + +class A1 { + <V> V f(V v) { + return v; + } +} + +class A11<T> extends A1 { + T t; + + //this is OK, type parameters of base class are not raw + String s = new A11().f(""); +} + +//IDEADEV-26163 +class Test1<X> { + X x; + java.util.ArrayList<Number> foo = new java.util.ArrayList<Number>(); + public static Number foo() { + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.Number'">return new Test1().foo.get(0);</error> + } +} +//end of IDEADEV-26163 + + +/////////////// signatures in non-parameterized class are not erased +public class C3 { + public int get(Class<?> c) { + return 0; + } +} + +class Cp<T> extends C3 { + public T i; +} +class C extends Cp/*<C>*/ { + @Override + public int get(Class<?> c) { + return 0; + } +} +////////////// diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawAssignments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawAssignments.java new file mode 100644 index 000000000000..bd2af729795f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawAssignments.java @@ -0,0 +1,18 @@ +import java.io.*; +import java.util.*; + +interface Foo { + String getText(Map attributes) throws IOException; + String getText(Properties attributes) throws IOException; +} + +class Bar { + void foo(Foo foo, Properties prop) throws IOException { + foo.getText(prop); + } +} +public abstract class Hashtable<K,V> implements Map<K,V>, Cloneable { +} + +public abstract class Properties extends Hashtable<Object,Object> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawOnParameterized.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawOnParameterized.java new file mode 100644 index 000000000000..ebdeca98a1f1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawOnParameterized.java @@ -0,0 +1,29 @@ +class GenericOuter<T> { + public class GenericInner<U> { + } + + public static class StaticGenericInner<U> { + } + + public class SimpleInner { + } +} + +class OuterClient { + public void context() { + <error descr="Improper formed type; some type parameters are missing">GenericOuter<String>.GenericInner</error> v1 = null; + GenericOuter.GenericInner<error descr="Type arguments given on a raw type"><String></error> v2 = null; + GenericOuter.GenericInner v3 = null; + GenericOuter<String>.GenericInner<String> v4 = null; + + GenericOuter<error descr="Cannot select static class 'GenericOuter.StaticGenericInner' from parameterized type"><String></error>.StaticGenericInner sv1 = null; + GenericOuter.StaticGenericInner<String> sv2 = null; + GenericOuter.StaticGenericInner sv3 = null; + GenericOuter<error descr="Cannot select static class 'GenericOuter.StaticGenericInner' from parameterized type"><String></error>.StaticGenericInner<String> sv4 = null; + + GenericOuter<String>.SimpleInner iv1 = null; + GenericOuter.SimpleInner<error descr="Type arguments given on a raw type"><String></error> iv2 = null; + GenericOuter.SimpleInner iv3 = null; + GenericOuter<String>.SimpleInner<error descr="Type 'GenericOuter.SimpleInner' does not have type parameters"><String></error> iv4 = null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawOverridingMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawOverridingMethods.java new file mode 100644 index 000000000000..19340121a4c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/RawOverridingMethods.java @@ -0,0 +1,271 @@ +import java.util.*; + +class Base<T> { + public void method(Base<?> base) { } + public void method1(Base<Base<?>> base) { } + public <V> Base<V> foo() { return null; } + public Base<?> bar() { return null; } + public Base<Base<?>> far() { return null; } +} + +class Derived extends Base { + public void method(Base base) { } + public Base foo() { return null; } + public Base bar() { return null; } +} + +class Derived1 extends Base { + <error descr="'method1(Base<String>)' in 'Derived1' clashes with 'method1(Base<Base<?>>)' in 'Base'; both methods have same erasure, yet neither overrides the other">public void method1(Base<String> base)</error> { } + public Base<String> far() { return null; } // Acceptable construct as of JDK 1.5 beta 2 may 2004 +} + +class X <T> { + public <V> void foo () {} +} + +class YY extends X { + <error descr="'foo()' in 'YY' clashes with 'foo()' in 'X'; both methods have same erasure, yet neither overrides the other">public <V> void foo()</error> {} +} + +interface List<Y> { + public <T> T[] toArray(T[] ts); +} +class AbstractList<Y> { + public <T> T[] toArray(T[] ts) {return null;} +} +//Signatures from List and AbstractList are equal +class ArrayList extends AbstractList implements List {} + +//SCR 39485: the following overriding is OK +abstract class Doer { + abstract <X> void go(X x); +} + +class MyList <X> + extends Doer { + X x; + <Y> void go(Y y) {} +} + +class MyListRaw + extends MyList { +} + +//See IDEADEV-1125 +//The following two classes are OK +class A1 { + <T> void foo(T t) {} +} + +class A2 extends A1 { + void foo(Object o) {} +} + +//While these are not +class A3 { + void foo(Object o) {} +} + +class A4 extends A3 { + <error descr="'foo(T)' in 'A4' clashes with 'foo(Object)' in 'A3'; both methods have same erasure, yet neither overrides the other"><T> void foo(T t)</error> {} +} + +//This sibling override is OK +class A5 { + public void foo(Object o) {} +} + +interface I1 { + <T> void foo(T t); +} + +class A6 extends A5 implements I1 {} + +//While this is not +class A7 { + public <T> void foo(T t) {} +} + +interface I2 { + public void foo(Object o); +} + +<error descr="Class 'A8' must either be declared abstract or implement abstract method 'foo(Object)' in 'I2'">class A8 extends A7 implements I2</error> {} + +//IDEA-9321 +abstract class MyMap<K, V> implements java.util.Map<K, V> { + public <error descr="'put(K, V)' in 'MyMap' clashes with 'put(K, V)' in 'java.util.Map'; attempting to use incompatible return type">Object</error> put(K key, V value) { + return null; + } +} +//end of IDEA-9321 + +abstract class AA <T> { + abstract void foo(T t); +} + +abstract class BB<T> extends AA<BB> { + void foo(BB b) {} +} + +class CC extends BB { + //foo is correctly seen from BB +} + +class QQQ {} + +abstract class GrandParent<T> { + public abstract void paint(T object); +} + +class Parent<T extends QQQ> extends GrandParent<T> { + public void paint(T component) { + } +} + +// this overriding should be OK +class Child2 extends Parent { + +} + +class IDEA16494 { + class Base<B> { + public List<B> elements() { + return null; + } + } + + class Derived<T> extends Base<T[]> { + } + + class MostDerived extends Derived { + + public List<MostDerived[]> elements() { + return null; + } + } +} +class IDEA16494Original { + class Base<B> { + public List<B> elements() { + return null; + } + } + + class Derived<T> extends Base<T> { + } + + class MostDerived extends Derived { + + public List<MostDerived> elements() { + return null; + } + } +} +class IDEADEV23176Example { + public abstract class AbstractBase<E> extends AbstractParent<E> implements Interface<E> { + } + public abstract class AbstractParent<E> { + public void Implemented(Collection<?> c) { + } + public abstract void mustImplement(); + } + public class Baseclass extends AbstractBase implements Interface { + public void mustImplement() { + } + } + public interface Interface<E> { + void Implemented(Collection<?> c); + } +} + +/** @noinspection UnusedDeclaration*/ +class IDEADEV26185 +{ + public static abstract class SuperAbstract<Owner, Type> + { + public abstract Object foo(Type other); + } + + public static abstract class HalfGenericSuper<Owner> extends SuperAbstract<Owner, String> + { + public abstract Object foo(String other); + } + + public static abstract class AbstractImpl<Owner> extends HalfGenericSuper<Owner> + { + public Object foo(String other) + { + return null; + } + } + + public static class Concrete extends AbstractImpl + { + } +} + +class ideadev30090 { + abstract class MyBeanContext + implements MyListInterface/*<MyListMember>*/ { + public Object get(int index) { + return null; + } + } + + interface MyListInterface<E extends MyListMember> + extends List<E> { + } + interface MyListMember { + void f(); + } +} +////////////////////////////////////////// +class IDEADEV32421 { + interface InterfaceWithFoo { + Class<?> foo(); + } + + class ParentWithFoo implements InterfaceWithFoo { + public Class foo() { + return null; + } + } + + class TestII extends ParentWithFoo implements InterfaceWithFoo { + } +} + +class IDEADEV32421_TheOtherWay { + interface InterfaceWithFoo { + Class foo(); + } + + class ParentWithFoo implements InterfaceWithFoo { + public Class<?> foo() { + return null; + } + } + + class TestII extends ParentWithFoo implements InterfaceWithFoo { + } +} +////////////////////////////////////// +class SBBug { + abstract class A<T> implements Comparable<A<T>> {} + + class B extends A { + public int compareTo(Object o) { + return 0; + } + } +} +class SBBug2 { + abstract class A<T> implements Comparable<A<T>> {} + + <error descr="Class 'B' must either be declared abstract or implement abstract method 'compareTo(T)' in 'Comparable'">class B extends A</error> { + public int compareTo(A o) { + return 0; + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ReferenceTypeParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ReferenceTypeParams.java new file mode 100644 index 000000000000..2d64d7c8bc36 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ReferenceTypeParams.java @@ -0,0 +1,152 @@ +import java.lang.Object; +import java.util.*; + +class C<T,U> { + + C c1 = new C<error descr="Wrong number of type arguments: 1; required: 2"><Integer></error>(); + C c2 = new C<error descr="Wrong number of type arguments: 3; required: 2"><Integer, Float, Object></error>(); + Object o = new Object<error descr="Type 'java.lang.Object' does not have type parameters"><C></error>(); + + C c3 = new C(); + C c4 = new C<Object, C>(); + C<Integer, Float> c5 = new C<Integer, Float>(); +} + +class D<T extends C> { + { + new D<<error descr="Type parameter 'java.lang.Integer' is not within its bound; should extend 'C'">Integer</error>>(); + new D<C>(); + class CC extends C {}; + new D<CC>(); + new D<T>(); + } + + T field = new <error descr="Type parameter 'T' cannot be instantiated directly">T</error>(); + T field2 = new <error descr="Type parameter 'T' cannot be instantiated directly">T</error>() { }; + T[] array = new <error descr="Type parameter 'T' cannot be instantiated directly">T</error>[10]; +} + +class Primitives<T> { + Object a = new Primitives<<error descr="Type argument cannot be of primitive type">? extends int</error>>(); + Object o = new Primitives<<error descr="Type argument cannot be of primitive type">int</error>>(); + void f(Primitives<<error descr="Type argument cannot be of primitive type">boolean</error>> param) { + if (this instanceof Primitives<<error descr="Type argument cannot be of primitive type">double</error>>) { + return; + } + } +} + + +/////// calling super on generic bound class +public class Generic<T> { + Generic(T t){} +} +public class Bound extends Generic<String>{ + public Bound(String s) { + super(s); + } +} + +//// +class Generic2<T1,T2> { + class A {} + class B {} + private <error descr="Incompatible types. Found: 'Generic2<java.lang.String,Generic2.B>', required: 'Generic2<java.lang.String,Generic2.A>'">Generic2<String, A> map = new Generic2<String,B>();</error> + { + <error descr="Incompatible types. Found: 'Generic2<java.lang.String,java.lang.String>', required: 'Generic2<java.lang.String,Generic2.A>'">map = new Generic2<String,String>()</error>; + map = new Generic2<String,A>(); + } +} + +class DummyList<T> {} +abstract class GenericTest3 implements DummyList<<error descr="No wildcard expected">? extends String</error>> { + DummyList<DummyList<? extends DummyList>> l; + <T> void foo () {} + void bar () { + this.<DummyList<? extends DummyList>>foo(); + DummyList<DummyList<? super String>>[] l = <error descr="Generic array creation">new DummyList<DummyList<? super String>>[0]</error>; + DummyList<String>[] l1 = <error descr="Generic array creation">{}</error>; + } + + public <T> T[] getComponents (Class<T> baseInterfaceClass) { + T[] ts = <error descr="Generic array creation">{}</error>; + + return ts; + } +} + +class mylist<T> {} +class myAList<T> extends mylist<T> { + { + mylist<String> l = <error descr="Inconvertible types; cannot cast 'myAList<java.lang.Integer>' to 'mylist<java.lang.String>'">(mylist<String>) new myAList<Integer>()</error>; + boolean b = <error descr="Operator '==' cannot be applied to 'myAList<java.lang.Integer>', 'myAList<java.lang.String>'">new myAList<Integer>() == new myAList<String>()</error>; + + if (l instanceof <error descr="Illegal generic type for instanceof">myAList<String></error>); + Object o = new Object(); + if (o instanceof <error descr="Class or array expected">T</error>); + } + + Class<T> foo (Class<T> clazz) { + Class<String> clazz1 = (Class<String>)clazz; //Should be unchecked warning + return <error descr="Cannot select from a type variable">T</error>.class; + } +} + +class testDup<T, <error descr="Duplicate type parameter: 'T'">T</error>> { // CAN IT BE HIGHLIGHTED? b + public <T, <error descr="Duplicate type parameter: 'T'">T</error>> void foo() { // CAN IT BE HIGHLIGHTED? + } +} + +class aaaa { + { + <error descr="Incompatible types. Found: 'java.lang.Class<java.lang.String>', required: 'java.lang.Class<? super java.lang.Object>'">Class<? super Object> c = String.class;</error> + } +} + +//IDEADEV-6103: this code is OK +class Foo { + mylist<Test> foo; + + public Foo(mylist<Test> foo) { + this.foo = foo; + } + + public Foo() { + this(new mylist<Test>()); + } + + private class Test { + } +} +//end of IDEADEV-6103 + +class IDontCompile { + Map<error descr="Cannot select static class 'java.util.Map.Entry' from parameterized type"><?, ?></error>.Entry map; +} + +abstract class GenericTest99<E extends Enum<E>> { + GenericTest99<<error descr="Type parameter 'java.lang.Enum' is not within its bound; should extend 'java.lang.Enum<java.lang.Enum>'">Enum</error>> local; +} + +class ClassLiteral<T> { + { + Object c1 = <error descr="Cannot select from a type variable">T</error>.class; + Object c2 = <error descr="Cannot select from a type variable">T[]</error>.class; + + Object c3 = <error descr="Cannot select from parameterized type">List<String></error>.class; + Object c4 = <error descr="Cannot select from parameterized type">List<String>[]</error>.class; + Object c5 = List[].class; + Object c6 = List.class; + } +} + +class Outer<E> { + final Inner[] i = <error descr="Generic array creation">new Inner[10]</error>; + class Inner { + } +} +class Outer1<E> { + final Inner[] i = new Inner[10]; + static class Inner { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SOE.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SOE.java new file mode 100644 index 000000000000..85aeee7a3428 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SOE.java @@ -0,0 +1,24 @@ +public class SOE { +} +abstract class VersionEntity<V extends Version<V, R>, R extends Ref<V, R>> + implements Version<V, R>{} + +interface Version<V extends Version<V, R>, R extends Ref<V, R>>{} + +abstract class RefEntity<V extends Version<V, R>, R extends Ref<V, R>> + implements Ref<V, R> {} + +interface Ref<V extends Version<V, R>, R extends Ref<V, R>>{} + + +abstract class Node<G extends Node<G, GR>, + GR extends NodeRef<G, GR>> extends VersionEntity<G, GR> {} + +abstract class NodeRef<G extends Node<G, GR>, GR extends NodeRef<G, GR>> extends RefEntity<G, GR> {} + + +class D { + void f() { + Version v = new Node<<error descr="Wildcard type '?' cannot be instantiated directly">?</error>, <error descr="Wildcard type '?' cannot be instantiated directly">?</error>>(){}<EOLError descr="';' expected"></EOLError> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SOEInLeastUpperClass.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SOEInLeastUpperClass.java new file mode 100644 index 000000000000..70ad2666c619 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SOEInLeastUpperClass.java @@ -0,0 +1,12 @@ +<error descr="Cyclic inheritance involving 'A'">interface A extends A</error> {} +interface B {} + +<error descr="Cyclic inheritance involving 'A'">class T implements A, B</error>{ + <T1> T1 foo(A a, B b) { + return null; + } + + void bar (boolean a, A a1, B b1){ + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'T'">T t = a ? a1 : b1;</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasure.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasure.java new file mode 100644 index 000000000000..9bb49b29ce2b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasure.java @@ -0,0 +1,34 @@ +import java.util.*; + +class SameSignatureTest { + <error descr="'sameErasure(List<String>)' clashes with 'sameErasure(List<Integer>)'; both methods have same erasure">public static void sameErasure(List<String> strings)</error> { + } + + public static void sameErasure(List<Integer> integers) { + } +} + + class CCC { + <error descr="'f(Object)' clashes with 'f(Object)'; both methods have same erasure"><T> void f(Object o)</error> {} + + void f(Object o) {} +} + +public class Test1 { + <error descr="'bug(String)' clashes with 'bug(String)'; both methods have same erasure">public void bug(String s)</error> { + } + + public static <T> T bug(String s) { + return null; + } +} +//////////////////////////////// +class Test { + <error descr="'test()' clashes with 'test()'; both methods have same erasure">public static <K, V> HashMap<K, V> test()</error> { + return new HashMap<K, V>(); + } + + public static String test() { + return ""; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasureDifferentReturnTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasureDifferentReturnTypes.java new file mode 100644 index 000000000000..8bbd7b65154a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SameErasureDifferentReturnTypes.java @@ -0,0 +1,53 @@ +/** @noinspection UnusedDeclaration*/ +interface Matcher<T> { + + boolean matches(java.lang.Object object); + + void _dont_implement_Matcher___instead_extend_BaseMatcher_(); +} + +interface ArgumentConstraintPhrases { + <error descr="'with(Matcher<T>)' clashes with 'with(Matcher<Boolean>)'; both methods have same erasure"><T> T with(Matcher<T> matcher)</error>; + boolean with(Matcher<Boolean> matcher); + byte with(Matcher<Byte> matcher); + short with(Matcher<Short> matcher); + int with(Matcher<Integer> matcher); + long with(Matcher<Long> matcher); + float with(Matcher<Float> matcher); + double with(Matcher<Double> matcher); +} + +class ExpectationGroupBuilder implements ArgumentConstraintPhrases { + + <error descr="'with(Matcher<T>)' clashes with 'with(Matcher<Boolean>)'; both methods have same erasure">public <T> T with(final Matcher<T> matcher)</error> { + return null; + } + + public boolean with(final Matcher<Boolean> matcher) { + return false; + } + + public byte with(final Matcher<Byte> matcher) { + return 0; + } + + public short with(final Matcher<Short> matcher) { + return 0; + } + + public int with(final Matcher<Integer> matcher) { + return 0; + } + + public long with(final Matcher<Long> matcher) { + return 0; + } + + public float with(final Matcher<Float> matcher) { + return 0; + } + + public double with(final Matcher<Double> matcher) { + return 0; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SelectFromTypeParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SelectFromTypeParameter.java new file mode 100644 index 000000000000..79229dd23e66 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SelectFromTypeParameter.java @@ -0,0 +1,16 @@ +import java.util.List; +interface Builder<T> { + T build(); +} + +interface Test<D extends Test<D, X>, X> { + static interface TestBuilder<D extends Test<D, X>, X> extends Builder<D> {} +} + +interface Algorithm<T, B extends Builder<T>> {} + +class SelectFromVariableType<X, T extends Test<T, X>> + implements Algorithm<T,<error descr="Cannot select from a type parameter">T</error>.TestBuilder<T, X>> { + List<T.TestBuilder<T, X>> b; + T.TestBuilder<T, X> b1; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SelfRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SelfRef.java new file mode 100644 index 000000000000..e1f415c23581 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SelfRef.java @@ -0,0 +1,13 @@ +import java.util.*; +class Node<K> { + List<Node<K>> getNodes() { + return null; + } + + private static <T> int strongConnect(Node<T> currentNode) { + for (Node<T> dependantNode : currentNode.getNodes()) { + strongConnect(dependantNode); + } + return 0; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SpecificReturnType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SpecificReturnType.java new file mode 100644 index 000000000000..2edfece0d570 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SpecificReturnType.java @@ -0,0 +1,13 @@ +abstract class Field<D> { + public D getValue(){return null;} +} + +class LabelField extends Field<Object> { + public Object getValue() { return null; } +} +interface MyInterface<D> { + D getValue(); +} + +class MyLabelField extends LabelField implements MyInterface<Object> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/StaticImports.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/StaticImports.java new file mode 100644 index 000000000000..047391deb774 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/StaticImports.java @@ -0,0 +1,16 @@ + +import static java.util.Arrays.asList; +import static java.util.Arrays.sort; +<warning descr="Unused import statement">import static java.util.Arrays.binarySearch;</warning> + +public class StaticImports { + { + asList(new Object[]{}); + } + + void method() { + sort(new long[0]); +// sort< error descr="Cannot resolve method 'sort()'">()< /error>; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/StaticOverride.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/StaticOverride.java new file mode 100644 index 000000000000..d0209686a9c3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/StaticOverride.java @@ -0,0 +1,8 @@ +import java.util.*; + +public class MyClass implements Comparator<String> { + + <error descr="Static method 'compare(String, String)' in 'MyClass' cannot override instance method 'compare(T, T)' in 'java.util.Comparator'">public static int compare(String a, String b)</error> { + return 42; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SuperMethodCallWithErasure.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SuperMethodCallWithErasure.java new file mode 100644 index 000000000000..4bd51c05016d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SuperMethodCallWithErasure.java @@ -0,0 +1,18 @@ +import java.util.Set; + +interface Interface { + void method(Set<?> s); +} + +class SuperClass implements Interface { + public void method(Set s) { + // do nothing + } +} + +class SubClass extends SuperClass { + public void method(Set s) { + super.method(s); //ERROR: Abstract method 'method(Set<?>)' cannot be accessed directly + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SuperWildcardIsNotWithinItsBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SuperWildcardIsNotWithinItsBound.java new file mode 100644 index 000000000000..8035e3753f97 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/SuperWildcardIsNotWithinItsBound.java @@ -0,0 +1,20 @@ + +class TopGene<T> { +} + +class MidRaw extends TopGene { +} + +class BottomGene<T> extends MidRaw { +} + +class GeneType<T extends TopGene<String>> { +} + +class GeneUser { + public void success(GeneType<? extends BottomGene<String>> p) { + } + + public void fail(GeneType<<error descr="Type parameter '? super BottomGene<String>' is not within its bound; should extend 'TopGene<java.lang.String>'">? super BottomGene<String></error>> p) { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ThisAsAccessObject.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ThisAsAccessObject.java new file mode 100644 index 000000000000..ea3ecf06912c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ThisAsAccessObject.java @@ -0,0 +1,9 @@ +class Outer { + private void foo() {} + class Inner extends Outer { + { + this.<error descr="'foo()' has private access in 'Outer'">foo</error>(); + foo(); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgsOnRaw.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgsOnRaw.java new file mode 100644 index 000000000000..f8e48b201857 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgsOnRaw.java @@ -0,0 +1,21 @@ +class GenericsTest { + + static class SomeClass<U> { + public <T> T getX() { + return null; + } + public String f() { + return this.<String>getX(); + } + } + + + + public static void main(String[] args) { + + String v1 = new SomeClass().<error descr="Type arguments given on a raw method"><String></error>getX(); + String v2 = new SomeClass().f(); // + + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsGivenOnAnonymousClassCreation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsGivenOnAnonymousClassCreation.java new file mode 100644 index 000000000000..249c3aea0fec --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsGivenOnAnonymousClassCreation.java @@ -0,0 +1,12 @@ +class C +{ + Object x = new <error descr="Anonymous class implements interface; cannot have type arguments"><Integer></error> D() { }; + Object x1 = new <Integer> P() { }; + Object x2 = new <Integer> U() { }; + Object x3 = new <error descr="Anonymous class implements interface; cannot have type arguments"><Integer></error> I() { }; + interface D{} + abstract class P {} +} + +interface I {} +class U {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsGivenOnRawType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsGivenOnRawType.java new file mode 100644 index 000000000000..09ff35bad8d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsGivenOnRawType.java @@ -0,0 +1,49 @@ +import java.util.List; +class A<D> { + abstract class C<S> { + <T extends A> void foo(T.C<Integer> x) { + Integer bar = x.bar(); + } + + <T extends A> void foo1(A.C<error descr="Type arguments given on a raw type"><Integer></error> x) { + Integer bar = x.bar(); + } + + <T extends A> void foo2(A<String>.C<Integer> x) { + Integer bar = x.bar(); + } + + abstract S bar(); + } +} + +class A1 { + abstract class C<S> { + <T extends A1> void foo(T.C<Integer> x) { + Integer bar = x.bar(); + } + + <T extends A1> void foo1(A1.C<Integer> x) { + Integer bar = x.bar(); + } + + abstract S bar(); + } +} + +interface Builder<T> { + T build(); +} + +interface Test<D extends Test<D, X>, X> { + static interface TestBuilder<D extends Test<D, X>, X> extends Builder<D> {} +} + +interface Algorithm<T, B extends Builder<T>> {} + +class SelectFromVariableType<X, T extends Test<T, X>> + implements Algorithm<T, <error descr="Cannot select from a type parameter">T</error>.TestBuilder<T, X>> { + + List<T.TestBuilder<T, X>> b; + T.TestBuilder<T, X> b1; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsOnRawType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsOnRawType.java new file mode 100644 index 000000000000..7f38140c1e6b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsOnRawType.java @@ -0,0 +1,43 @@ +interface I{ + <T extends Iterable<String>> void foo(); +} + +abstract class A<S> implements I { + public abstract <T extends Iterable<String>> void foo(); + <T extends A> void bar(T x){ + A a = null; + a.<Iterable<String>> foo(); + x.<Iterable<String>> foo(); + } +} + +abstract class B<S> { + public abstract <T extends Iterable<String>> void foo(); + <T extends B> void bar(T x){ + B a = null; + a.<Iterable<String>>foo(); + x.<Iterable<String>> foo(); + } +} + +abstract class C<S> { + public abstract <T extends Iterable<String>> void foo(); + <T extends C & I> void bar(T x){ + x.<Iterable<String>> foo(); + } +} + +//--------------------------------------------------------------- +interface I1 { + void foo(); +} + + +abstract class B1<S> { + public abstract <T extends Iterable<String>> void foo(); + <T extends B1 & I1> void bar(T x){ + B1 a = null; + a.<Iterable<String>>foo(); + x.<Iterable<String>>foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsOnRawType17.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsOnRawType17.java new file mode 100644 index 000000000000..f586b18a8a1d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeArgumentsOnRawType17.java @@ -0,0 +1,43 @@ +interface I{ + <T extends Iterable<String>> void foo(); +} + +abstract class A<S> implements I { + public abstract <T extends Iterable<String>> void foo(); + <T extends A> void bar(T x){ + A a = null; + a.<Iterable<String>> foo(); + x.<Iterable<String>> foo(); + } +} + +abstract class B<S> { + public abstract <T extends Iterable<String>> void foo(); + <T extends B> void bar(T x){ + B a = null; + a.<error descr="Type arguments given on a raw method"><Iterable<String>></error> foo(); + x.<Iterable<String>> foo(); + } +} + +abstract class C<S> { + public abstract <T extends Iterable<String>> void foo(); + <T extends C & I> void bar(T x){ + x.<Iterable<String>> foo(); + } +} + +//--------------------------------------------------------------- +interface I1 { + void foo(); +} + + +abstract class B1<S> { + public abstract <T extends Iterable<String>> void foo(); + <T extends B1 & I1> void bar(T x){ + B1 a = null; + a.<error descr="Type arguments given on a raw method"><Iterable<String>></error> foo(); + x.<Iterable<String>> foo(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeInference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeInference.java new file mode 100644 index 000000000000..0156c7531a87 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeInference.java @@ -0,0 +1,95 @@ +import java.io.FileNotFoundException; +import java.util.*; + +interface PrivilegedExceptionAction <E extends Exception> { + void run() throws E; +} + +class AccessController { + public static <E extends Exception> Object doPrivileged(PrivilegedExceptionAction<E> action) throws E { + return null; + } +} +class Test { + public static void main(String[] args) { + try { + AccessController.doPrivileged( + new PrivilegedExceptionAction<FileNotFoundException>() { + public void run() throws FileNotFoundException { + } + }); + } catch (FileNotFoundException f) { + } + } + +// @#@! mock JDK Class does not take params +// static <T> T create(Class<T> t) throws InstantiationException, IllegalAccessException { +// return t.newInstance(); +// } +} + +//IDEADEV-6390 +class Printer<T> { + private final List<T> _elements; + + private Printer(final Collection<? extends T> col) { + _elements = new ArrayList<T>(col); + } + + public static <T> Printer<T> build(final Collection<? extends T> col) { + return new Printer<T>(col); + } + + public static <T, S extends T> Printer<T> build(final S... elements) { + return new Printer<T>(Arrays.asList(elements)); + } + + public void print() { + for (final T element : _elements) { + System.out.println(element); + } + + } + + public static void main(final String[] args) { + final Printer<?> objects = build(Integer.valueOf(5), Boolean.TRUE, "A String!"); //this is OK + objects.print(); + } + +} +//end of IDEADEV-6390 + +//IDEADEV-6738 +interface I1<P1 extends I1<P1,P2>, P2 extends I2<P1,P2>>{} +interface I2<P1 extends I1<P1,P2>, P2 extends I2<P1,P2>>{} + +class C1 implements I1<C1,C2>{} +class C2 implements I2<C1,C2>{} + +class U { + public static <P1 extends I1<P1,P2>, P2 extends I2<P1,P2>> P1 test(P1 p1) { + return null; + } + { + C1 c = new C1(); + U.test(c); //this should be OK + } +} +//end of IDEADEV-6738 + +/////////////////////////////////// +public class Err { + void f() { + Decl[] extensions = getExtensions(Decl.EXTENSION_POINT_NAME); + } + + static <T> T[] getExtensions(List<T> tExtensionPointName) { + return null; + } + + public static class Decl<K,V> { + public static List<Decl> EXTENSION_POINT_NAME = null; + } + +} +///////////////////////////////////// diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundVisibility.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundVisibility.java new file mode 100644 index 000000000000..68c2337916c0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundVisibility.java @@ -0,0 +1,50 @@ +class A { + private int value = 1; + + static class B<T extends A> { + void print(T t) { + System.out.println(t.<error descr="'value' has private access in 'A'">value</error>); + } + } +} + +abstract class Foo<T extends Foo<T>> { + private int field; + + public int bar(T t){ + return t.<error descr="'field' has private access in 'Foo'">field</error>; + } +} + +public class Bug { + // Idea incorrectly analyses this code with JDK 7 + public <T extends Bug> void doit(T other) { + // Oops, was legal with JDK 6, no longer legal with JDK 7 + other.<error descr="'mPrivate()' has private access in 'Bug'">mPrivate</error>(); + // Redundant with JDK 6, not a redundant cast with JDK 7 + ((Bug)other).mPrivate(); + } + + // Idea correctly analyses this code + public void doit2(SubClass other) { + // Not legal with JDK 6 or 7 + other.<error descr="'mPrivate()' has private access in 'Bug'">mPrivate</error>(); + // Not redundant with JDK 6 or 7 + ((Bug)other).mPrivate(); + } + + private void mPrivate() { + } +} + +class SubClass extends Bug { +} + +class A67678 +{ + private void foo(){} + <T extends A67678 & Cloneable> void bar(T x) + { + x.<error descr="'foo()' has private access in 'A67678'">foo</error>(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundsList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundsList.java new file mode 100644 index 000000000000..506add049639 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundsList.java @@ -0,0 +1,33 @@ +class C<T extends Runnable&<error descr="Interface expected here">Exception</error>,U> { + +} + +class Stuff<X extends Stuff & Runnable> { + <T, V extends T & <error descr="Type parameter cannot be followed by other bounds">Runnable</error>> T method(V v) { + return null; + } + + <T extends X & <error descr="Type parameter cannot be followed by other bounds">Runnable</error> & <error descr="Type parameter cannot be followed by other bounds">Comparable</error>> void f(T t) { + + } + + <T extends Stuff & Runnable & Comparable> void f2(T t) { + + } + <T extends Runnable & Comparable> void f3(T t) { + + } +} + +//////////////// +public class TypeParameters { + class X {} + static <T extends X> void f(Class<T> t){} + + static { + f(X.class); + } +} +class Typr { + <T extends TypeParameters.X> void f() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParamsCyclicInference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParamsCyclicInference.java new file mode 100644 index 000000000000..a5609115d7b8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParamsCyclicInference.java @@ -0,0 +1,2 @@ +class Test<<error descr="Cyclic inheritance involving 'T'"></error>T extends T> {} +class Test1<<error descr="Cyclic inheritance involving 'T'"></error>T extends S, S extends T> {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeWithinItsWildcardBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeWithinItsWildcardBound.java new file mode 100644 index 000000000000..47ecb3b838c3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeWithinItsWildcardBound.java @@ -0,0 +1,317 @@ +public class WithingBounds { + interface I { + } + interface I1 { + } + + void testE1() { + class A { + } + class B extends A { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<? extends B> pr; + } + + void testERec1() { + class A { + } + class B<K> extends A { + } + class C<Y>{} + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<<error descr="Type parameter '? extends C<? extends C>' is not within its bound; should extend 'A'">? extends C<? extends C></error>> pr; + ToCheckExtends<? extends B<? extends C>> pr1; + } + + + void testE2() { + class A { + } + class B { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<<error descr="Type parameter '? extends B' is not within its bound; should extend 'A'">? extends B</error>> pr; + } + + void testE22() { + class B { + } + class A extends B { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<? extends B> pr; + } + + + void testE23() { + class A { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<? extends I> pr; + } + + void testE24() { + final class A { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<<error descr="Type parameter '? extends I' is not within its bound; should extend 'A'">? extends I</error>> pr; + } + + + void testE25() { + class B { + void foo() { + this.<Iterable>bar(); + } + + <T extends Iterable<String>> void bar() { + } + } + } + + void testE26() { + class A<T>{} + class B { + void foo() { + this.<A>bar(); + } + + <T extends A<String>> void bar() { + } + } + } + + //--------------------------------- + + void testE3() { + class A { + } + class ToCheckExtends<TTT extends I> { + } + + ToCheckExtends<? extends A> pr; + } + + void testE4() { + final class A { + } + class ToCheckExtends<TTT extends I> { + } + + ToCheckExtends<<error descr="Type parameter '? extends A' is not within its bound; should extend 'WithingBounds.I'">? extends A</error>> pr; + } + + void testE5() { + final class A implements I { + } + class ToCheckExtends<TTT extends I> { + } + + ToCheckExtends<? extends A> pr; + } + + + interface AInterface { + } + void testE6() { + + class ToCheckExtends<TTT extends I> { + } + + ToCheckExtends<? extends AInterface> pr; + } + + //----------------------------- + + void testS1() { + class A { + } + class B extends A { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<? super B> pr; + } + + void testS2() { + class A { + } + class B { + } + class ToCheckExtends<TTT extends A> { + } + + ToCheckExtends<<error descr="Type parameter '? super B' is not within its bound; should extend 'A'">? super B</error>> pr; + } + + void testS3() { + class A { + } + class B extends A { + } + class ToCheckExtends<TTT extends B> { + } + + ToCheckExtends<<error descr="Type parameter '? super A' is not within its bound; should extend 'B'">? super A</error>> pr; + } + + void testMisc() { + class A<T, S extends T> {} + class i {} + final class ii extends i {} + + A<String, String> pr4; + A<Integer, <error descr="Type parameter 'java.lang.String' is not within its bound; should extend 'java.lang.Integer'">String</error>> pr5; + A<String, ? extends String> pr51; + A<Integer, <error descr="Type parameter '? extends String' is not within its bound; should extend 'java.lang.Integer'">? extends String</error>> pr52; + A<String, ? super String> pr53; + A<ii, <error descr="Type parameter 'i' is not within its bound; should extend 'ii'">i</error>> pr54; + A<i, ii> pr55; + A<i, ? extends ii> pr56; + A<ii, ? extends i> pr57; + A<i, ? super ii> pr58; + A<ii, <error descr="Type parameter '? super i' is not within its bound; should extend 'ii'">? super i</error>> pr59; + A<i, <error descr="Type parameter '? extends A<i, i>' is not within its bound; should extend 'i'">? extends A<i, i></error>> pr510; + A<i, <error descr="Type parameter 'ii[]' is not within its bound; should extend 'i'">ii[]</error>> pr511; + A<i, ?> pr512; + + A<?, ?> pr30; + A<?, <error descr="Type parameter 'i' is not within its bound; should extend '?'">i</error>> pr3; + A<? extends Object, i> pr330; + A<?, ? extends ii> pr2; + A<?, <error descr="Type parameter '? super String' is not within its bound; should extend '?'">? super String</error>> pr10; + A<?, <error descr="Type parameter 'A' is not within its bound; should extend '?'">A<?, ?></error>> pr31; + A<?, <error descr="Type parameter 'ii[]' is not within its bound; should extend '?'">ii[]</error>> pr32; + A<?, <error descr="Type parameter 'A' is not within its bound; should extend '?'">A<i, i></error>> pr33; + + A<? extends i, i> pr6; + A<? extends ii, <error descr="Type parameter 'i' is not within its bound; should extend '? extends ii'">i</error>> pr6x1; + A<? extends i, ii> pr6x2; + A<? extends ii, ii> pr6x3; + A<? extends i, <error descr="Type parameter 'java.lang.Integer' is not within its bound; should extend '? extends i'">Integer</error>> pr8; + + A<? extends i, <error descr="Type parameter '? extends String' is not within its bound; should extend '? extends i'">? extends String</error>> pr12; + A<? extends i, ? extends i> pr13; + A<? extends i, ? extends ii> pr14; + A<? extends ii, ? extends i> pr13x3; + A<? extends ii, ? extends ii> pr13x4; + + + A<? extends i, ? super i> pr19; + A<? extends i, ? super ii> pr110; + A<? extends ii, ? super ii> pr11x0; + A<? extends ii, <error descr="Type parameter '? super i' is not within its bound; should extend '? extends ii'">? super i</error>> pr111; + + A<? extends i, ?> pr15; + A<? extends i, <error descr="Type parameter 'ii[]' is not within its bound; should extend '? extends i'">ii[]</error>> pr16; + A<? extends i, <error descr="Type parameter 'A' is not within its bound; should extend '? extends i'">A<?, ?></error>> pr17; + A<? extends i, <error descr="Type parameter 'A' is not within its bound; should extend '? extends i'">A<ii, ii></error>> pr18; + A<? extends ii, <error descr="Type parameter '? super String' is not within its bound; should extend '? extends ii'">? super String</error>> pr112; + A<? extends ii, <error descr="Type parameter '? super A<i, i>' is not within its bound; should extend '? extends ii'">? super A<i, i></error>> pr113; + + A<? super i, i> pr701; + A<? super i, <error descr="Type parameter 'java.lang.String' is not within its bound; should extend '? super i'">String</error>> pr72; + A<? super i, ?> pr73; + A<? super i, <error descr="Type parameter 'ii[]' is not within its bound; should extend '? super i'">ii[]</error>> pr74; + A<? super i, <error descr="Type parameter '? extends String' is not within its bound; should extend '? super i'">? extends String</error>> pr75; + A<? super i, ? extends i> pr76; + A<? super ii, ? extends i> pr77; + A<? super ii, ? extends ii> pr78; + A<? super i, ? super i> pr79; + A<? super i, ? super ii> pr791; + A<? super ii, ? super ii> pr713; + A<? super i, <error descr="Type parameter '? super String' is not within its bound; should extend '? super i'">? super String</error>> pr712; + A<? super ii, <error descr="Type parameter '? super i' is not within its bound; should extend '? super ii'">? super i</error>> pr710; + A<? super ii, <error descr="Type parameter 'i' is not within its bound; should extend '? super ii'">i</error>> pr70; + A<? super i, ii> pr71; + A<? super i, ? extends ii> pr711; + + A<i[], i[]> a1; + A<i[], <error descr="Type parameter 'java.lang.Object' is not within its bound; should extend 'i[]'">Object</error>> a2; + A<i[], ii[]> a3; + A<ii[], <error descr="Type parameter 'i[]' is not within its bound; should extend 'ii[]'">i[]</error>> a4; + + A<i[], <error descr="Type parameter 'int[]' is not within its bound; should extend 'i[]'">int[]</error>> a5; + A<Object, int[]> a6; + A<Cloneable, int[]> a7; + A<java.io.Serializable, int[]> a8; + A<Cloneable[], <error descr="Type parameter 'int[]' is not within its bound; should extend 'java.lang.Cloneable[]'">int[]</error>> a9; + A<Cloneable[], int[][]> a10; + A<Cloneable[][], int[][][]> a11; + A<Cloneable[], <error descr="Type parameter 'i[]' is not within its bound; should extend 'java.lang.Cloneable[]'">i[]</error>> a12; + A<Cloneable[], i[][]> a13; + + A<? super i[], ii[]> a14; + A<? super i[], i[]> a140; + A<? super ii[], <error descr="Type parameter 'i[]' is not within its bound; should extend '? super ii[]'">i[]</error>> a141; + A<? super i[], <error descr="Type parameter 'i' is not within its bound; should extend '? super i[]'">i</error>> a142; + A<? super i[], <error descr="Type parameter 'java.lang.String' is not within its bound; should extend '? super i[]'">String</error>> a143; + A<? super i[], <error descr="Type parameter 'i[][]' is not within its bound; should extend '? super i[]'">i[][]</error>> a144; + A<? super i[], ? extends i[]> a145; + A<? super i[], ? extends ii[]> a146; + A<? super ii[], ? extends i[]> a147; + A<? super i[], <error descr="Type parameter '? extends i' is not within its bound; should extend '? super i[]'">? extends i</error>> a148; + A<? super i[], <error descr="Type parameter '? extends String' is not within its bound; should extend '? super i[]'">? extends String</error>> a149; + A<? super i[], ?> a1410; + A<? super i[], <error descr="Type parameter '? extends i[][]' is not within its bound; should extend '? super i[]'">? extends i[][]</error>> a1411; + A<? super i[], ? super i[]> a1412; + A<? super i[], ? super ii[]> a1413; + A<? super ii[], <error descr="Type parameter '? super i[]' is not within its bound; should extend '? super ii[]'">? super i[]</error>> a1414; + A<? super i[], <error descr="Type parameter '? super i' is not within its bound; should extend '? super i[]'">? super i</error>> a1415; + A<? super i[], <error descr="Type parameter '? super String' is not within its bound; should extend '? super i[]'">? super String</error>> a1416; + A<? super i[], <error descr="Type parameter '? super i[][]' is not within its bound; should extend '? super i[]'">? super i[][]</error>> a1417; + + A<? extends i[], ii[]> a15; + A<? extends i[], i[]> a150; + A<? extends ii[],<error descr="Type parameter 'i[]' is not within its bound; should extend '? extends ii[]'">i[]</error>> a151; + A<? extends i[], <error descr="Type parameter 'i' is not within its bound; should extend '? extends i[]'">i</error>> a152; + A<? extends i[], <error descr="Type parameter 'java.lang.String' is not within its bound; should extend '? extends i[]'">String</error>> a153; + A<? extends i[], <error descr="Type parameter 'i[][]' is not within its bound; should extend '? extends i[]'">i[][]</error>> a154; + A<? extends i[], ? extends i[]> a155; + A<? extends i[], ? extends ii[]> a156; + A<? extends ii[], ? extends i[]> a157; + A<? extends i[], <error descr="Type parameter '? extends i' is not within its bound; should extend '? extends i[]'">? extends i</error>> a158; + A<? extends i[], <error descr="Type parameter '? extends String' is not within its bound; should extend '? extends i[]'">? extends String</error>> a159; + A<? extends i[], ?> a1510; + A<? extends i[], <error descr="Type parameter '? extends i[][]' is not within its bound; should extend '? extends i[]'">? extends i[][]</error>> a1511; + A<? extends i[], ? super i[]> a1512; + A<? extends i[], ? super ii[]> a1513; + A<? extends ii[], <error descr="Type parameter '? super i[]' is not within its bound; should extend '? extends ii[]'">? super i[]</error>> a1514; + A<? extends i[], <error descr="Type parameter '? super i' is not within its bound; should extend '? extends i[]'">? super i</error>> a1515; + A<? extends i[], <error descr="Type parameter '? super String' is not within its bound; should extend '? extends i[]'">? super String</error>> a1516; + A<? extends i[], <error descr="Type parameter '? super i[][]' is not within its bound; should extend '? extends i[]'">? super i[][]</error>> a1517; + + A<? extends Cloneable, ? extends i[]> a16; + A<? extends Cloneable[], ? extends i[][]> a160; + A<Cloneable, ? extends i[]> a161; + A<? super Cloneable, ? extends i[]> a162; + A< I1[], ? extends I[]> cl; + + } + + void testRawTypes() { + class A<T extends A<T>> {} + A a; + A<<error descr="Type parameter 'java.lang.String' is not within its bound; should extend 'A<java.lang.String>'">String</error>> a1; + A<<error descr="Type parameter 'A' is not within its bound; should extend 'A<A>'">A</error>> a2; + A<A<<error descr="Type parameter 'A' is not within its bound; should extend 'A<A>'">A</error>>> a3; + + A<? extends A> a4; + A<<error descr="Type parameter '? super A' is not within its bound; should extend 'A<? super A>'">? super A</error>> a5; + A<<error descr="Type parameter 'A[]' is not within its bound; should extend 'A<A[]>'">A[]</error>> a7; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedCasts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedCasts.java new file mode 100644 index 000000000000..0532d1f1f6ce --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedCasts.java @@ -0,0 +1,108 @@ +import java.util.*; + +class X<<warning descr="Type parameter 'T' is never used">T</warning>> { + +} + +class XX<T> extends X<T> { + Object f(X<String> x) { + if (x != null) { + XX<String> xx = <warning descr="Unchecked cast: 'XX' to 'XX<java.lang.String>'">(XX<String>)new XX()</warning>; + return xx; + } + if (1 == 1) { + XX<String> xx = (XX<String>)x; + return xx; + } + return null; + } +} + +class eee<COMP extends eee> { + COMP comp; + COMP foo() { + return <warning descr="Unchecked cast: 'eee' to 'COMP'">(COMP) new eee()</warning>; + } +} + +class AllPredicate<T> + { + private List<Set<? super T>> lists; + + public void e(AllPredicate that) + { + lists = <warning descr="Unchecked cast: 'java.util.List' to 'java.util.List<java.util.Set<? super T>>'">(List<Set<? super T>>)that.lists</warning>; + } + + public static List<String> fff() { + Collection<String> c = new ArrayList<String>(); + return (List<String>) c; //not unchecked + } + + public static Comparable<Object> ggg() { + Object time = new Object(); + return <warning descr="Unchecked cast: 'java.lang.Object' to 'java.lang.Comparable<java.lang.Object>'">(Comparable<Object>) time</warning>; + } + + public static void foo(SortedMap<?, ?> sourceSortedMap) { + new TreeMap<Object, Object>(<warning descr="Unchecked cast: 'java.util.Comparator<capture<?>>' to 'java.util.Comparator<? super java.lang.Object>'">(Comparator<? super Object>) sourceSortedMap.comparator()</warning>); + } +} + +class K { } +class L extends K { } +class M { + public static <T extends K> L f(T t) { + return (L) t; //this should NOT generate unchecked cast + } +} + +class UncheckedCastFalsePositive { + + public static void method(Object something) { + if (something instanceof NumberList) { + NumberList<? extends Number> <warning descr="Variable 'numberList' is never used">numberList</warning> = (NumberList<? extends Number>) something; + } + + } + + public static class NumberList<E extends Number> extends ArrayList<E> { + } + +} + +class IDEA21547 { + class O {} + class A<<warning descr="Type parameter 'T' is never used">T</warning>> {} + class B<K extends O> extends A<K>{} + + public void bar(A<? extends O> a, B<O> b) { + b = <warning descr="Unchecked cast: 'IDEA21547.A<capture<? extends IDEA21547.O>>' to 'IDEA21547.B<IDEA21547.O>'">(B<O>)a</warning>; + System.out.println(b); + } + + public void bar1(A<?> a, B<O> b) { + b = <warning descr="Unchecked cast: 'IDEA21547.A<capture<?>>' to 'IDEA21547.B<IDEA21547.O>'">(B<O>)a</warning>; + System.out.println(b); + } + + public void bar2(A<?> a, B<?> b) { + b = <warning descr="Unchecked cast: 'IDEA21547.A<capture<?>>' to 'IDEA21547.B<IDEA21547.O>'">(B<O>)a</warning>; + System.out.println(b); + } + + public void bar4(A<? extends O> a, B<?> b) { + b = <warning descr="Unchecked cast: 'IDEA21547.A<capture<? extends IDEA21547.O>>' to 'IDEA21547.B<IDEA21547.O>'">(B<O>)a</warning>; + System.out.println(b); + } + + public void bar5(A<? super O> a, B<?> b) { + b = <warning descr="Unchecked cast: 'IDEA21547.A<capture<? super IDEA21547.O>>' to 'IDEA21547.B<IDEA21547.O>'">(B<O>)a</warning>; + System.out.println(b); + } + + public void bar6(A a, B<?> b) { + b = <warning descr="Unchecked cast: 'IDEA21547.A' to 'IDEA21547.B<IDEA21547.O>'">(B<O>)a</warning>; + System.out.println(b); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedOverriding.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedOverriding.java new file mode 100644 index 000000000000..9f71e16b1d0d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedOverriding.java @@ -0,0 +1,45 @@ +class List<T> { T t;} + +class Base<T> { + List<T> getList(List<T> l) { + return null; + } + + +} + +class Derived extends Base <String> { + <warning descr="Unchecked overriding: return type requires unchecked conversion. Found 'List', required 'List<java.lang.String>'">List</warning> getList(List<String> l) { + return null; + } +} + +class A1 { + <T> T foo(T t) { + return null; + } +} + +class A2 extends A1 { + <warning descr="Unchecked overriding: return type requires unchecked conversion. Found 'java.lang.Object', required 'T'">Object</warning> foo(Object o) { + return null; + } +} + +//IDEADEV-15918 +abstract class Outer<U> { + public abstract Inner m(U u); + + public class Inner { + } +} + +class Other extends Outer<Other> { + public Ither m(Other other) { + return new Ither(); + } + + public class Ither extends Inner { + } +} +//end of IDEADEV-15918 diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningsLevel6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningsLevel6.java new file mode 100644 index 000000000000..e9ff21b87144 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/UncheckedWarningsLevel6.java @@ -0,0 +1,128 @@ +import java.lang.Override; +import java.util.*; +class GenericsTest<T> { + + static <S> S next(GenericsTest<S> test) + { + System.out.println(test); + return null; + } + + public Iterator<T> iterator() + { + return new Iterator<T>() { + @Override + public boolean hasNext() + { + return false; + } + + @Override + public T next() + { + return GenericsTest.next(GenericsTest.this); + } + + @Override + public void remove() + { + } + }; + } +} + +class GenericsTest1<T> { + + static <S> S next1(GenericsTest1<S> test) + { + System.out.println(test); + return null; + } + + public Iterator<T> iterator() + { + return new Iterator<T>() { + @Override + public boolean hasNext() + { + return false; + } + + @Override + public T next() + { + return GenericsTest1.next1(GenericsTest1.this); + } + + @Override + public void remove() + { + } + }; + } +} + + +class GenericsTest2<T> { + + static <S> S next2(GenericsTest2<S> test) + { + System.out.println(test); + return null; + } + + public Iterator<T> iterator() + { + return new Iterator<T>() { + @Override + public boolean hasNext() + { + return false; + } + + @Override + public T next() + { + return next2(GenericsTest2.this); + } + + @Override + public void remove() + { + } + }; + } +} +class Example { + private static <T> void assertThat(T actual, Matcher<? super T> matcher) { + assert actual != null; + assert matcher != null; + } + + private static <E> Matcher<? super Collection<? extends E>> hasSize(int size) { + assert size >=0; + return new Matcher<Collection<? extends E>>() { + @Override + public void foo(Collection<? extends E> es) { + System.out.println(es); + } + }; + } + + public static void main(String[] args) { + List<Boolean> list = <warning descr="Unchecked assignment: 'java.util.ArrayList' to 'java.util.List<java.lang.Boolean>'">new ArrayList()</warning>; + System.out.println(list); + assertThat(new ArrayList<Boolean>(), hasSize(0)); + } + + private interface Matcher<T> { + void foo(T t); + } +} + +abstract class IDEA57337<<warning descr="Type parameter 'S' is never used">S</warning>> { + abstract <T> void foo(IDEA57337<? super IDEA57337<T>> x); + void bar(IDEA57337<? super IDEA57337<?>> x){ + foo(x); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Unused.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Unused.java new file mode 100644 index 000000000000..7b75df1999b0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Unused.java @@ -0,0 +1,11 @@ +enum e { + A("xxx"); + + private String s; + e(String str) { + s = str; + } + public String getS() { + return s; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Varargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Varargs.java new file mode 100644 index 000000000000..5ba94fb346e4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Varargs.java @@ -0,0 +1,33 @@ +class clazz1 { + clazz1(int... args) { args = null; } + public static class Myclazz1 extends clazz1 {} +} + +class AmbiguousReference { + void test() { + doSomething<error descr="Ambiguous method call: both 'AmbiguousReference.doSomething(String, Number...)' and 'AmbiguousReference.doSomething(Number...)' match">(null, 1)</error>; + } + + void doSomething(String s, Number... n) { + s+=n; + } + + void doSomething(Number... n) { + n.hashCode(); + } +} + +class OK { + protected void fff() { + find(""); + } + public void find(String queryString) { + queryString.hashCode(); + } + + public void find(final String queryString, final Object... values) { + queryString.hashCode(); + values.hashCode(); + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java new file mode 100644 index 000000000000..67f89f9a7314 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/Variance.java @@ -0,0 +1,285 @@ +import java.util.*; +import java.util.Comparator; + + +/** + * Created by IntelliJ IDEA. + * User: dsl + * Date: Mar 25, 2004 + * Time: 8:08:44 PM + * To change this template use File | Settings | File Templates. + */ +public class VarianceTesting { + void method(List<? extends VarianceTesting> l) { +// l.add(new VarianceTesting()); + l.add(null); + } + + static void shuffle(Collection<?> c) {} + + static class X<T> { + T field; + T[] arrayField; + T[] method() {return arrayField;}; + void putAll(Collection<? super T> c) {} + } + + void method1(List<? super VarianceTesting> l) { + List<? extends VarianceTesting> l1 = new ArrayList<VarianceTesting>(); + l1.add<error descr="'add(capture<? extends VarianceTesting>)' in 'java.util.List' cannot be applied to '(VarianceTesting)'">(new VarianceTesting())</error>; + List<List<? extends VarianceTesting>> lll = null; + lll.add(l1); + X<? extends VarianceTesting> x = new X<VarianceTesting>(); + VarianceTesting z = x.field; + VarianceTesting[] v = x.arrayField; + VarianceTesting v1 = x.arrayField[0]; + x.arrayField[0] = new VarianceTesting(); + <error descr="Incompatible types. Found: 'VarianceTesting', required: 'capture<? extends VarianceTesting>'">x.field = new VarianceTesting()</error>; + VarianceTesting[] k = x.method(); + k[0] = new VarianceTesting(); + x.method()[0] = new VarianceTesting(); + <error descr="Incompatible types. Found: 'VarianceTesting[]', required: 'capture<? extends VarianceTesting>[]'">x.arrayField = new VarianceTesting[10]</error>; + l1.addAll<error descr="'addAll(java.util.Collection<capture<? extends VarianceTesting>>)' in 'java.util.List' cannot be applied to '(java.util.ArrayList<VarianceTesting>)'">(new ArrayList<VarianceTesting>())</error>; + <error descr="Incompatible types. Found: 'java.util.ArrayList<java.lang.String>', required: 'java.util.List<? extends VarianceTesting>'">List<? extends VarianceTesting> l2 = new ArrayList<String>();</error> + List<? extends VarianceTesting> l3 = l2; + VarianceTesting t = l1.get(0); + l.add(new VarianceTesting()); + l.add(null); + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'VarianceTesting'">VarianceTesting t1 = l.get(0);</error> + X<? extends VarianceTesting> x1 = null; + x1.putAll(new ArrayList<VarianceTesting>()); + List<?> unknownlist = l; + List<?> unknownlist1 = new ArrayList<VarianceTesting>(); + List<?> unknownlist2 = new ArrayList<<error descr="Wildcard type '?' cannot be instantiated directly">?</error>>(); + shuffle(l); + shuffle(new ArrayList<VarianceTesting>()); + List<VarianceTesting> lllll = new ArrayList<VarianceTesting>(); + lllll.removeAll(new ArrayList<String>()); + } + +} + +class SuperTester <U> { + void go(Acceptor<? super U> acceptor, U u) { + acceptor.accept<error descr="'accept(SuperTester<capture<? super U>>, capture<? super U>)' in 'SuperTester.Acceptor' cannot be applied to '(SuperTester<U>, U)'">(this, u)</error>; + } + + static class Acceptor <V> { + void accept(SuperTester<V> tester, V v) { } + } +} + +class SCR40202 { + void foo(Map<?, String> map) { + for (<error descr="Incompatible types. Found: 'java.util.Iterator<java.util.Map.Entry<capture<?>,java.lang.String>>', required: 'java.util.Iterator<java.util.Map.Entry<?,java.lang.String>>'">Iterator<Map.Entry<?, String>> it = map.entrySet().iterator();</error> it.hasNext();) { + + } + } +} + +class CaptureTest { + static class Emum<T> { + T t; + public static <T extends Emum<T>> T valueOf(Class<T> enumType, + String name) { + return null; + } + } + + void foo (Class<? extends Emum<CaptureTest>> clazz) { + Emum.valueOf<error descr="'valueOf(java.lang.Class<T>, java.lang.String)' in 'CaptureTest.Emum' cannot be applied to '(java.lang.Class<capture<? extends CaptureTest.Emum<CaptureTest>>>, java.lang.String)'">(clazz, "CCC")</error>; + } +} + +class SuperTest { + public List<List<? extends SuperTest>> waitingList; + + public Comparator<List<?>> SIZE_COMPARATOR; + + { + //This call has its type arguments inferred alright: T -> List<capture<? extends SuperTest>> + Collections.sort(waitingList, SIZE_COMPARATOR); + } +} + +class Bug<A> { + static class B<C> { + } + + static class D<E> { + B<E> f() { + return null; + } + } + + <G extends A> void h(B<G> b) { + } + + void foo(D<? extends A> d) { + h(d.f()); //This call is OK as a result of reopening captured wildcard for calling "h" + } +} + +//IDEA-4215 +class Case2 { + class A {} + + class B extends A {} + + Comparator<A> aComparator; + Case2() { + + ArrayList<B> blist = new ArrayList<B>(); + + // this call is OK: T -> B + Collections.sort(blist, aComparator); + } +} + +class S1 { + <T> void f(List<T> l1, T l2) { + + } + + void bar(List<? extends S1> k) { + f<error descr="'f(java.util.List<capture<? extends S1>>, capture<? extends S1>)' in 'S1' cannot be applied to '(java.util.List<capture<? extends S1>>, S1)'">(k, k.get(0))</error>; + } +} + +class S2 { + <T> void f(List<T> l1, List<T> l2) { + + } + + void bar(List<? extends S2> k) { + f<error descr="'f(java.util.List<T>, java.util.List<T>)' in 'S2' cannot be applied to '(java.util.List<capture<? extends S2>>, java.util.List<capture<? extends S2>>)'">(k, k)</error>; + } +} + +class S3 { + <T> void f(Map<T,T> l2) { + + } + + void bar(Map<? extends S3, ? extends S3> k) { + f<error descr="'f(java.util.Map<T,T>)' in 'S3' cannot be applied to '(java.util.Map<capture<? extends S3>,capture<? extends S3>>)'">(k)</error>; + } +} + +class TypeBug { + private static class ValueHolder<T> { + public T value; + } + + public static void main(final String[] args) { + List<ValueHolder<?>> multiList = new ArrayList<ValueHolder<?>>(); + + ValueHolder<Integer> intHolder = new ValueHolder<Integer>(); + intHolder.value = 1; + + ValueHolder<Double> doubleHolder = new ValueHolder<Double>(); + doubleHolder.value = 1.5; + + multiList.add(intHolder); + multiList.add(doubleHolder); + swapFirstTwoValues<error descr="'swapFirstTwoValues(java.util.List<TypeBug.ValueHolder<T>>)' in 'TypeBug' cannot be applied to '(java.util.List<TypeBug.ValueHolder<?>>)'">(multiList)</error>; //need to be highlighted + + // this line causes a ClassCastException when checked. + Integer value = intHolder.value; + System.out.println(value); + } + + private static <T> void swapFirstTwoValues(List<ValueHolder<T>> multiList) { + ValueHolder<T> intHolder = multiList.get(0); + ValueHolder<T> doubleHolder = multiList.get(1); + + intHolder.value = doubleHolder.value; + } +} + +class OtherBug { +public static void foo(List<? extends Foo> foos) { + final Comparator<Foo> comparator = createComparator(); + Collections.sort(foos, comparator); //this call is OK + } + + private static Comparator<Foo> createComparator() { + return null; + } + + public interface Foo { + } +} + +class OtherBug1 { + public static void foo(List<? super Foo> foos) { + final Comparator<Foo> comparator = createComparator(); + Collections.sort<error descr="'sort(java.util.List<capture<? super OtherBug1.Foo>>, java.util.Comparator<capture<? super OtherBug1.Foo>>)' in 'java.util.Collections' cannot be applied to '(java.util.List<capture<? super OtherBug1.Foo>>, java.util.Comparator<OtherBug1.Foo>)'">(foos, comparator)</error>; + } + + private static Comparator<Foo> createComparator() { + return null; + } + + public interface Foo { + } +} + +//IDEADEV-7187 +class AA <B extends AA<B,C>, C extends AA<C, ?>>{} +//end of IDEADEV-7187 + +//IDEADEV-8697 +class GenericTest99<E extends GenericTest99<E, F>,F> { +} +class GenericTest99D<E extends GenericTest99D<E>> extends GenericTest99<E,Double> { +} +class Use99<U extends GenericTest99<?,F>,F> { +} +class Use99n extends Use99<GenericTest99D<?>,Double> { +} +//end of IDEADEV-8697 + +class IDEA79360 { + public static void main(Map<?, ?> map, Map<Object, Object> test) { + map.putAll<error descr="'putAll(java.util.Map<capture<?>,capture<?>>)' in 'java.util.Map' cannot be applied to '(java.util.Map<java.lang.Object,java.lang.Object>)'">(test)</error>; + map.put<error descr="'put(capture<?>, capture<?>)' in 'java.util.Map' cannot be applied to '(java.lang.String, java.lang.String)'">("", "")</error>; + map.put<error descr="'put(capture<?>, capture<?>)' in 'java.util.Map' cannot be applied to '(java.lang.Object, java.lang.Object)'">(new Object(), new Object())</error>; + map = new HashMap<Object, Object>(test); + } +} + +class GenericFailureExample { + + interface Descriptor<T extends Comparable<T>> { + Class<T> getType(); + } + + void isMarkedFaultyButCompilesClean(Descriptor<?> n) { + bar(n.getType()); + } + + <T extends Comparable<T>> void butThisWorks(Descriptor<T> n) { + bar(n.getType()); + } + + <T extends Comparable<T>> Comparator<T> bar(Class<T> type) { + return null; + } +} + +//IDEA-67675 +abstract class A67675<T> +{ + abstract T foo(); +} + +abstract class B67675<T> extends A67675<T[]> { } + +class C67675<T extends B67675<?>> +{ + void foo(T x) + { + x.foo()[0] = ""; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WideningCastToTypeParam.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WideningCastToTypeParam.java new file mode 100644 index 000000000000..7615d72908e3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WideningCastToTypeParam.java @@ -0,0 +1,51 @@ +import java.lang.Double; + +interface IConverter<C> { +} + +abstract class AbstractNumberConverter<N extends Number> implements IConverter<N> { +} + +class DoubleConverter extends AbstractNumberConverter<Double> { +} + +public class Test { + public static <C> IConverter<C> getConverter(Class<C> type) { + return (IConverter<C>)new DoubleConverter() { + }; + } + + public static <C extends String> IConverter<C> getConverter1(Class<C> type) { + return <error descr="Inconvertible types; cannot cast 'DoubleConverter' to 'IConverter<C>'">(IConverter<C>)new DoubleConverter() { + }</error>; + } + + public static <C extends Double> IConverter<C> getConverter2(Class<C> type) { + return (IConverter<C>)new DoubleConverter() { + }; + } + + public static void main(String[] args) { + IConverter<String> converter = getConverter(String.class); + IConverter<String> converter1 = getConverter1(String.class); + IConverter<String> converter2 = <error descr="Inferred type 'java.lang.String' for type parameter 'C' is not within its bound; should extend 'java.lang.Double'">getConverter2(String.class)</error>; + } +} + + +class Z { + +} + +class TestNonNarrowingConversion<T extends Z> { + public TestNonNarrowingConversion(T u) { + + } + + public T z = null; + + public int a() { + <error descr="Incompatible types. Found: 'TestNonNarrowingConversion<Z>', required: 'TestNonNarrowingConversion<T>'">TestNonNarrowingConversion<T> x = new TestNonNarrowingConversion<Z>(new Z());</error> + return 1; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardCastConversion.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardCastConversion.java new file mode 100644 index 000000000000..f610bacd5314 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardCastConversion.java @@ -0,0 +1,548 @@ +public class Test { + interface A {} + interface B {} + + //? extends A, ? extends B ----------------------------------------- + void testEE1() { + class A {} + class B {} + + W<? extends A> xx = null; + W<? extends B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A>>' to 'W<? extends B>'">(W<? extends B>) xx</error>; + } + + void testEE2() { + class A {} + class B extends A {} + + W<? extends A> xx = null; + W<? extends B> y = (W<? extends B>) xx; + } + + void testEE21() { + class A {} + class B extends A {} + + W<? extends B> xx = null; + W<? extends A> y = (W<? extends A>) xx; + } + + void testEE211() { + class A {} + final class B extends A {} + + W<? extends A> xx = null; + W<? extends B> y = (W<? extends B>) xx; + } + + void test3EE() { + W<? extends A> xx = null; + W<? extends B> y = (W<? extends B>) xx; + } + + void test4EE() { + class A {} + W<? extends A> xx = null; + W<? extends B> y = (W<? extends B>) xx; + } + + void test41EE() { + class A {} + W<? extends B> xx = null; + W<? extends A> y = (W<? extends A>) xx; + } + + void test411EE() { + final class A {} + W<? extends B> xx = null; + W<? extends A> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends Test.B>>' to 'W<? extends A>'">(W<? extends A>) xx</error>; + } + + void test412EE() { + final class A implements B {} + W<? extends B> xx = null; + W<? extends A> y = (W<? extends A>) xx; + } + + void test1() { + class A {} + class B {} + + W<? super A> xx = null; + W<? super B> y = (W<? super B>) xx; + } + + void test2() { + final class A {} + final class B {} + + W<? super A> xx = null; + W<? super B> y = (W<? super B>) xx; + } + + //? super A, ? super B ------------------------- + void test3SS() { + W<? super A> xx = null; + W<? super B> y = (W<? super B>) xx; + } + + //? extends A, ? super B ------------------------- + void test1ES() { + class A {} + class B {} + + W<? extends A> x = null; + W<? super B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A>>' to 'W<? super B>'">(W<? super B>) x</error>; + } + + void test2ES() { + class A {} + class B extends A {} + + W<? extends A> x = null; + W<? super B> y = (W<? super B>) x; + } + + void test3ES() { + class A {} + class B extends A {} + + W<? extends B> x = null; + W<? super A> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends B>>' to 'W<? super A>'">(W<? super A>) x</error>; + } + + + void test4ES() { + W<? extends B> x = null; + W<? super A> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends Test.B>>' to 'W<? super Test.A>'">(W<? super A>) x</error>; + } + + void test5ES() { + final class B implements A {} + + W<? extends A> x = null; + W<? super B> y = (W<? super B>) x; + } + + void test6ES() { + final class B implements A {} + + W<? extends B> x = null; + W<? super A> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends B>>' to 'W<? super Test.A>'">(W<? super A>) x</error>; + } + + // ? extends A, B ----------------------- + void test1EWC() { + class A { + } + class B { + } + + W<? extends A> xx = null; + W<B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A>>' to 'W<B>'">(W<B>) xx</error>; + } + + void test2EWC() { + class A { + } + + W<? extends A> xx = null; + W<?> y = (W<?>) xx; + } + + void test3EWC() { + class A { + } + class B extends A { + } + + W<? extends A> xx = null; + W<B> y = (W<B>) xx; + } + + // ? super A, B ----------------------- + void test1SWC() { + class A { + } + class B { + } + + W<? super A> xx = null; + W<B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? super A>>' to 'W<B>'">(W<B>) xx</error>; + } + + void test2SWC() { + class A { + } + + W<? super A> xx = null; + W<?> y = (W<?>) xx; + } + + void test3SWC() { + class A { + } + class B extends A { + } + + W<? super B> xx = null; + W<A> y = (W<A>) xx; + } + + // ?, ? ------------------------------------------ + void test1WWW() { + W<?> xx = null; + W<?> y = xx; + } + + //? extends P<? extends A>, B -------------------- + + void test1EEWC() { + class A { + } + class B { + } + + W<? extends P<? extends A>> xx = null; + W<? extends B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends P<? extends A>>>' to 'W<? extends B>'">(W<? extends B>) xx</error>; + } + + void test2EEWC() { + class A { + } + class B extends P { + } + + W<? extends P<? extends A>> xx = null; + W<? extends B> y = (W<? extends B>) xx; + } + + void test3EEWC() { + class A { + } + class B<TB> extends P<TB> { + } + + W<? extends P<? extends A>> xx = null; + W<? extends B<? super A>> y = (W<? extends B<? super A>>) xx; + } + + + void test4EEWC() { + class A { + } + class B<TB> extends P<TB> { + } + + W<? extends P<? extends A>> xx = null; + W<? extends B<?>> y = (W<? extends B<?>>) xx; + } + + void test5EEWC() { + class A { + } + class B<TB> extends P<TB> { + } + class C {} + + W<? extends P<? extends A>> xx = null; + W<? extends B<? extends C>> y = (W<? extends B<? extends C>>) xx; + } + + //Array Types inside wildcards + void test1AE() { + class A {} + class B {} + + W<? extends A[]> xx = null; + W<? extends B[]> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A[]>>' to 'W<? extends B[]>'">(W<? extends B[]>) xx</error>; + } + + void test11AE() { + class A {} + class B {} + + W<? extends A[]> xx = null; + W<? extends B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A[]>>' to 'W<? extends B>'">(W<? extends B>) xx</error>; + } + + void test2AE() { + class A {} + class B extends A {} + + W<? extends A[]> xx = null; + W<? extends B[]> y = (W<? extends B[]>) xx; + } + + void test21AE() { + class A {} + class B extends A {} + + W<? extends A[]> xx = null; + W<? extends B> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A[]>>' to 'W<? extends B>'">(W<? extends B>) xx</error>; + } + + + + void testIntAE() { + + W<? extends A[]> xx = null; + W<? extends B[]> y = (W<? extends B[]>) xx; + } + + void testInt1AE() { + + W<? extends A[]> xx = null; + W<? extends B[][]> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends Test.A[]>>' to 'W<? extends Test.B[][]>'">(W<? extends B[][]>) xx</error>; + } + + void testASS() { + class A {} + class B {} + + W<? super A[]> xx = null; + W<? super B[]> y = (W<? super B[]>) xx; + } + + void test1AES() { + class A {} + class B {} + + W<? extends A[]> x = null; + W<? super B[]> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends A[]>>' to 'W<? super B[]>'">(W<? super B[]>) x</error>; + } + + void test2AES() { + class A {} + class B extends A {} + + W<? extends A[]> x = null; + W<? super B[]> y = (W<? super B[]>) x; + } + + void test3AES() { + class A {} + class B extends A {} + + W<? extends B[]> x = null; + W<? super A[]> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends B[]>>' to 'W<? super A[]>'">(W<? super A[]>) x</error>; + } + + + + void test4AES() { + W<? extends B[]> x = null; + W<? super A[]> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends Test.B[]>>' to 'W<? super Test.A[]>'">(W<? super A[]>) x</error>; + } + + void test5AES() { + final class B implements A {} + + W<? extends A[]> x = null; + W<? super B[]> y = (W<? super B[]>) x; + } + + void test6AES() { + final class B implements A {} + + W<? extends B[]> x = null; + W<? super A[]> y = <error descr="Inconvertible types; cannot cast 'W<capture<? extends B[]>>' to 'W<? super Test.A[]>'">(W<? super A[]>) x</error>; + } + + // type parameters extensions: D<T extends A> + void testT3() { + class A { + } + class D<T extends A > { + class B extends A { + } + + void foo() { + D<? extends T> x = null; + D<? extends B> y = (D<? extends B>) x; + } + + } + + } + + void testT4() { + class A { + } + class D<T extends A> { + class B { + } + + void foo() { + D<? extends T> x = null; + D<<error descr="Type parameter '? extends B' is not within its bound; should extend 'A'">? extends B</error>> y = (D<<error descr="Type parameter '? extends B' is not within its bound; should extend 'A'">? extends B</error>>) x; + } + + } + + } + + + void testT5() { + class D<T> { + class B { + } + + void foo() { + D<? extends T> x = null; + D<? extends B> y = (D<? extends B>) x; + } + + } + + } + + void testT6() { + class A { + } + class D<T extends A> { + class B extends A { + } + + void foo() { + D<? super T> x = null; + D<? super B> y = (D<? super B>) x; + } + + } + + } + + void testT7() { + class A { + } + class D<T extends A> { + class B extends A { + } + + void foo() { + D<? extends T> x = null; + D<? super B> y = (D<? super B>) x; + } + + } + + } + + void testT8() { + class A { + } + class D<T extends A> { + class B extends A { + } + + void foo() { + D<? super T> x = null; + D<? extends B> y = (D<? extends B>) x; + } + + } + + } + + void testT9() { + class A { + } + class D<T> { + class B extends A { + } + + void foo() { + D<? super T> x = null; + D<? extends A> y = (D<? extends B>) x; + } + + } + + } + + void testUnbounded() { + W<?> x = null; + W<? extends A> y = ( W<? extends A>) x; + W<?> y1 = (W<?>)x; + } + + void testTypeParams() { + class MyClass<K, V> { + MyClass<K, V> convert(MyClass<? super K, ? super V> arg) { + MyClass<K, V> result = (MyClass<K, V>)arg; + return result; + } + } + } + + //IDEA-63447 + void testUnboundWildcardWithArrayTypes() { + class IUWWAT{ + private <T> void method1(T[][] matrix) { + final Class<T[]> type = (Class<T[]>) matrix.getClass().getComponentType(); + } + + private <T> void method2(T[][] matrix) { + final Class<Object> type = (Class<Object>) matrix.getClass().getComponentType(); + } + + private <T> void method3(T[][] matrix) { + final Class<Object[]> type = (Class<Object[]>) matrix.getClass().getComponentType(); + } + + private <T> void method4(T[][] matrix) { + final Class<Object[][]> type = (Class<Object[][]>) matrix.getClass().getComponentType(); + } + } + } +} + +class W<T> {} +class P<L> {} + +// IDEA-62529 +class Refx<T> { + Class<? super T> get() { return null; } + boolean f() { + if (get() == Enum.class) return false; + return (Class<Enum>)get() == Enum.class; + } +} + + +//hierarchy of type param bound +abstract class DomInvocationHandler<T extends AbstractDomChildDescriptionImpl> { + void f() { + if (this instanceof IndexedElementInvocationHandler) { + } + } +} + +interface AbstractDomChildrenDescription { +} + +class AbstractDomChildDescriptionImpl implements AbstractDomChildrenDescription { +} + +class IndexedElementInvocationHandler extends DomInvocationHandler<FixedChildDescriptionImpl> { +} + +class FixedChildDescriptionImpl extends AbstractDomChildDescriptionImpl { +} + +class CaptureSymmetry { + interface Collection<A> {} + interface List<A> extends Collection<A>{} + class ArrayList<A> implements List<A> {} + + public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) { + return null; + } + + public <B extends List<?>> Collection<? extends B> getBreakpoints (List<B> b) { + Collection<? extends ArrayList<?>> breakpoints = null; + Collection<? extends B> regular = breakpoints != null ? unmodifiableCollection((Collection<? extends B>)breakpoints) : b; + return null; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardTypes.java new file mode 100644 index 000000000000..d55e641fef11 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardTypes.java @@ -0,0 +1,246 @@ +import java.util.*; + +class a { + public void printList(List<?> list) { + for (Iterator<?> i = list.iterator(); i.hasNext();) { + System.out.println(i.next().toString()); + } + } +} + +class b<<warning descr="Type parameter 'T' is never used">T</warning>> { + public interface Lst <E, Self extends Lst<E, Self>> { + Self subList(int fromIndex, int toIndex); + } + + public static Lst<?, ?> foo(Lst<?, ?> lst) { + Lst<?, ?> myl = lst.subList(0, 2); + return myl; + } +} + +class ThingUser <V> { + V v; + { + new ThingUser<<error descr="Wildcard type '?' cannot be instantiated directly">?</error>>() { + }; + } +} + +class SuperWildcardTest { + static void method(List<?> list) { + <error descr="Incompatible types. Found: 'java.util.List<capture<?>>', required: 'java.util.List<? super java.lang.String>'">List<? super String> l = list;</error> + l.size(); + } +} + +class IdeaDev4166 { + Map<String, Object> f( Map<String, ?> fieldsTemplate) { + return new HashMap<String, Object>( fieldsTemplate); + } +} + +//IDEADEV-5816 +class TwoD { + int x, y; + TwoD(int a, int b) { + x = a; + y = b; + } +} +// Three-dimensional coordinates. +class ThreeD extends TwoD { + int z; + ThreeD(int a, int b, int c) { + super(a, b); + z = c; + } +} +// Four-dimensional coordinates. +class FourD extends ThreeD { + int t; + FourD(int a, int b, int c, int d) { + super(a, b, c); + t = d; + } +} +// This class holds an array of coordinate objects. +class Coords<T extends TwoD> { + T[] coords; + Coords(T[] o) { coords = o; } +} + +// Demonstrate a bounded wildcard. +class BoundedWildcard { + + static void showXY(Coords<? extends TwoD> c) { + System.out.println("X Y Coordinates:"); + for(int i=0; i < c.coords.length; i++) { + System.out.println(c.coords[i].x + " " + c.coords[i].y); + } + System.out.println(); + } + + static void showXYZ(Coords<? extends ThreeD> c) { + System.out.println("X Y Z Coordinates:"); + for(int i=0; i < c.coords.length; i++) + System.out.println(c.coords[i].x + " " + + c.coords[i].y + " " + + c.coords[i].z); + System.out.println(); + } + + static void showAll(Coords<? extends FourD> c) { + System.out.println("X Y Z T Coordinates:"); + for(int i=0; i < c.coords.length; i++) + System.out.println(c.coords[i].x + " " + + c.coords[i].y + " " + + c.coords[i].z + " " + + c.coords[i].t); + System.out.println(); + } + + public static void main(String args[]) { + TwoD td[] = { + new TwoD(0, 0), + new TwoD(7, 9), + new TwoD(18, 4), + new TwoD(-1, -23) + }; + Coords<TwoD> tdlocs = new Coords<TwoD>(td); + System.out.println("Contents of tdlocs."); + showXY(tdlocs); // OK, is a TwoD + showXYZ<error descr="'showXYZ(Coords<? extends ThreeD>)' in 'BoundedWildcard' cannot be applied to '(Coords<TwoD>)'">(tdlocs)</error>; + showAll<error descr="'showAll(Coords<? extends FourD>)' in 'BoundedWildcard' cannot be applied to '(Coords<TwoD>)'">(tdlocs)</error>; + // Now, create some FourD objects. + FourD fd[] = { + new FourD(1, 2, 3, 4), + new FourD(6, 8, 14, 8), + new FourD(22, 9, 4, 9), + new FourD(3, -2, -23, 17) + }; + Coords<FourD> fdlocs = new Coords<FourD>(fd); + System.out.println("Contents of fdlocs."); + // These are all OK. + showXY(fdlocs); + showXYZ(fdlocs); + showAll(fdlocs); + } +} +//end of IDEADEV-5816 + +interface I33 {} +public class Q<T extends I33> { + T t; + <V extends I33> List<V> foo(Q<V> v) { + v.hashCode(); + return null; + } + + List<? extends I33> g (Q<?> q) { + return foo(q); + } +} + +//IDEADEV-16628 +class CollectionHelper { + public static <A> Collection<A> convertDown(Collection<? super A> collection) { + return collection == null ? null : null; + } + public static <A> Collection<A> convertUp(Collection<? extends A> collection) { + return collection == null ? null : null; + } + + public static void main(String[] args) { + // Downcast examples + final Collection<Number> numbers1 = new ArrayList<Number>(1); + Collection<Integer> integers1 = CollectionHelper.convertDown(numbers1); + integers1.hashCode(); + // Upcast example + final Collection<Integer> integers4 = new ArrayList<Integer>(1); + final Collection<Number> numbers4 = CollectionHelper.<Number>convertUp(integers4); + numbers4.hashCode(); + } +} + +//IDEA-62529 +class My<T> { + private Class<? super T> getSuperclass(){ + return null; + } + + public void test() { + if (getSuperclass() == List.class); + } +} + +class IDEA75178 { + void test(Set<String> labels) { + final Matcher<? super Object> empty = isEmpty(); + assertThat(labels, empty); + assertAlsoThat(empty, labels); + } + + public static <T> void assertThat(T actual, Matcher<T> matcher) { throw new AssertionError(actual.toString() + matcher.toString());} + public static <T> void assertAlsoThat(Matcher<T> matcher, T actual) { throw new AssertionError(actual.toString() + matcher.toString());} + + public static <T> Matcher<? super T> isEmpty() { + return null; + } + + static class Matcher<<warning descr="Type parameter 'T' is never used">T</warning>>{} + + class Foo {} + void testComment() { + Set<Foo> foos = Collections.emptySet(); + assertThatComment(foos, hasSize(0)); + } + + <E> Matcher<? super Collection<? extends E>> hasSize(int size) {return size == 0 ? null : null;} + <T> void assertThatComment(T actual, Matcher<? super T> matcher){ throw new AssertionError(actual.toString() + matcher.toString());} +} + +class IDEA66750 { + public void test() { + List<List<String>> data = new ArrayList<List<String>>(); + List<List<?>> y = <error descr="Inconvertible types; cannot cast 'java.util.List<java.util.List<java.lang.String>>' to 'java.util.List<java.util.List<?>>'">(List<List<?>>)data</error>; + System.out.println(y); + + ArrayList<Number> al = <error descr="Inconvertible types; cannot cast 'java.util.ArrayList<java.lang.Integer>' to 'java.util.ArrayList<java.lang.Number>'">(ArrayList<Number>) new ArrayList<Integer>(1)</error>; + System.out.println(al); + } +} + +class IDEA73377 { + public Iterator<Map.Entry<Map.Entry<?, ?>, ?>> iterator(Map<?, ?> map) { + //noinspection unchecked + return <error descr="Inconvertible types; cannot cast 'java.util.Iterator<java.util.Map.Entry<capture<?>,capture<?>>>' to 'java.util.Iterator<java.util.Map.Entry<java.util.Map.Entry<?,?>,?>>'">(Iterator<Map.Entry<Map.Entry<?, ?>, ?>>)map.entrySet().iterator()</error>; + } +} + +class IDEA91481 { + void bar(){ + BeanBuilder<? extends DirectBean> builder = <warning descr="Unchecked cast: 'IDEA91481.BeanBuilder<capture<? extends IDEA91481.Bean>>' to 'IDEA91481.BeanBuilder<? extends IDEA91481.DirectBean>'">(BeanBuilder<? extends DirectBean>) builder()</warning>; + System.out.println(builder); + } + + BeanBuilder<? extends Bean> builder() { + return null; + } + + class BeanBuilder<<warning descr="Type parameter 'T' is never used">T</warning>> {} + class Bean {} + class DirectBean extends Bean {} +} + +class IDEA89640 { + interface X {} + class Y<<warning descr="Type parameter 'T' is never used">T</warning> extends X> {} + + public static void main(String[] args) { + Y<? extends X> a = null; + Y<? extends X> b = null; + boolean flag = a != b; + System.out.println(flag); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardsBoundsIntersection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardsBoundsIntersection.java new file mode 100644 index 000000000000..3fc74e586d26 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardsBoundsIntersection.java @@ -0,0 +1,15 @@ +class NodeProperty<A, B> {} + +class NodeType {} +class NumberExpression extends NodeType {} +class Node<NodeTypeT extends NodeType> { + public <ValueT> ValueT get(NodeProperty<? super NodeTypeT, ValueT> prop) { + return null; + } +} + +class Main { + public static void main(NodeProperty<NumberExpression, Integer> nval, Node<? extends NodeType> expr) { + int val = expr.get<error descr="'get(NodeProperty<? super capture<? extends NodeType>,ValueT>)' in 'Node' cannot be applied to '(NodeProperty<NumberExpression,java.lang.Integer>)'">(nval)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardsOnRawTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardsOnRawTypes.java new file mode 100644 index 000000000000..ed1aa05e4925 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/WildcardsOnRawTypes.java @@ -0,0 +1,15 @@ +import java.util.List; + +public class Main<T> { + Object get(List<DiagramNode<T>> nodes, A a) { + return null; + } +} +class DiagramNode<T> {} + +class A { + static void f(Main m, List<DiagramNode<?>> nodes){ + final Object data = m.get(nodes, new A()); + final <error descr="Incompatible types. Found: 'java.util.List<DiagramNode<?>>', required: 'java.util.List<DiagramNode>'">List<DiagramNode> n = nodes;</error> + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/exceptions/LambdaParamExceptionVariable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/exceptions/LambdaParamExceptionVariable.java index 80d78a4e8deb..ad628642462d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/exceptions/LambdaParamExceptionVariable.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/exceptions/LambdaParamExceptionVariable.java @@ -5,7 +5,7 @@ class Test { <K extends Throwable> void foo(F<K> f) throws K { } { - foo(<error descr="Cyclic inference">(t)->{}</error>); + <error descr="Unhandled exception: java.lang.Throwable">foo((t)->{});</error> <error descr="Unhandled exception: java.lang.ClassNotFoundException">foo((ClassNotFoundException t)->{});</error> } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/DefaultConstructorAsArgument.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/DefaultConstructorAsArgument.java new file mode 100644 index 000000000000..98462674376d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/DefaultConstructorAsArgument.java @@ -0,0 +1,21 @@ +class Main2 { + + <R> void bar(Fun<Integer, R> collector) { } + + <T, D> Fun<T, Integer> foo(D d) { return null; } + + public void test() { + bar(new Foo<>()); + } + + interface Fun<T, R> { + R _(T t); + } + + class Foo<K> implements Fun<K, Integer> { + @Override + public Integer _(K k) { + return null; + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution.java index 43c4ba966b7b..57f194dcab48 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution.java @@ -1,6 +1,6 @@ public interface IDEA99969 { default IntStream distinct(Stream s) { - return s.map(i -> (int) i); + return s.map<error descr="Ambiguous method call: both 'Stream.map(Function)' and 'Stream.map(IntFunction)' match">(i -> <error descr="Inconvertible types; cannot cast '<lambda parameter>' to 'int'">(int) i</error>)</error>; } } interface Stream<T> { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution2.java index c89c855e10c9..a178b4d970d8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution2.java @@ -8,19 +8,19 @@ public class Test<A, B extends Number> { } - private void foo(IO<? extends A> <warning descr="Parameter 'p' is never used">p</warning>) {} + private void <warning descr="Private method 'foo(Test.IO<? extends A>)' is never used">foo</warning>(IO<? extends A> <warning descr="Parameter 'p' is never used">p</warning>) {} private void <warning descr="Private method 'foo(Test.IN<? extends B>)' is never used">foo</warning>(IN<? extends B> <warning descr="Parameter 'p' is never used">p</warning>) {} private static class Inner<A extends Object, B extends Number> { private void <warning descr="Private method 'm8(Test.IO<? extends A>)' is never used">m8</warning>(IO<? extends A> <warning descr="Parameter 'p' is never used">p</warning>) {} - private void m8(IN<? extends B> <warning descr="Parameter 'p' is never used">p</warning>) {} + private void <warning descr="Private method 'm8(Test.IN<? extends B>)' is never used">m8</warning>(IN<? extends B> <warning descr="Parameter 'p' is never used">p</warning>) {} } public static void main(String[] args) { Inner<Number, Double> inn = new Inner<>(); - inn.m8(p -> 1.0); - new Test<Number, Integer>().foo(p -> 1.0); + inn.m8<error descr="Ambiguous method call: both 'Inner.m8(IO<? extends Number>)' and 'Inner.m8(IN<? extends Double>)' match">(p -> 1.0)</error>; + new Test<Number, Integer>().foo<error descr="Ambiguous method call: both 'Test.foo(IO<? extends Number>)' and 'Test.foo(IN<? extends Integer>)' match">(p -> 1.0)</error>; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java index 435e10da0634..6f7e6d061350 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution3.java @@ -8,8 +8,8 @@ class Test { IntStream mi = sp.map(Inner::foo); Stream<Integer> mI = sp.map(Inner::fooBoxed); - IntStream li = sp.map(inner->inner.foo()); - Stream<Integer> lI = sp.map(inner -> inner.fooBoxed()); + IntStream li = sp.map<error descr="Ambiguous method call: both 'Stream.map(Function<? super Inner,?>)' and 'Stream.map(IntFunction<? super Inner>)' match">(inner->inner.<error descr="Cannot resolve method 'foo()'">foo</error>())</error>; + Stream<Integer> lI = sp.map<error descr="Ambiguous method call: both 'Stream.map(Function<? super Inner,? extends Integer>)' and 'Stream.map(IntFunction<? super Inner>)' match">(inner -> inner.<error descr="Cannot resolve method 'fooBoxed()'">fooBoxed</error>())</error>; } interface Stream<T> { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java index c0908783911c..738dd6602d38 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguitySpecificReturn.java @@ -1,15 +1,15 @@ class IntStream { private void foo(IntStream s) { - s.map(i -> 1 << i); - s.map(i -> 1); - s.map(i -> i); + s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">(i -> <error descr="Operator '<<' cannot be applied to 'int', '<lambda parameter>'">1 << i</error>)</error>; + s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">(i -> 1)</error>; + s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">(i -> i)</error>; } public static void main(String[] args) { new IntStream().foo(null); } - private IntStream map(IntUnaryOperator mapper) { + private IntStream <warning descr="Private method 'map(IntUnaryOperator)' is never used">map</warning>(IntUnaryOperator mapper) { System.out.println(mapper); return null; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/InferenceFromArgs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/InferenceFromArgs.java index 2febfc550382..2c5ca5ea18da 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/InferenceFromArgs.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/InferenceFromArgs.java @@ -15,13 +15,13 @@ class InferenceFromArgs { private static <E> void bazz(I<? super E, Integer> i) { } void foo(B<Integer> b) { - bar(null, <error descr="Cyclic inference">(k, v) -> v</error>); + bar(null, (k, v) -> v); bar(null, null); bar(b, (k, v) -> {return v;}); bar(b, (k, v) -> {<error descr="Incompatible types. Found: 'java.lang.Integer', required: 'java.lang.String'">String i = k;</error> return v;}); bar(b, (k, v) -> {Integer i = k; return v;}); - bazz(<error descr="Cyclic inference">(k, v) -> v</error>); + bazz((k, v) -> v); bazz((k, v) -> {<error descr="Incompatible types. Found: 'java.lang.Object', required: 'int'">int i = k;</error> return v;}); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/LambdaRawOrNot.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/LambdaRawOrNot.java index 4b9b085ce780..774c55574a9e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/LambdaRawOrNot.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/LambdaRawOrNot.java @@ -12,7 +12,7 @@ class Test1 { class Test2 { protected <T, U> U exerciseOps(TestData<T> data, TerminalOp<T, U> terminal, IntermediateOp... ops) { - return exerciseOps(data, <error descr="Cyclic inference">(u, v) -> u.equals(v)</error>, terminal); + <error descr="Incompatible types. Found: 'java.lang.Object', required: 'U'">return exerciseOps(data, (u, v) -> u.equals(v), terminal);</error> } } @@ -23,15 +23,15 @@ class Test3 { static <T> void bar(I<T> i, List<T> l){ bar(x -> {}, l); - bar(<error descr="Cyclic inference">x -> {}</error>, null); + bar(x -> {}, null); bar((I<T>)x -> {}, null); bar((T x) -> {}, null); bar(x -> {}, new ArrayList<T>()); - bar(<error descr="Cyclic inference">x -> {}</error>, new ArrayList()); + bar(x -> {}, new ArrayList()); } static { - bar(<error descr="Cyclic inference">x->{}</error>, new ArrayList()); + bar(x->{}, new ArrayList()); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/NoInferenceResult.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/NoInferenceResult.java index 7af6276e5d31..53e96c39b125 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/NoInferenceResult.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/NoInferenceResult.java @@ -21,7 +21,7 @@ class NoInferenceResult { m((String s1) -> s1.length()); m((String s1) -> s1); - m1(<error descr="Cyclic inference">() -> { }</error>); + m1<error descr="'m1(T)' in 'NoInferenceResult' cannot be applied to '(<lambda expression>)'">(() -> { })</error>; Foo<String> foo = new Foo<String>(); foo.map(v -> null); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java index 4ca8cb3995be..a922039b3933 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility.java @@ -25,7 +25,7 @@ class ReturnTypeIncompatibility { } public static void main(String[] args) { - call(i-> {return i;}); + call<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<Integer>)' and 'ReturnTypeIncompatibility.call(I2<String>)' match">(i-> {return i;})</error>; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java index d34d61ffad42..8daa44f040a7 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnTypeCompatibility1.java @@ -21,9 +21,9 @@ class Test { } void foo(Foo<String> as, final Foo<Character> ac) { - boolean b1 = as.forAll(s -> ac.forAll(c -> false)); - String s1 = as.forAll(s -> ac.forAll(c -> "")); - <error descr="Incompatible types. Found: 'java.lang.String', required: 'boolean'">boolean b2 = as.forAll(s -> ac.forAll(c -> ""));</error> + boolean b1 = as.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<String,Boolean>)' and 'Foo.forAll(II<String,String>)' match">(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> false)</error>)</error>; + String s1 = as.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<String,Boolean>)' and 'Foo.forAll(II<String,String>)' match">(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> "")</error>)</error>; + boolean b2 = as.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<String,Boolean>)' and 'Foo.forAll(II<String,String>)' match">(s -> ac.forAll<error descr="Ambiguous method call: both 'Foo.forAll(I<Character,Boolean>)' and 'Foo.forAll(II<Character,String>)' match">(c -> "")</error>)</error>; String s2 = as.forAll2(s -> ac.forAll2(<error descr="Incompatible return type boolean in lambda expression">c -> false</error>)); boolean b3 = as.forAll((I<String, Boolean>)s -> ac.forAll((I<Character, Boolean>)<error descr="Incompatible return type String in lambda expression">c -> ""</error>)); String s3 = as.forAll((II<String, String>)s -> ac.forAll((II<Character, String>)<error descr="Incompatible return type boolean in lambda expression">c -> false</error>)); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/TypeArgsConsistencyMisc1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/TypeArgsConsistencyMisc1.java index 613bbebced77..be5128f67884 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/TypeArgsConsistencyMisc1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/TypeArgsConsistencyMisc1.java @@ -64,8 +64,8 @@ class Test2 { static <T> void bar3(I<T> i, T t){} { - bar(<error descr="Cyclic inference">x -> x</error>); - bar1(<error descr="Cyclic inference">x -> x</error>); + bar(x -> x); + bar1(x -> x); bar2(1, <error descr="Incompatible return type List<Integer> in lambda expression">x -> x</error>); bar2("", <error descr="Incompatible return type List<String> in lambda expression">x -> x</error>); bar3(<error descr="Incompatible return type List<String> in lambda expression">x -> x</error>, ""); @@ -84,8 +84,8 @@ class Test3 { static <T> void bar3(I<T> i, T t){} { - bar(<error descr="Cyclic inference">x -> x</error>); - bar1(<error descr="Cyclic inference">x -> x</error>); + bar(x -> x); + bar1(x -> x); bar2(1, x -> x); bar2("", x -> x); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/WildcardsAndFormalLambdaParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/WildcardsAndFormalLambdaParams.java new file mode 100644 index 000000000000..3dda1b4857cc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/WildcardsAndFormalLambdaParams.java @@ -0,0 +1,11 @@ +public class Test { + interface Predicate<T> { + boolean test(T t); + } + + { + Predicate<? super Integer> p = (Number n) -> n.equals(23); + Predicate<Integer> p1 = (<error descr="Incompatible parameter types in lambda expression">Number n</error>) -> n.equals(23); + Predicate<Number> p2 = (Number n) -> n.equals(23); + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/inference/SimpleCyclicInference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/inference/SimpleCyclicInference.java index d344665c631b..400c4696b9ca 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/inference/SimpleCyclicInference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/inference/SimpleCyclicInference.java @@ -8,13 +8,13 @@ class NoLambda { void bazz() { bar(null); - bar(<error descr="Cyclic inference">(z)-> {System.out.println();}</error>); + bar((z)-> {System.out.println();}); } static <T> T id(T i2) {return i2;} { - id(<error descr="Cyclic inference">() -> {System.out.println("hi");}</error>); + id<error descr="'id(T)' in 'NoLambda' cannot be applied to '(<lambda expression>)'">(() -> {System.out.println("hi");})</error>; NoLambda.<Runnable>id(() -> {System.out.println("hi");}); } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/FormalParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/FormalParams.java index 8ecb69a21e89..5fffb8951185 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/FormalParams.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/FormalParams.java @@ -30,8 +30,8 @@ class ReturnTypeCompatibility { public static void main(String[] args) { call((String i)->{ return i;}); - call(<error descr="Cyclic inference">i->{ return i;}</error>); - call(<error descr="Cyclic inference">i->""</error>); - call<error descr="'call(ReturnTypeCompatibility.I1<java.lang.Integer>)' in 'ReturnTypeCompatibility' cannot be applied to '(<lambda expression>)'">((int i)->{ return i;})</error>; + call(i->{ return i;}); + call(i->""); + call((<error descr="Incompatible parameter types in lambda expression">int i</error>)->{ return i;}); } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java index b39fca9cb111..a5358d3feb4e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java @@ -9,6 +9,6 @@ class Test2 { static <T> I<T> bar(I<T> i){return i;} { - bar((List<String> list) -> null); + bar(list -> null); } } diff --git a/java/java-tests/testData/codeInsight/parameterInfo/AnnotationWithGenerics.java b/java/java-tests/testData/codeInsight/parameterInfo/AnnotationWithGenerics.java new file mode 100644 index 000000000000..7dcc9bca500e --- /dev/null +++ b/java/java-tests/testData/codeInsight/parameterInfo/AnnotationWithGenerics.java @@ -0,0 +1,10 @@ +import java.util.List; + +@interface PrepareForTest { + Class<List<String[]>> value(); +} + +abstract class A implements List<String>{} + +@PrepareForTest({A<caret>.class}) +class Main {} diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java index c39c02232f00..a5c27dd21749 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java @@ -6,14 +6,22 @@ import java.lang.AssertionError; import java.lang.IllegalArgumentException; public class AssertIsNotNull { - void bar(String s) { + void bar(String s, String s1) { if (<warning descr="Condition 's == null && trimIfNotNull(s) != null' is always 'false'">s == null && <warning descr="Condition 'trimIfNotNull(s) != null' is always 'false' when reached">trimIfNotNull(s) != null</warning></warning>) { throw new AssertionError(); } final Object o = call(); assertIsNotNull(o); + System.out.println(o.toString()); if(<warning descr="Condition 'o == null' is always 'false'">o == null</warning>) {} + + if (trimIfNotNull(s1) != null) { + System.out.println(s1.charAt(0)); + if (<warning descr="Condition 's1 == null' is always 'false'">s1 == null</warning>) { + + } + } } @Contract("null -> fail") diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractPreservesUnknownNullability.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractPreservesUnknownNullability.java new file mode 100644 index 000000000000..d829f23d6e4c --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractPreservesUnknownNullability.java @@ -0,0 +1,27 @@ +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class Foo { + + @Contract("null->null") + String foo(String s){ + return s; + } + + void bar(String s, String s2) { + foo(s); + s.hashCode(); + goo(foo(s2)); + } + + void bar2(String s, String s2) { + foo(s); + if (equals(s2)) { + s.hashCode(); + } + } + + + void goo(@NotNull String s) {} + +}
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FinalGetter.java b/java/java-tests/testData/inspection/dataFlow/fixture/FinalGetter.java new file mode 100644 index 000000000000..839452a32bd7 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FinalGetter.java @@ -0,0 +1,14 @@ +class Some { + final boolean getFoo() { return equals(2); } + void changeEverything() {} + + void bar() { + if (getFoo()) { + changeEverything(); + if (getFoo()) { + + } + } + } + +}
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ForeachOverWildcards.java b/java/java-tests/testData/inspection/dataFlow/fixture/ForeachOverWildcards.java new file mode 100644 index 000000000000..152c9eae2e30 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ForeachOverWildcards.java @@ -0,0 +1,12 @@ +import org.jetbrains.annotations.Nullable; + +class Some { + void bar2(@Nullable Iterable<? extends String> dirs) { + if (dirs != null) { + for (String dir : dirs) { + + } + } + } + +}
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/IsNullCheck.java b/java/java-tests/testData/inspection/dataFlow/fixture/IsNullCheck.java index 1b2c48593a16..f87e0de62022 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/IsNullCheck.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/IsNullCheck.java @@ -2,8 +2,9 @@ public class IsNullCheck { void bar() { final Value v = call(); if (Value.isNull(v)) { - if(<warning descr="Condition 'v == null' is always 'true'">v == null</warning>) {} + return; } + if(<warning descr="Condition 'v == null' is always 'false'">v == null</warning>) {} } Value call() {return new Value();} } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/LongDisjunctionsNotComplex.java b/java/java-tests/testData/inspection/dataFlow/fixture/LongDisjunctionsNotComplex.java new file mode 100644 index 000000000000..affd67c7742d --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/LongDisjunctionsNotComplex.java @@ -0,0 +1,47 @@ +class Some { + void getName(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10) { + if (i1 == 1 || + i1 == 2 || + i1 == 3 || + i1 == 4) { } + if (i2 == 1 || + i2 == 2 || + i2 == 3 || + i2 == 4) { } + if (i3 == 1 || + i3 == 2 || + i3 == 3 || + i3 == 4) { } + if (i4 == 1 || + i4 == 2 || + i4 == 3 || + i4 == 4) { } + if (i5 == 1 || + i5 == 2 || + i5 == 3 || + i5 == 4) { } + if (i6 == 1 || + i6 == 2 || + i6 == 3 || + i6 == 4) { } + if (i7 == 1 || + i7 == 2 || + i7 == 3 || + i7 == 4) { } + if (i8 == 1 || + i8 == 2 || + i8 == 3 || + i8 == 4) { } + if (i9 == 1 || + i9 == 2 || + i9 == 3 || + i9 == 4) { } + if (i10 == 1 || + i10 == 2 || + i10 == 3 || + i10 == 4) { } + } + +} + + diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ManySequentialIfsNotComplex.java b/java/java-tests/testData/inspection/dataFlow/fixture/ManySequentialIfsNotComplex.java new file mode 100644 index 000000000000..605636ba5e36 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ManySequentialIfsNotComplex.java @@ -0,0 +1,37 @@ +class Some { + void foo(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, Foo foo) { + if (i1 == 0) { + i3 = 2; + System.out.println(foo.getBar1().length()); + } + if (i2 == 0) System.out.println(foo.getBar2().length()); + if (i3 == 0) System.out.println(foo.getBar3().length()); + if (i4 == 0) System.out.println(foo.getBar4().length()); + if (i5 == 0) System.out.println(foo.getBar5().length()); + if (i6 == 0) System.out.println(foo.getBar6().length()); + if (i7 == 0) System.out.println(foo.getBar7().length()); + if (i8 == 0) System.out.println(foo.getBar8().length()); + if (i9 == 0) System.out.println(foo.getBar9().length()); + if (i10 == 0) System.out.println(foo.getBar10().length()); + if (i11 == 0) System.out.println(foo.getBar11().length()); + if (i12 == 0) System.out.println(foo.getBar12().length()); + if (i13 == 0) System.out.println(foo.getBar13().length()); + } + +} + +interface Foo { + String getBar1(); + String getBar2(); + String getBar3(); + String getBar4(); + String getBar5(); + String getBar6(); + String getBar7(); + String getBar8(); + String getBar9(); + String getBar10(); + String getBar11(); + String getBar12(); + String getBar13(); +} diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/WhileNotComplex.java b/java/java-tests/testData/inspection/dataFlow/fixture/WhileNotComplex.java new file mode 100644 index 000000000000..65d32c385ccf --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/WhileNotComplex.java @@ -0,0 +1,14 @@ +import java.io.File; + +class Some { + private File findRepository(File file) { + while (file != null) { + file = file.getParentFile(); + } + + return new File("foo"); + } + +} + + diff --git a/java/java-tests/testData/inspection/dataFlow/unboxingNPE/expected.xml b/java/java-tests/testData/inspection/dataFlow/unboxingNPE/expected.xml index caab45d3b56a..000168e3d991 100644 --- a/java/java-tests/testData/inspection/dataFlow/unboxingNPE/expected.xml +++ b/java/java-tests/testData/inspection/dataFlow/unboxingNPE/expected.xml @@ -384,10 +384,4 @@ <description>Condition <code>i</code> is always <code>true</code> when reached</description> </problem> - <problem> - <file>Test.java</file> - <line>62</line> - <module>testUnboxingNPE_7454908424878253728</module> - <description>Switch label<code>case 0:</code> is unreachable</description> - </problem> </problems> diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAll3.java b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAll3.java new file mode 100644 index 000000000000..6c73f8359479 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAll3.java @@ -0,0 +1,12 @@ +class C { + static enum E { + A + } + + void x(String s1, String s2) {} + + private void y() { + x(E.A.toString(), E.<caret>A.toString()); + + } +} diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAll3_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAll3_after.java new file mode 100644 index 000000000000..8d7703ca4d04 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAll3_after.java @@ -0,0 +1,12 @@ +class C { + static enum E { + A + } + + void x(String s1, String s2) {} + + private void y(E a) { + x(a.toString(), a.toString()); + + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java index 1ccef129a263..607b1b468aab 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ParameterInfoTest.java @@ -1,6 +1,7 @@ package com.intellij.codeInsight; import com.intellij.codeInsight.hint.ParameterInfoComponent; +import com.intellij.codeInsight.hint.api.impls.AnnotationParameterInfoHandler; import com.intellij.codeInsight.hint.api.impls.MethodParameterInfoHandler; import com.intellij.lang.parameterInfo.CreateParameterInfoContext; import com.intellij.lang.parameterInfo.ParameterInfoUIContextEx; @@ -74,4 +75,25 @@ public class ParameterInfoTest extends LightCodeInsightTestCase { MethodParameterInfoHandler .updateMethodPresentation(method, ((MethodCandidateInfo)itemsToShow[0]).getSubstitutor(), parameterContext)); } + + public void testAnnotationWithGenerics() throws Exception { + doTestAnnotationPresentation("<html>Class<List<String[]>> <b>value</b>()</html>"); + } + + private void doTestAnnotationPresentation(String expectedString) { + configureByFile(BASE_PATH + getTestName(false) + ".java"); + + final AnnotationParameterInfoHandler handler = new AnnotationParameterInfoHandler(); + final CreateParameterInfoContext context = new MockCreateParameterInfoContext(myEditor, myFile); + final PsiAnnotationParameterList list = handler.findElementForParameterInfo(context); + assertNotNull(list); + final Object[] itemsToShow = context.getItemsToShow(); + assertNotNull(itemsToShow); + assertTrue(itemsToShow.length == 1); + assertTrue(itemsToShow[0] instanceof PsiAnnotationMethod); + final PsiAnnotationMethod method = (PsiAnnotationMethod)itemsToShow[0]; + final ParameterInfoUIContextEx parameterContext = ParameterInfoComponent.createContext(itemsToShow, myEditor, handler); + Assert.assertEquals(expectedString, + AnnotationParameterInfoHandler.updateUIText(method, parameterContext)); + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy index dde4d0520bb7..e1250ef62019 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HippieCompletionTest.groovy @@ -27,11 +27,75 @@ class HippieCompletionTest extends LightCodeInsightFixtureTestCase { $some_long_variable_name = Obj::instance(); $some_lon<caret> ''' - myFixture.performEditorAction(IdeActions.ACTION_HIPPIE_COMPLETION) + complete() myFixture.checkResult ''' $some_long_variable_name = Obj::instance(); $some_long_variable_name<caret> ''' } + public void testFromAnotherFile() { + myFixture.configureByText "b.txt", ''' +$some_long_variable_name = Obj::instance(); +''' + myFixture.configureByText "a.txt", ''' +$some_lon<caret> +''' + + complete() + myFixture.checkResult ''' +$some_long_variable_name<caret> +''' + } + + public void "test no middle matching"() { + myFixture.configureByText "a.txt", ''' +fooExpression +exp<caret> +''' + complete() + myFixture.checkResult ''' +fooExpression +exp<caret> +''' + } + + public void "test words from javadoc"() { + myFixture.configureByText "a.java", ''' +/** some comment */ +com<caret> +''' + complete() + myFixture.checkResult ''' +/** some comment */ +comment<caret> +''' + } + + public void "test words from line comments"() { + myFixture.configureByText "a.java", ''' +// some comment2 +com<caret> +''' + complete() + myFixture.checkResult ''' +// some comment2 +comment2<caret> +''' + } + public void "test words from block comments"() { + myFixture.configureByText "a.java", ''' +/* some comment3 */ +com<caret> +''' + complete() + myFixture.checkResult ''' +/* some comment3 */ +comment3<caret> +''' + } + + private void complete() { + myFixture.performEditorAction(IdeActions.ACTION_HIPPIE_COMPLETION) + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 697e5349d9cd..aad87e838578 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -880,7 +880,9 @@ class Foo { void foo(int aaa, int aaaaa) { } void bar(int aaa, int aaaaa) { foo(<caret>) } } """) - type 'a,' + type 'a' + println myFixture.lookupElementStrings + type ',' assert myFixture.editor.document.text.contains('foo(aaa, )') } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 5380c7e83821..8e04d8728e73 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -994,6 +994,7 @@ public class ListUtils { public void testNewGenericClass() throws Throwable { doTest('\n') } public void testNewGenericInterface() throws Throwable { doTest() } public void testEnumPrivateFinal() throws Throwable { doTest() } + public void testNoFieldsInImplements() throws Throwable { doTest() } public void testSwitchConstantsFromReferencedClass() throws Throwable { doTest('\n') } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlighting8Test.java new file mode 100644 index 000000000000..2b87ecf12c45 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlighting8Test.java @@ -0,0 +1,775 @@ +/* + * 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.codeInsight.daemon; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; +import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection; +import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl; +import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { + @NonNls private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/genericsHighlighting8"; + + @NotNull + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new UncheckedWarningLocalInspection(), new UnusedSymbolLocalInspection(), new UnusedImportLocalInspection()}; + } + + @Override + protected Sdk getProjectJDK() { + return getTestName(false).contains("Jdk14") ? IdeaTestUtil.getMockJdk14() : super.getProjectJDK(); + } + + public void testReferenceTypeParams() { + doTest(); + } + public void testTypeParameterBoundsList() { + doTest(); + } + public void testClassInheritance() { + doTest(); + } + public void testTypeInference() { + doTest(); + } + public void testRaw() { + doTest(true); + } + public void testExceptions() { + doTest(); + } + public void testExplicitMethodParameters() { + doTest(); + } + public void testInferenceWithBounds() { + doTest(); + } + public void testInferenceWithSuperBounds() { + doTest(); + } + public void testInferenceWithUpperBoundPromotion() { + doTest(); + } + public void _testVariance() {//todo + doTest(); + } + public void testForeachTypes() { + doTest(); + } + public void testRawOverridingMethods() { + doTest(); + } + public void _testAutoboxing() { //todo + doTest(); + } + public void testAutoboxingMethods() { + doTest(); + } + public void testAutoboxingConstructors() { + doTest(); + } + public void testEnumWithAbstractMethods() { + doTest(); + } + public void _testEnum() { doTest(); } //todo + public void testEnum56239() { + doTest(); + } + public void testSameErasure() { + doTest(); + } + public void testMethods() { + doTest(); + } + public void testFields() { + doTest(); + } + public void testStaticImports() { + doTest(true); + } + public void testUncheckedCasts() { + doTest(true); + } + public void testUncheckedOverriding() { + doTest(true); + } + public void testWildcardTypes() { + doTest(true); + } + public void testConvertibleTypes() { + doTest(true); + } + public void testIntersectionTypes() { + doTest(true); + } + public void testVarargs() { + doTest(true); + } + public void testTypeArgsOnRaw() { + doTest(); + } + public void testConditionalExpression() { + doTest(); + } + public void testUnused() { + doTest(true); + } + public void testIDEADEV7337() { + doTest(true); + } + public void testIDEADEV10459() { + doTest(true); + } + public void testIDEADEV12951() { + doTest(true); + } + public void testIDEADEV13011() { + doTest(true); + } + public void testIDEADEV14006() { + doTest(true); + } + public void testIDEADEV14103() { + doTest(true); + } + public void testIDEADEV15534() { + doTest(true); + } + public void testIDEADEV23157() { + doTest(true); + } + public void testIDEADEV24166() { + doTest(true); + } + public void testIDEADEV57343() { + doTest(); + } + public void testSOE() { + doTest(true); + } + public void testGenericExtendException() { + doTest(); + } + public void testSameErasureDifferentReturnTypes() { + doTest(); + } + public void testDeepConflictingReturnTypes() { + doTest(); + } + public void testInheritFromTypeParameter() { + doTest(); + } + public void testAnnotationsAsPartOfModifierList() { + doTest(); + } + public void testImplementAnnotation() { + doTest(); + } + public void testOverrideAtLanguageLevel6() { + doTest(); + } + public void testSuperMethodCallWithErasure() { + doTest(); + } + public void testWildcardCastConversion() { + doTest(); + } + public void testTypeWithinItsWildcardBound() { + doTest(); + } + public void testMethodSignatureEquality() { + doTest(); + } + public void testInnerClassRef() { + doTest(); + } + public void testPrivateInnerClassRef() { + doTest(); + } + public void testWideningCastToTypeParam() { + doTest(); + } + public void testCapturedWildcardAssignments() { + doTest(); + } + public void testTypeParameterBoundVisibility() { + doTest(); + } + public void testUncheckedWarningsLevel6() { + doTest(true); + } + public void testIDEA77991() { + doTest(); + } + public void testIDEA80386() { + doTest(); + } + public void testIDEA66311() { + doTest(); + } + public void testIDEA67672() { + doTest(); + } + public void testIDEA88895() { + doTest(); + } + public void testIDEA67667() { + doTest(); + } + public void testIDEA66311_16() { + doTest(); + } + public void _testIDEA76283() {//todo bounds + doTest(); + } + public void testIDEA74899() { + doTest(); + } + public void testIDEA63291() { + doTest(); + } + public void testIDEA72912() { + doTest(); + } + public void testIllegalGenericTypeInInstanceof() { + doTest(); + } + public void testIDEA57339() { + doTest(); + } + public void testIDEA57340() { + doTest(); + } + public void testIDEA89771() { + doTest(); + } + public void testIDEA89801() { + doTest(); + } + public void testIDEA67681() { + doTest(); + } + public void testIDEA67599() { + doTest(); + } + public void testIDEA57668() { + doTest(); + } + public void testIDEA57667() { + doTest(); + } + public void testIDEA57650() { + doTest(); + } + public void testIDEA57378() { + doTest(); + } + public void testIDEA57557() { + doTest(); + } + public void testIDEA57563() { + doTest(); + } + public void testIDEA57275() { + doTest(); + } + public void testIDEA57533() { + doTest(); + } + public void testIDEA57509() { + doTest(); + } + public void testIDEA57410() { + doTest(); + } + public void testIDEA57411() { + doTest(); + } + public void testIDEA57484() { + doTest(); + } + public void _testIDEA57485() {//todo + doTest(); + } + public void testIDEA57486() { + doTest(); + } + public void testIDEA57492() { + doTest(); + } + public void testIDEA57493() { + doTest(); + } + public void testIDEA57495() { + doTest(); + } + public void testIDEA57494() { + doTest(); + } + public void testIDEA57496() { + doTest(); + } + public void testIDEA57264() { + doTest(); + } + public void testIDEA57315() { + doTest(); + } + public void testIDEA57346() { + doTest(); + } + public void testIDEA57284() { + doTest(); + } + public void testIDEA57286() { + doTest(); + } + public void testIDEA57307() { + doTest(true); + } + public void testIDEA57308() { + doTest(); + } + public void testIDEA57310() { + doTest(); + } + public void testIDEA57311() { + doTest(); + } + public void testIDEA57309() { + doTest(); + } + public void testIDEA90802() { + doTest(); + } + public void testIDEA70370() { + doTest(true); + } + public void testInaccessibleThroughWildcard() { + doTest(); + } + public void testInconvertibleTypes() { + doTest(); + } + public void testIncompatibleReturnType() { + doTest(); + } + public void testContinueInferenceAfterFirstRawResult() { + doTest(); + } + public void testDoNotAcceptLowerBoundIfRaw() { + doTest(); + } + public void testStaticOverride() { + doTest(); + } + public void testTypeArgumentsGivenOnRawType() { + doTest(); + } + public void testSelectFromTypeParameter() { + doTest(); + } + public void testTypeArgumentsGivenOnAnonymousClassCreation() { + doTest(); + } + + public void testIDEA94011() { + doTest(); + } + public void testDifferentTypeParamsInOverloadedMethods() { + doTest(true); + } + + public void testIDEA91626() { + doTest(true); + } + public void testIDEA92022() { + doTest(); + } + public void testRawOnParameterized() { + doTest(); + } + public void testFailedInferenceWithBoxing() { + doTest(); + } + public void testFixedFailedInferenceWithBoxing() { + doTest(); + } + public void testInferenceWithBoxingCovariant() { + doTest(); + } + public void testSuperWildcardIsNotWithinItsBound() { + doTest(); + } + public void testSpecificReturnType() { + doTest(); + } + public void testParameterizedParameterBound() { + doTest(); + } + public void testInstanceClassInStaticContextAccess() { + doTest(); + } + public void testFlattenIntersectionType() { + doTest(); + } + public void testIDEA97276() { + doTest(); + } + public void testWildcardsBoundsIntersection() { + doTest(); + } + public void testOverrideWithMoreSpecificReturn() { + doTest(); + } + public void testIDEA97888() { + doTest(); + } + public void testMethodCallParamsOnRawType() { + doTest(); + } + public void testIDEA98421() { + doTest(); + } + public void testErasureTypeParameterBound() { + doTest(); + } + public void testThisAsAccessObject() { + doTest(); + } + public void testIDEA67861() { + doTest(); + } + public void testIDEA67597() { + doTest(); + } + public void testIDEA57539() { + doTest(); + } + public void testIDEA67570() { + doTest(); + } + public void testIDEA99061() { + doTest(); + } + public void testIDEA99347() { + doTest(); + } + public void testIDEA86875() { + doTest(); + } + public void testIDEA103760(){ + doTest(); + } + public void testIDEA105846(){ + doTest(); + } + public void testIDEA105695(){ + doTest(); + } + public void testIDEA104992(){ + doTest(); + } + public void testIDEA57446(){ + doTest(); + } + public void testIDEA67677(){ + doTest(); + } + public void testIDEA67798(){ + doTest(); + } + public void testIDEA57534(){ + doTest(); + } + public void testIDEA57482(){ + doTest(); + } + public void testIDEA67577(){ + doTest(); + } + public void testIDEA57413(){ + doTest(); + } + public void testIDEA57265(){ + doTest(); + } + public void testIDEA57271(){ + doTest(); + } + public void testIDEA57272(){ + doTest(); + } + public void testIDEA57285(){ + doTest(); + } + public void testIDEA65066(){ + doTest(); + } + public void testIDEA67998(){ + doTest(); + } + public void testIDEA18425(){ + doTest(); + } + public void testIDEA27080(){ + doTest(); + } + public void testIDEA22079(){ + doTest(); + } + public void testIDEA21602(){ + doTest(); + } + public void testIDEA21602_7(){ + doTest(); + } + + public void testIDEA21597() throws Exception { + doTest(); + } + public void testIDEA20573() throws Exception { + doTest(); + } + public void testIDEA20244() throws Exception { + doTest(); + } + public void testIDEA22005() throws Exception { + doTest(); + } + public void testIDEA57259() throws Exception { + doTest(); + } + public void testIDEA107957() throws Exception { + doTest(); + } + public void testIDEA109875() throws Exception { + doTest(); + } + public void testIDEA106964() throws Exception { + doTest(); + } + public void testIDEA107782() throws Exception { + doTest(); + } + public void testInheritedWithDifferentArgsInTypeParams() throws Exception { + doTest(); + } + public void testIllegalForwardReferenceInTypeParameterDefinition() throws Exception { + doTest(); + } + + public void testIDEA57877() throws Exception { + doTest(); + } + public void testIDEA110568() throws Exception { + doTest(); + } + public void testSelfRef() throws Exception { + doTest(); + } + public void testTypeParamsCyclicInference() throws Exception { + doTest(); + } + public void testCaptureTopLevelWildcardsForConditionalExpression() throws Exception { + doTest(); + } + public void testGenericsOverrideMethodInRawInheritor() throws Exception { + doTest(); + } + + public void testIDEA107654() throws Exception { + doTest(); + } + + public void testIDEA55510() throws Exception { + doTest(); + } + + public void testIDEA27185(){ + doTest(); + } + public void testIDEA67571(){ + doTest(); + } + public void _testTypeArgumentsOnRawType(){//todo + doTest(); + } + + public void testTypeArgumentsOnRawType17(){ + doTest(); + } + + public void testWildcardsOnRawTypes() { + doTest(); + } + public void testDisableWithinBoundsCheckForSuperWildcards() { + doTest(); + } + + public void testIDEA108287() throws Exception { + doTest(); + } + + public void testIDEA77128() throws Exception { + doTest(); + } + + public void testDisableCastingToNestedWildcards() throws Exception { + doTest(); + } + + public void testBooleanInferenceFromIfCondition() throws Exception { + doTest(); + } + + public void testMethodCallOnRawTypesExtended() throws Exception { + doTest(); + } + + public void testIDEA104100() { + doTest(); + } + public void testIDEA104160() { + doTest(); + } + public void testSOEInLeastUpperClass() { + doTest(); + } + + public void testIDEA57334() { + doTest(); + } + + public void testIDEA57325() { + doTest(); + } + public void testIDEA67835() { + doTest(); + } + public void testIDEA67744() { + doTest(); + } + public void testIDEA67682() { + doTest(); + } + public void testIDEA57391() { + doTest(); + } + public void testIDEA110869() { + doTest(); + } + /*public void testIDEA110947() { doTest5(false); }*/ + public void testIDEA112122() { + doTest(); + } + public void testNoInferenceFromTypeCast() { + doTest(); + } + public void testCaptureWildcardsInTypeCasts() { + doTest(); + } + public void testIDEA111085() { + doTest(); + } + public void testIDEA109556() { + doTest(); + } + public void testIDEA107440() { + doTest(); + } + public void testIDEA57289() { + doTest(); + } + public void testIDEA57439() { + doTest(); + } + public void testIDEA57312() { + doTest(); + } + public void testIDEA67865() { + doTest(); + } + public void testBoxingSpecific() { + doTest(); + } + public void testIDEA67843() { //fixme need to change test + doTest(); + } + public void testAmbiguousTypeParamVsConcrete() { + doTest(); + } + public void testRawAssignments() throws Exception { + doTest(); + } + public void testIDEA87860() throws Exception { + doTest(); + } + + private void doTest() { + doTest(false); + } + + private void doTest(boolean warnings) { + LanguageLevelProjectExtension.getInstance(getJavaFacade().getProject()).setLanguageLevel(LanguageLevel.JDK_1_8); + IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), myTestRootDisposable); + final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper(); + helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager())); + try { + doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false); + } + finally { + helper.setTestHelper(null); + } + } + + + public void testIDEA67584() throws Exception { + doTest(); + } + public void testIDEA113225() throws Exception { + doTest(); + } + + public void _testJavaUtilCollections_NoVerify() throws Exception { //todo + PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule())); + assertNotNull(collectionsClass); + collectionsClass = (PsiClass)collectionsClass.getNavigationElement(); + final String text = collectionsClass.getContainingFile().getText(); + configureFromFileText("Collections.java", text.replaceAll("\r", "\n")); + final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper(); + helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager())); + try { + doTestConfiguredFile(false, false, null); + } + finally { + helper.setTestHelper(null); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java index be7ff01e0e24..99c7c27b9dbc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java @@ -26,6 +26,6 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase { } private void doTest() throws Exception { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java index 1e665ac000e2..182b9f2b068d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java @@ -42,6 +42,6 @@ public class ExceptionVariablesInferenceTest extends LightDaemonAnalyzerTestCase } private void doTest(final boolean checkWarnings) throws Exception { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 84e60d5aa03f..1071f19491b5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -79,12 +79,16 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testDefaultConstructorAsArgument() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } private void doTest(final boolean checkWarnings) throws Exception { IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); - doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java index cf99110228b8..f2e23bd2fe50 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Interface8MethodsHighlightingTest.java @@ -37,6 +37,6 @@ public class Interface8MethodsHighlightingTest extends LightDaemonAnalyzerTestCa } private void doTest(boolean checkWarnings, boolean checkInfos) { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, checkInfos); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, checkInfos); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java index 633beb0cc5d3..b6f6654e6ef5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java @@ -51,7 +51,7 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase { public void testAmbiguityRawGenerics() { doTest(); } public void testDefaultMethod() { doTest(); } public void testLambdaOnVarargsPlace() { doTest(); } - public void testLambdaRawOrNot() { doTest(); } + public void testLambdaRawOrNot() { doTest(); } //todo incorrect testdata public void testReturnTypeCompatibility1() { doTest(); } public void testNoInferenceResult() { doTest(); } public void testInferenceFromArgs() { doTest(); } @@ -92,12 +92,13 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase { public void testFunctionalInterfaceCheck() { doTest();} public void testUnderscores() { doTest(true);} public void testReturnTypeAmbiguity() { doTest();} + public void testWildcardsAndFormalLambdaParams() {doTest();} private void doTest() { doTest(false); } private void doTest(final boolean checkWarnings) { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java index 6584cdc17aa8..96e60587a225 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java @@ -30,6 +30,6 @@ public class LambdaInferenceTest extends LightDaemonAnalyzerTestCase { } private void doTest() throws Exception { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java index c27dc9c5af43..94ca90df2d02 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java @@ -30,6 +30,6 @@ public class LambdaParamsTest extends LightDaemonAnalyzerTestCase { public void testInferFromFormal() { doTest(); } private void doTest() { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java index 17d7bd13fcbb..36f98aa91cc6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java @@ -35,6 +35,6 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase { public void testIntersection() { doTest(); } public void testSer() { doTest(); } private void doTest() { - doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", true, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java index b0b87519e4cb..3559d65b8b81 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java @@ -95,6 +95,6 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { private void doTest(boolean warnings) { IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); - doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false); + doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/PsiPolyExpressionUtilTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/PsiPolyExpressionUtilTest.java index b892318943e0..cca3bd550c62 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/PsiPolyExpressionUtilTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/PsiPolyExpressionUtilTest.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.daemon.lambda; import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; @@ -79,4 +80,41 @@ public class PsiPolyExpressionUtilTest extends LightCodeInsightFixtureTestCase { assertNotNull(elementAtCaret); return PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); } + + public void testPertinentLambdaExpression() throws Exception { + assertTrue(doTestLambdaPertinent(" void bar(List<Runnable> l) {" + + " foo(() <caret>-> {}, l);" + + " }")); + } + + public void testPertinentImplicitLambdaExpression() throws Exception { + assertTrue(doTestLambdaPertinent(" void bar(List<Comparable<String>> l) {" + + " foo((String s) <caret>-> 1, l);" + + " }")); + } + + public void testPertinentNestedLambdaExpression() throws Exception { + assertTrue(doTestLambdaPertinent(" interface Fun<I, O> { O inOut(I i);}\n" + + " void bar(List<Fun<String, Fun<String, String>>> l) {" + + " foo((sIn, sOut) -> (sInInner, sOutInner) <caret>-> sOutInner, l);" + + " }")); + } + + private boolean doTestLambdaPertinent(final String barText) { + myFixture.configureByText("Foo.java", "import java.util.*;" + + "class Foo {" + + " <T> T foo(T t, List<T> lT) {" + + " }" + + barText + + "}"); + final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset()); + assertNotNull(elementAtCaret); + final PsiExpression psiExpression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); + assertInstanceOf(psiExpression, PsiLambdaExpression.class); + final PsiClass aClass = myFixture.findClass("Foo"); + assertNotNull(aClass); + final PsiMethod[] meths = aClass.findMethodsByName("foo", false); + assertTrue(meths.length == 1); + return InferenceSession.isPertinentToApplicability(psiExpression, meths[0]); + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java index fd9369adfb67..07be23a29906 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java @@ -31,7 +31,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.slicer.SliceAnalysisParams; import com.intellij.slicer.SliceHandler; -import com.intellij.slicer.SliceManager; import com.intellij.slicer.SliceUsage; import com.intellij.util.CommonProcessors; import com.intellij.util.containers.IntArrayList; @@ -59,7 +58,7 @@ public class SliceBackwardTest extends DaemonAnalyzerTestCase { params.scope = new AnalysisScope(getProject()); params.dataFlowToThis = true; - SliceUsage usage = SliceManager.createRootUsage(element, params); + SliceUsage usage = SliceUsage.createRootUsage(element, params); checkUsages(usage, true, myFlownOffsets); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java index 69c3547ad220..7b2d30770e99 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java @@ -23,7 +23,6 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.slicer.SliceAnalysisParams; import com.intellij.slicer.SliceForwardHandler; -import com.intellij.slicer.SliceManager; import com.intellij.slicer.SliceUsage; import com.intellij.util.containers.IntArrayList; import gnu.trove.TIntObjectHashMap; @@ -49,7 +48,7 @@ public class SliceForwardTest extends DaemonAnalyzerTestCase { SliceAnalysisParams params = new SliceAnalysisParams(); params.scope = new AnalysisScope(getProject()); params.dataFlowToThis = false; - SliceUsage usage = SliceManager.createRootUsage(element, params); + SliceUsage usage = SliceUsage.createRootUsage(element, params); SliceBackwardTest.checkUsages(usage, false, myFlownOffsets); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java index 624ec7fd314d..771cfe3004b6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java @@ -1,11 +1,9 @@ package com.intellij.codeInsight.slice; import com.intellij.analysis.AnalysisScope; -import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.impl.ToolWindowHeadlessManagerImpl; @@ -34,7 +32,7 @@ public class SliceTreeTest extends LightDaemonAnalyzerTestCase { params.scope = new AnalysisScope(getProject()); params.dataFlowToThis = true; - SliceUsage usage = SliceManager.createRootUsage(element, params); + SliceUsage usage = SliceUsage.createRootUsage(element, params); SlicePanel panel = new SlicePanel(getProject(), true, new SliceRootNode(getProject(), new DuplicateMap(), usage), false, ToolWindowHeadlessManagerImpl.HEADLESS_WINDOW) { @@ -252,7 +250,7 @@ public class SliceTreeTest extends LightDaemonAnalyzerTestCase { } private static void checkStructure(final SliceNode root, @NonNls String dataExpected) { - List<SliceNode> actualNodes = new ArrayList<SliceNode>((Collection<? extends SliceNode>)root.getChildren()); + List<SliceNode> actualNodes = new ArrayList<SliceNode>((Collection)root.getChildren()); Collections.sort(actualNodes, SliceTreeBuilder.SLICE_NODE_COMPARATOR); Object[] actualStrings = ContainerUtil.map2Array(actualNodes, new Function<SliceNode, Object>() { diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index b0df0fb12b85..cc9dee3d26aa 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -286,6 +286,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testContractAnnotation() { doTest(); } public void testContractInLoopNotTooComplex() { doTest(); } public void testContractWithNullable() { doTest(); } + public void testContractPreservesUnknownNullability() { doTest(); } public void testBoxingImpliesNotNull() { doTest(); } public void testLargeIntegersAreNotEqualWhenBoxed() { doTest(); } @@ -295,6 +296,12 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testAnonymousMethodIndependence() { doTest(); } public void testAnonymousFieldIndependence() { doTest(); } public void testNoConfusionWithAnonymousConstantInitializer() { doTest(); } + public void testForeachOverWildcards() { doTest(); } + public void testFinalGetter() { doTest(); } + + public void testManySequentialIfsNotComplex() { doTest(); } + public void testLongDisjunctionsNotComplex() { doTest(); } + public void testWhileNotComplex() { doTest(); } public void _testNullCheckBeforeInstanceof() { doTest(); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java index 480a910cc394..1bd64f4d0802 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java @@ -15,6 +15,9 @@ */ package com.intellij.codeInspection; +import com.intellij.codeInsight.completion.NormalCompletionTest; +import com.intellij.codeInsight.completion.SmartTypeCompletionTest; +import com.intellij.codeInsight.slice.SliceBackwardTest; import com.intellij.codeInsight.slice.SliceTreeTest; import junit.framework.Test; import junit.framework.TestSuite; @@ -25,6 +28,9 @@ public class DataFlowInspectionTestSuite { suite.addTestSuite(DataFlowInspectionTest.class); suite.addTestSuite(DataFlowInspectionAncientTest.class); suite.addTestSuite(SliceTreeTest.class); + suite.addTestSuite(SliceBackwardTest.class); + suite.addTestSuite(SmartTypeCompletionTest.class); + suite.addTestSuite(NormalCompletionTest.class); return suite; } } diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index e579fbb49ca4..49ff83510136 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -478,36 +478,36 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { private static void runFindForwardAndBackward(FindManager findManager, FindModel findModel, String text, String ext) { findModel.setForward(true); LightVirtualFile file = new LightVirtualFile("A."+ext, text); - int prevousOffset; + int previousOffset; FindResult findResult = findManager.findString(text, 0, findModel, file); assertTrue(findResult.isStringFound()); - prevousOffset = findResult.getStartOffset(); + previousOffset = findResult.getStartOffset(); findResult = findManager.findString(text, findResult.getEndOffset(), findModel, file); assertTrue(findResult.isStringFound()); - assertTrue(findResult.getStartOffset() > prevousOffset); - prevousOffset = findResult.getStartOffset(); + assertTrue(findResult.getStartOffset() > previousOffset); + previousOffset = findResult.getStartOffset(); findResult = findManager.findString(text, findResult.getEndOffset(), findModel, file); assertTrue(findResult.isStringFound()); - assertTrue(findResult.getStartOffset() > prevousOffset); + assertTrue(findResult.getStartOffset() > previousOffset); findModel.setForward(false); findResult = findManager.findString(text, text.length(), findModel, file); assertTrue(findResult.isStringFound()); - prevousOffset = findResult.getStartOffset(); + previousOffset = findResult.getStartOffset(); - findResult = findManager.findString(text, prevousOffset, findModel, file); + findResult = findManager.findString(text, previousOffset, findModel, file); assertTrue(findResult.isStringFound()); - assertTrue(prevousOffset > findResult.getStartOffset() ); + assertTrue(previousOffset > findResult.getStartOffset() ); - prevousOffset = findResult.getStartOffset(); + previousOffset = findResult.getStartOffset(); - findResult = findManager.findString(text, prevousOffset, findModel, file); + findResult = findManager.findString(text, previousOffset, findModel, file); assertTrue(findResult.isStringFound()); - assertTrue(prevousOffset > findResult.getStartOffset() ); + assertTrue(previousOffset > findResult.getStartOffset() ); } public void testFindInJavaDocs() throws Exception{ @@ -547,4 +547,35 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { runFindInCommentsAndLiterals(findManager, findModel, text, "cs"); } + + public void testFindInLiteralToSkipQuotes() throws Exception{ + FindManager findManager = FindManager.getInstance(myProject); + + FindModel findModel = new FindModel(); + findModel.setStringToFind("^done$"); + findModel.setWholeWordsOnly(false); + findModel.setRegularExpressions(true); + findModel.setFromCursor(false); + findModel.setGlobal(true); + findModel.setMultipleFiles(false); + findModel.setProjectScope(true); + + String text = "\"done\"; 'done'; 'done' \"done2\""; + + findModel.setInStringLiteralsOnly(true); + findModel.setInCommentsOnly(false); + runFindForwardAndBackward(findManager, findModel, text, "java"); + + text = "def n = \"\"\"done\"\"\"\n def n = /done/\n def n = \"done\"\n def n = \"done2\""; + + runFindForwardAndBackward(findManager, findModel, text, "groovy"); + + text = "\"\"; \"done\"; 'done'; 'done' \"done2\""; + + findModel.setStringToFind("done"); + findModel.setWholeWordsOnly(true); + findModel.setRegularExpressions(false); + + runFindForwardAndBackward(findManager, findModel, text, "java"); + } } diff --git a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java index 72e9c2acf396..80dda6dc2d5e 100644 --- a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java +++ b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java @@ -42,6 +42,6 @@ public class JavaFileStructureFilteringTest extends JavaFileStructureTestCase { public void testMatcher1() throws Exception {checkTree("ico");} public void testMatcher2() throws Exception {checkTree("ico");} - @Bombed(user = "peter", month = Calendar.SEPTEMBER, day = 20) + @Bombed(user = "peter", month = Calendar.DECEMBER, day = 20) public void testAnonymousMatcher2() throws Exception {checkTree("ico");} } diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerBlankLinesTest.groovy b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerBlankLinesTest.groovy index 0b4e838382de..b456d41aa300 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerBlankLinesTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerBlankLinesTest.groovy @@ -131,4 +131,16 @@ class Test { }''' doTest(initial: text, expected: text, rules: [rule(CLASS)] ) } + + void "test statements on the same line"() { + def before = '''\ + + + +public enum Sender {a, b; private String value; +} +''' + doTest(initial: before, expected: before) + } + } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java index 889e59160d98..2e2d0c5943e3 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBracesTest.java @@ -155,4 +155,14 @@ public class JavaFormatterBracesTest extends AbstractJavaFormatterTest { "}"; doTextTest(text, text); } + + public void testSimpleMethodsInOneLineEvenIfExceedsRightMargin() { + getSettings().KEEP_SIMPLE_METHODS_IN_ONE_LINE = true; + getSettings().getRootSettings().RIGHT_MARGIN = 90; + String text = "public class Repr2 {\n" + + " public void start() { System.out.println(\"kfjsdkfjsdkfjskdjfslkdjfklsdjfklsdjfksjdfkljsdkfjsd!\"); }\n" + + "}"; + doTextTest(text, text); + } + } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java index be335471d355..b34720759c8a 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterIndentationTest.java @@ -536,4 +536,13 @@ public class JavaFormatterIndentationTest extends AbstractJavaFormatterTest { getIndentOptions().USE_TAB_CHARACTER = true; doTextTest(initial, expected); } + + public void testLambdaIndentation() throws Exception { + String before = "Runnable r = () ->\n" + + "{\n" + + " System.out.println(\"olo\");\n" + + "};"; + doMethodTest(before, before); + } + } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java index ab35904d3daa..e78f7183af49 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java @@ -33,6 +33,34 @@ public class JavaFormatterSpaceTest extends AbstractJavaFormatterTest { "class Foo {\n" + " Map<String, String> map() {\n" + " }\n" + "}"); } + public void testDoNotPlaceStatementsOnOneLineIfFirstEndsWithSingleLineComment() { + getSettings().KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE = true; + getSettings().KEEP_LINE_BREAKS = false; + String before = "public class Reproduce {\n" + + " public void start() {\n" + + " if (true)\n" + + " return; // comment\n" + + " final int count = 5;\n" + + " for (int i = 0; i < count; i++) {\n" + + " System.out.println(\"AAA!\");\n" + + " System.out.println(\"BBB!\"); // ololol\n" + + " System.out.println(\"asda\"); /* ololo */\n" + + " System.out.println(\"booo\");\n" + + " }\n" + + " }\n" + + "}"; + String after = "public class Reproduce {\n" + + " public void start() {\n" + + " if (true) return; // comment\n" + + " final int count = 5; for (int i = 0; i < count; i++) {\n" + + " System.out.println(\"AAA!\"); System.out.println(\"BBB!\"); // ololol\n" + + " System.out.println(\"asda\"); /* ololo */ System.out.println(\"booo\");\n" + + " }\n" + + " }\n" + + "}"; + doTextTest(before, after); + } + public void testSpaceBeforeAnnotationParamArray() { // Inspired by IDEA-24329 getSettings().SPACE_BEFORE_ANNOTATION_ARRAY_INITIALIZER_LBRACE = true; diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java index 695ac719529d..68dbf094a3da 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java @@ -2972,4 +2972,33 @@ public void testSCR260() throws Exception { " }\n" + "}"); } + + public void testCommaInMethodDeclParamsList() { + getSettings().SPACE_AFTER_COMMA = true; + String before = "public class Test {\n" + + " public static void act( int a , int b , int c , int d) {\n" + + " act(1,2,3,4);\n" + + " }\n" + + "}\n"; + String after = "public class Test {\n" + + " public static void act(int a, int b, int c, int d) {\n" + + " act(1, 2, 3, 4);\n" + + " }\n" + + "}\n"; + doTextTest(before, after); + getSettings().SPACE_AFTER_COMMA = false; + before = "public class Test {\n" + + " public static void act( int a , int b , int c , int d) {\n" + + " act(1 , 2 , 3 , 4);\n" + + " }\n" + + "}\n"; + after = "public class Test {\n" + + " public static void act(int a,int b,int c,int d) {\n" + + " act(1,2,3,4);\n" + + " }\n" + + "}\n"; + doTextTest(before, after); + } + + } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/EncapsulateFieldsTest.java b/java/java-tests/testSrc/com/intellij/refactoring/EncapsulateFieldsTest.java index fd536cbd609c..dd3af4b420d0 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/EncapsulateFieldsTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/EncapsulateFieldsTest.java @@ -43,11 +43,11 @@ public class EncapsulateFieldsTest extends MultiFileTestCase{ } public void testDiffWithReturnTypeOnly() throws Exception { - doTest("i", "There already is a method <b><code>Test setI(int)</code></b> which differs from setter <b><code>setI</code></b> by return type only."); + doTest("i", "There is already method <b><code>Test setI(int)</code></b> which differs from setter <b><code>setI</code></b> by return type only"); } public void testDiffWithReturnTypeOnlyInHierarchy() throws Exception { - doTest("i", "There already is a method <b><code>Super setI(int)</code></b> which differs from setter <b><code>setI</code></b> by return type only."); + doTest("i", "There is already method <b><code>Super setI(int)</code></b> which differs from setter <b><code>setI</code></b> by return type only"); } public void testHideOverriderMethod() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java index b5ec296e7bc5..5be5dad1c1a1 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java @@ -59,6 +59,15 @@ public class InplaceIntroduceParameterTest extends AbstractJavaInplaceIntroduceT }); } + public void testReplaceAll3() throws Exception { + doTest(new Pass<AbstractInplaceIntroducer>() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + inplaceIntroduceFieldPopup.setReplaceAllOccurrences(true); + } + }); + } + public void testReplaceAllMethodCalls() throws Exception { doTest(new Pass<AbstractInplaceIntroducer>() { @Override diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java index 5fff2193ee83..618381a194b6 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java @@ -1,4 +1,20 @@ /* + * 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. + */ + +/* * Created by IntelliJ IDEA. * User: dsl * Date: 07.05.2002 @@ -114,7 +130,7 @@ public class IntroduceParameterTest extends LightRefactoringTestCase { } public void testSuperInExpression() throws Exception { - doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false, "Parameter initializer contains <b><code>super</code></b>, but not all calls to method are in its class."); + doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false, "Parameter initializer contains <b><code>super</code></b>, but not all calls to method are in its class"); } public void testNull() throws Exception { @@ -150,7 +166,7 @@ public class IntroduceParameterTest extends LightRefactoringTestCase { } public void testSuperWithSideEffect() throws Exception { - doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false, "Parameter initializer contains <b><code>super</code></b>, but not all calls to method are in its class."); + doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false, "Parameter initializer contains <b><code>super</code></b>, but not all calls to method are in its class"); } public void testConflictingField() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index a447fa117790..07f3a61f96ed 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -149,8 +149,8 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { protected boolean reportConflicts(MultiMap<PsiElement,String> conflicts, final Project project, IntroduceVariableSettings dialog) { assertEquals(2, conflicts.size()); Collection<? extends String> conflictsMessages = conflicts.values(); - assertTrue(conflictsMessages.contains("Introducing variable may break code logic.")); - assertTrue(conflictsMessages.contains("Local variable <b><code>c</code></b> is modified in loop body.")); + assertTrue(conflictsMessages.contains("Introducing variable may break code logic")); + assertTrue(conflictsMessages.contains("Local variable <b><code>c</code></b> is modified in loop body")); return false; } }); @@ -242,7 +242,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { } catch (Exception e) { assertEquals(e.getMessage(), "Error message:Cannot perform refactoring.\n" + - "Selected block should represent an expression."); + "Selected block should represent an expression"); return; } fail("Should not be able to perform refactoring"); @@ -254,7 +254,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { } catch (Exception e) { assertEquals(e.getMessage(), "Error message:Cannot perform refactoring.\n" + - "Selected block should represent an expression."); + "Selected block should represent an expression"); return; } fail("Should not be able to perform refactoring"); @@ -366,7 +366,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { } catch (Exception e) { assertEquals(e.getMessage(), "Error message:Cannot perform refactoring.\n" + - "Selected block should represent an expression."); + "Selected block should represent an expression"); return; } fail("Should not be able to perform refactoring"); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/MoveClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/MoveClassTest.java index bcaabef58603..c646301c664c 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/MoveClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/MoveClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -78,7 +78,7 @@ public class MoveClassTest extends RefactoringTestCase { fail("Conflicts expected"); } catch (BaseRefactoringProcessor.ConflictsInTestsException e) { - assertEquals("A package-local class <b><code>Class2</code></b> will no longer be accessible from field <b><code>User.class2</code></b>", e.getMessage()); + assertEquals("Package-local class <b><code>Class2</code></b> will no longer be accessible from field <b><code>User.class2</code></b>", e.getMessage()); } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java index 2caa921ab3fc..9bc767a40ccb 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java @@ -1,3 +1,18 @@ +/* + * 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.refactoring; import com.intellij.JavaTestUtil; @@ -172,7 +187,7 @@ public class RenameCollisionsTest extends LightRefactoringTestCase { doTest("foo1"); } catch (BaseRefactoringProcessor.ConflictsInTestsException e) { - Assert.assertEquals("Method with same erasure is already defined in the class <b><code>RenameTest</code></b>.", e.getMessage()); + Assert.assertEquals("Method with same erasure is already defined in the class <b><code>RenameTest</code></b>", e.getMessage()); return; } fail("Conflicts were not found"); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameMembersInplaceTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameMembersInplaceTest.java index f72add53a204..f77166535cef 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameMembersInplaceTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameMembersInplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * 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. @@ -81,7 +81,7 @@ public class RenameMembersInplaceTest extends LightCodeInsightTestCase { doTestInplaceRename("bar"); } catch (BaseRefactoringProcessor.ConflictsInTestsException e) { - assertEquals("Method bar() is already defined in the class <b><code>Foo</code></b>.", e.getMessage()); + assertEquals("Method bar() is already defined in the class <b><code>Foo</code></b>", e.getMessage()); checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); return; } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java index f2b52e19e34c..6da0cdf162c0 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameMethodMultiTest.java @@ -1,5 +1,21 @@ +/* + * 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.refactoring; +import com.intellij.JavaTestUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JavaPsiFacade; @@ -7,7 +23,6 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.rename.RenameProcessor; -import com.intellij.JavaTestUtil; import org.junit.Assert; /** @@ -51,7 +66,7 @@ public class RenameMethodMultiTest extends MultiFileTestCase { catch (BaseRefactoringProcessor.ConflictsInTestsException e) { Assert.assertEquals("Renaming method will override final \"method <b><code>A.finalMethod()</code></b>\"\n" + "Method finalMethod() will override \n" + - "a method of the base class <b><code>p.A</code></b>.", e.getMessage()); + "a method of the base class <b><code>p.A</code></b>", e.getMessage()); return; } fail("Conflicts were not found"); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java index 6d66a438ba82..4cf3229a412c 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -1,3 +1,18 @@ +/* + * 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.refactoring.inline; import com.intellij.JavaTestUtil; @@ -108,11 +123,11 @@ public class InlineLocalTest extends LightCodeInsightTestCase { } public void testAnotherDefinitionUsed() throws Exception { - doTest(true, "Cannot perform refactoring.\nAnother variable 'bar' definition is used together with inlined one."); + doTest(true, "Cannot perform refactoring.\nAnother variable 'bar' definition is used together with inlined one"); } public void testAnotherDefinitionUsed1() throws Exception { - doTest(false, "Cannot perform refactoring.\nAnother variable 'bar' definition is used together with inlined one."); + doTest(false, "Cannot perform refactoring.\nAnother variable 'bar' definition is used together with inlined one"); } public void testTypeArgumentsStatic() throws Exception { @@ -137,7 +152,7 @@ public class InlineLocalTest extends LightCodeInsightTestCase { public void testAssignmentToArrayElement() throws Exception { doTest(true, "Cannot perform refactoring.\n" + - "Variable 'arr' is accessed for writing."); + "Variable 'arr' is accessed for writing"); } public void testArrayMethodCallInitialized() throws Exception { @@ -150,7 +165,7 @@ public class InlineLocalTest extends LightCodeInsightTestCase { public void testNonEqAssignment() throws Exception { doTest(false, "Cannot perform refactoring.\n" + - "Variable 'x' is accessed for writing."); + "Variable 'x' is accessed for writing"); } public void testInlineFromTryCatch() throws Exception { @@ -223,7 +238,7 @@ public class InlineLocalTest extends LightCodeInsightTestCase { public void testLocalVarInsideLambdaBodyWriteUsage() throws Exception { doTest(true, "Cannot perform refactoring.\n" + - "Variable 'hello' is accessed for writing."); + "Variable 'hello' is accessed for writing"); } private void doTest(final boolean inlineDef, String conflictMessage) throws Exception { diff --git a/java/jdkAnnotations/java/util/annotations.xml b/java/jdkAnnotations/java/util/annotations.xml index 9699f06c123b..4d202ed84b61 100644 --- a/java/jdkAnnotations/java/util/annotations.xml +++ b/java/jdkAnnotations/java/util/annotations.xml @@ -462,12 +462,7 @@ <item name="java.util.Arrays void sort(short[], int, int) 0"> <annotation name="org.jetbrains.annotations.NotNull" /> </item> - <item name="java.util.Calendar void add(int, int) 0" > - <annotation name="org.intellij.lang.annotations.MagicConstant"> - <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> - </annotation> - </item> - <item name="java.util.Calendar void clear(int) 0" > + <item name="java.util.Calendar boolean isSet(int) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> @@ -487,52 +482,57 @@ <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar java.lang.String getDisplayName(int, int, java.util.Locale) 0"> + <item name="java.util.Calendar int getFirstDayOfWeek()"> <annotation name="org.intellij.lang.annotations.MagicConstant"> - <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> + <val name="intValues" val="{java.util.Calendar.SUNDAY, java.util.Calendar.MONDAY, java.util.Calendar.TUESDAY, java.util.Calendar.WEDNESDAY, java.util.Calendar.THURSDAY, java.util.Calendar.FRIDAY, java.util.Calendar.SATURDAY}" /> </annotation> </item> - <item name="java.util.Calendar java.lang.String getDisplayName(int, int, java.util.Locale) 1"> + <item name="java.util.Calendar int getGreatestMinimum(int) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> - <val name="intValues" val="{java.util.Calendar.SHORT, java.util.Calendar.LONG}" /> + <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, java.util.Locale) 0"> + <item name="java.util.Calendar int getLeastMaximum(int) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, java.util.Locale) 1"> + <item name="java.util.Calendar int getMaximum(int) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> - <val name="intValues" val="{java.util.Calendar.SHORT, java.util.Calendar.LONG, java.util.Calendar.ALL_STYLES}" /> + <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar int getFirstDayOfWeek()"> + <item name="java.util.Calendar int getMinimum(int) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> - <val name="intValues" val="{java.util.Calendar.SUNDAY, java.util.Calendar.MONDAY, java.util.Calendar.TUESDAY, java.util.Calendar.WEDNESDAY, java.util.Calendar.THURSDAY, java.util.Calendar.FRIDAY, java.util.Calendar.SATURDAY}" /> + <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar int getGreatestMinimum(int) 0"> + <item name="java.util.Calendar java.lang.String getDisplayName(int, int, java.util.Locale) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar int getLeastMaximum(int) 0"> + <item name="java.util.Calendar java.lang.String getDisplayName(int, int, java.util.Locale) 1"> <annotation name="org.intellij.lang.annotations.MagicConstant"> - <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> + <val name="intValues" val="{java.util.Calendar.SHORT, java.util.Calendar.LONG}" /> </annotation> </item> - <item name="java.util.Calendar int getMaximum(int) 0"> + <item name="java.util.Calendar java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, java.util.Locale) 0"> <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar int getMinimum(int) 0"> + <item name="java.util.Calendar java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, java.util.Locale) 1"> + <annotation name="org.intellij.lang.annotations.MagicConstant"> + <val name="intValues" val="{java.util.Calendar.SHORT, java.util.Calendar.LONG, java.util.Calendar.ALL_STYLES}" /> + </annotation> + </item> + <item name="java.util.Calendar void add(int, int) 0" > <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> </item> - <item name="java.util.Calendar boolean isSet(int) 0"> + <item name="java.util.Calendar void clear(int) 0" > <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, java.util.Calendar.WEEK_OF_MONTH, java.util.Calendar.DATE, java.util.Calendar.DAY_OF_MONTH, java.util.Calendar.DAY_OF_YEAR, java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.DAY_OF_WEEK_IN_MONTH, java.util.Calendar.AM_PM, java.util.Calendar.HOUR, java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.MINUTE, java.util.Calendar.SECOND, java.util.Calendar.MILLISECOND, java.util.Calendar.ZONE_OFFSET, java.util.Calendar.DST_OFFSET}" /> </annotation> diff --git a/java/jdkAnnotations/java/util/regex/annotations.xml b/java/jdkAnnotations/java/util/regex/annotations.xml index b3f189ef714a..2afbcb551b37 100644 --- a/java/jdkAnnotations/java/util/regex/annotations.xml +++ b/java/jdkAnnotations/java/util/regex/annotations.xml @@ -11,10 +11,17 @@ <val name="flagsFromClass" val="java.util.regex.Pattern.class" /> </annotation> </item> + <item name='java.util.regex.Pattern java.util.regex.Matcher matcher(java.lang.CharSequence)'> + <annotation name='org.jetbrains.annotations.NotNull'/> + </item> <item name="java.util.regex.Pattern java.util.regex.Pattern compile(java.lang.String) 0"> <annotation name="org.jetbrains.annotations.NonNls" /> <annotation name="org.jetbrains.annotations.NotNull" /> </item> + <item name="java.util.regex.Pattern java.util.regex.Pattern compile(java.lang.String, int) 0"> + <annotation name="org.jetbrains.annotations.NonNls" /> + <annotation name="org.jetbrains.annotations.NotNull" /> + </item> <item name="java.util.regex.Pattern java.util.regex.Pattern compile(java.lang.String, int) 1"> <annotation name="org.intellij.lang.annotations.MagicConstant"> <val name="flagsFromClass" val="java.util.regex.Pattern.class" /> diff --git a/java/manifest/src/org/jetbrains/lang/manifest/parser/ManifestLexer.java b/java/manifest/src/org/jetbrains/lang/manifest/parser/ManifestLexer.java index 26741c2d4d60..13727688ef3a 100644 --- a/java/manifest/src/org/jetbrains/lang/manifest/parser/ManifestLexer.java +++ b/java/manifest/src/org/jetbrains/lang/manifest/parser/ManifestLexer.java @@ -27,6 +27,7 @@ package org.jetbrains.lang.manifest.parser; import com.intellij.lexer.LexerBase; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.lang.manifest.psi.ManifestTokenType; @@ -63,7 +64,7 @@ public class ManifestLexer extends LexerBase { private IElementType myTokenType; @Override - public void start(CharSequence buffer, int startOffset, int endOffset, int initialState) { + public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { this.myBuffer = buffer; this.myEndOffset = endOffset; myCurrentState = State.values()[initialState]; @@ -104,6 +105,7 @@ public class ManifestLexer extends LexerBase { return myEndOffset; } + @NotNull @Override public CharSequence getBufferSequence() { return myBuffer; diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java index 60bf96c5bb39..52a24e8c2681 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java @@ -24,8 +24,11 @@ import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl; +import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper; import com.intellij.testFramework.ExpectedHighlightingData; import com.intellij.testFramework.FileTreeAccessFilter; import com.intellij.testFramework.HighlightTestInfo; @@ -80,6 +83,18 @@ public abstract class LightDaemonAnalyzerTestCase extends LightCodeInsightTestCa doTestConfiguredFile(checkWarnings, checkInfos, filePath); } + protected void doTestNewInference(@NonNls String filePath, boolean checkWarnings, boolean checkInfos) { + final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper(); + //helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager())); + try { + configureByFile(filePath); + doTestConfiguredFile(checkWarnings, checkInfos, filePath); + } + finally { + helper.setTestHelper(null); + } + } + protected void doTest(@NonNls String filePath, boolean checkWarnings, boolean checkWeakWarnings, boolean checkInfos) { configureByFile(filePath); doTestConfiguredFile(checkWarnings, checkWeakWarnings, checkInfos, filePath); diff --git a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java index 7164207797db..348a1afadae3 100644 --- a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java +++ b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java @@ -80,7 +80,7 @@ public class CompilerTestUtil { public static void enableExternalCompiler(final Project project) { new WriteAction() { protected void run(final Result result) { - CompilerWorkspaceConfiguration.getInstance(project).USE_COMPILE_SERVER = true; + CompilerWorkspaceConfiguration.getInstance(project).USE_OUT_OF_PROCESS_BUILD = true; ApplicationManagerEx.getApplicationEx().doNotSave(false); JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); table.addJdk(table.getInternalJdk()); @@ -91,7 +91,7 @@ public class CompilerTestUtil { public static void disableExternalCompiler(final Project project) { new WriteAction() { protected void run(final Result result) { - CompilerWorkspaceConfiguration.getInstance(project).USE_COMPILE_SERVER = false; + CompilerWorkspaceConfiguration.getInstance(project).USE_OUT_OF_PROCESS_BUILD = false; ApplicationManagerEx.getApplicationEx().doNotSave(true); JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); table.removeJdk(table.getInternalJdk()); diff --git a/java/testFramework/src/com/intellij/ide/projectWizard/NewProjectWizardTestCase.java b/java/testFramework/src/com/intellij/ide/projectWizard/NewProjectWizardTestCase.java new file mode 100644 index 000000000000..8ae8848fabf1 --- /dev/null +++ b/java/testFramework/src/com/intellij/ide/projectWizard/NewProjectWizardTestCase.java @@ -0,0 +1,18 @@ +package com.intellij.ide.projectWizard; + +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; + +import java.io.File; + +/** + * @author Dmitry Avdeev + * Date: 23.09.13 + */ +public abstract class NewProjectWizardTestCase extends ProjectWizardTestCase { + @Override + protected AbstractProjectWizard createWizard(Project project, File directory) { + return new NewProjectWizard(project, ModulesProvider.EMPTY_MODULES_PROVIDER, directory.getPath()); + } +} diff --git a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java index 9620aa7f27f9..8a05be2e6e68 100644 --- a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java +++ b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java @@ -2,10 +2,11 @@ package com.intellij.ide.projectWizard; import com.intellij.ide.actions.ImportModuleAction; import com.intellij.ide.impl.NewProjectUtil; +import com.intellij.ide.util.newProjectWizard.AbstractProjectWizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; import com.intellij.ide.util.newProjectWizard.SelectTemplateSettings; import com.intellij.ide.util.newProjectWizard.SelectTemplateStep; -import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.wizard.Step; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -38,14 +39,15 @@ import java.util.List; * @author Dmitry Avdeev * Date: 10/29/12 */ -public abstract class ProjectWizardTestCase extends PlatformTestCase { +@SuppressWarnings("unchecked") +public abstract class ProjectWizardTestCase<T extends AbstractProjectWizard> extends PlatformTestCase { protected final List<Sdk> mySdks = new ArrayList<Sdk>(); - protected AddModuleWizard myWizard; + protected T myWizard; @Nullable private Project myCreatedProject; - protected Project createProjectFromTemplate(String group, String name, @Nullable Consumer<ModuleWizardStep> adjuster) throws IOException { + protected Project createProjectFromTemplate(String group, String name, @Nullable Consumer<Step> adjuster) throws IOException { runWizard(group, name, null, adjuster); try { myCreatedProject = NewProjectUtil.createFromWizard(myWizard, null); @@ -68,7 +70,7 @@ public abstract class ProjectWizardTestCase extends PlatformTestCase { } @Nullable - protected Module createModuleFromTemplate(String group, String name, @Nullable Consumer<ModuleWizardStep> adjuster) throws IOException { + protected Module createModuleFromTemplate(String group, String name, @Nullable Consumer<Step> adjuster) throws IOException { runWizard(group, name, getProject(), adjuster); return createModuleFromWizard(); } @@ -77,7 +79,7 @@ public abstract class ProjectWizardTestCase extends PlatformTestCase { return new NewModuleAction().createModuleFromWizard(myProject, null, myWizard); } - protected void runWizard(String group, String name, Project project, @Nullable Consumer<ModuleWizardStep> adjuster) throws IOException { + protected void runWizard(String group, String name, Project project, @Nullable Consumer<Step> adjuster) throws IOException { createWizard(project); SelectTemplateStep step = (SelectTemplateStep)myWizard.getCurrentStepObject(); @@ -98,11 +100,22 @@ public abstract class ProjectWizardTestCase extends PlatformTestCase { protected void createWizard(Project project) throws IOException { File directory = FileUtil.createTempDirectory(getName(), "new", false); myFilesToDelete.add(directory); - myWizard = new AddModuleWizard(project, DefaultModulesProvider.createForProject(project), directory.getPath()); + myWizard = createWizard(project, directory); UIUtil.dispatchAllInvocationEvents(); // to make default selection applied } - protected void runWizard(Consumer<ModuleWizardStep> adjuster) { + protected Project createProject(Consumer<Step> adjuster) throws IOException { + createWizard(getProject()); + runWizard(adjuster); + myCreatedProject = NewProjectUtil.createFromWizard(myWizard, null); + return myCreatedProject; + } + + protected T createWizard(Project project, File directory) { + return (T)new AddModuleWizard(project, DefaultModulesProvider.createForProject(project), directory.getPath()); + } + + protected void runWizard(Consumer<Step> adjuster) { while (!myWizard.isLast()) { myWizard.doNextAction(); if (adjuster != null) { @@ -157,7 +170,7 @@ public abstract class ProjectWizardTestCase extends PlatformTestCase { return importFrom(path, getProject(), null, provider); } - protected Module importProjectFrom(String path, Consumer<ModuleWizardStep> adjuster, ProjectImportProvider... providers) { + protected Module importProjectFrom(String path, Consumer<Step> adjuster, ProjectImportProvider... providers) { Module module = importFrom(path, null, adjuster, providers); if (module != null) { myCreatedProject = module.getProject(); @@ -166,13 +179,14 @@ public abstract class ProjectWizardTestCase extends PlatformTestCase { } private Module importFrom(String path, - @Nullable Project project, Consumer<ModuleWizardStep> adjuster, + @Nullable Project project, Consumer<Step> adjuster, final ProjectImportProvider... providers) { VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); assertNotNull("Can't find " + path, file); assertTrue(providers[0].canImport(file, project)); - myWizard = ImportModuleAction.createImportWizard(project, null, file, providers); + myWizard = (T)ImportModuleAction.createImportWizard(project, null, file, providers); + assertNotNull(myWizard); if (myWizard.getStepCount() > 0) { runWizard(adjuster); } |