Merge remote-tracking branch 'origin/master'

This commit is contained in:
Anton Tarasov
2017-04-05 15:09:57 +03:00
429 changed files with 11580 additions and 7650 deletions
+4
View File
@@ -1,3 +1,5 @@
build/dependencies/.gradle
build/dependencies/build
/android
/config
/system
@@ -7,3 +9,5 @@
/test-system
/test-config
*.pyc
.idea/libraries/Gradle__*.xml
.idea/gradle_extensions.xml
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$/build/dependencies" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$/build/dependencies" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useAutoImport" value="true" />
</GradleProjectSettings>
</option>
</component>
</project>
+77 -4
View File
@@ -1,5 +1,5 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<profile version="1.0">
<option name="myName" value="idea.default" />
<option name="myLocal" value="true" />
<inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
@@ -128,11 +128,15 @@
<inspection_tool class="AndroidMissingOnClickHandler" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidNonConstantResIdsInSwitch" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Anonymous2MethodRef" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AppEngineForbiddenCode" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ArchaicSystemPropertyAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ArgNamesErrorsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ArgNamesWarningsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AroundAdviceStyleInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ArraysAsListWithZeroOrOneArgument" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="Tests" level="INFO" enabled="true" />
</inspection_tool>
<inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_checkForeachParameters" value="false" />
</inspection_tool>
@@ -181,7 +185,6 @@
<inspection_tool class="CfmlReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ChainedEquality" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CheckNodeTest" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ClassNameSameAsAncestorName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CloneCallsSuperClone" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CloneDeclaresCloneNotSupported" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CommaExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -194,6 +197,10 @@
</inspection_tool>
<inspection_tool class="ConstantConditionalExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConstantConditions" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="Tests" level="WARNING" enabled="false">
<option name="SUGGEST_NULLABLE_ANNOTATIONS" value="false" />
<option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="false" />
</scope>
<scope name="runtime.classes" level="WARNING" enabled="false">
<option name="SUGGEST_NULLABLE_ANNOTATIONS" value="false" />
<option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="false" />
@@ -208,6 +215,11 @@
<inspection_tool class="ConstraintValidatorCreator" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ContinueOrBreakFromFinallyBlock" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ContinueOrBreakFromFinallyBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Convert2Lambda" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="android" level="WARNING" enabled="false" />
<option name="reportNotAnnotatedInterfaces" value="false" />
</inspection_tool>
<inspection_tool class="Convert2MethodRef" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="CovariantCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DeclareParentsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
@@ -227,6 +239,10 @@
<option name="ignoreMethodCalls" value="false" />
</inspection_tool>
<inspection_tool class="DuplicatedBlockNamesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EmptyStatementBody" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_reportEmptyBlocks" value="true" />
<option name="commentsAreContent" value="true" />
</inspection_tool>
<inspection_tool class="EmptyStatementBodyJS" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_reportEmptyBlocks" value="false" />
</inspection_tool>
@@ -254,16 +270,22 @@
<inspection_tool class="Geronimo" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GlassFish" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GrUnresolvedAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Guava" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HardcodedActionUrl" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HardwiredNamespacePrefix" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="IOResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredTypesString" value="java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringBufferInputStream,java.io.CharArrayWriter,java.io.CharArrayReader,java.io.StringWriter,java.io.StringReader,io.netty.buffer.ByteBufOutputStream,com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream" />
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="IfCanBeSwitch" enabled="false" level="WARNING" enabled_by_default="false">
<option name="minimumBranches" value="3" />
<option name="suggestIntSwitches" value="false" />
<option name="suggestEnumSwitches" value="false" />
</inspection_tool>
<inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IgnoreResultOfCall" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_reportAllNonLibraryCalls" value="false" />
<option name="callCheckString" value="java.io.File,.*,java.io.InputStream,read|skip|available|markSupported,java.io.Writer,read|skip|ready|markSupported,java.lang.Boolean,.*,java.lang.Byte,.*,java.lang.Character,.*,java.lang.Double,.*,java.lang.Float,.*,java.lang.Integer,.*,java.lang.Long,.*,java.lang.Math,.*,java.lang.Object,equals|hashCode|toString,java.lang.Short,.*,java.lang.StrictMath,.*,java.lang.String,.*,java.math.BigInteger,.*,java.math.BigDecimal,.*,java.net.InetAddress,.*,java.net.URI,.*,java.util.UUID,.*,java.util.regex.Matcher,pattern|toMatchResult|start|end|group|groupCount|matches|find|lookingAt|quoteReplacement|replaceAll|replaceFirst|regionStart|regionEnd|hasTransparantBounds|hasAnchoringBounds|hitEnd|requireEnd,java.util.regex.Pattern,.*,com.intellij.openapi.util.LowMemoryWatcher,register" />
<option name="callCheckString" value="java.io.File,.*,java.io.InputStream,read|skip|available|markSupported,java.io.Writer,read|skip|ready|markSupported,java.lang.Boolean,.*,java.lang.Byte,.*,java.lang.Character,.*,java.lang.Double,.*,java.lang.Float,.*,java.lang.Integer,.*,java.lang.Long,.*,java.lang.Math,.*,java.lang.Object,equals|hashCode|toString,java.lang.Short,.*,java.lang.StrictMath,.*,java.lang.String,.*,java.math.BigInteger,.*,java.math.BigDecimal,.*,java.net.InetAddress,.*,java.net.URI,.*,java.util.UUID,.*,java.util.regex.Matcher,pattern|toMatchResult|start|end|group|groupCount|matches|find|lookingAt|quoteReplacement|replaceAll|replaceFirst|regionStart|regionEnd|hasTransparantBounds|hasAnchoringBounds|hitEnd|requireEnd,java.util.regex.Pattern,.*,com.intellij.openapi.util.LowMemoryWatcher,register,com.intellij.codeInsight.FileModificationService,preparePsiElementForWrite" />
</inspection_tool>
<inspection_tool class="ImplicitTypeConversion" enabled="false" level="WARNING" enabled_by_default="false">
<option name="BITS" value="1720" />
@@ -317,7 +339,7 @@
<inspection_tool class="JSValidateJSON" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JSValidateTypes" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JUnitTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_regex" value="[A-Z][A-Za-z0-9]*Test" />
<option name="m_regex" value="[A-Z][A-Za-z0-9_]*Test" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
@@ -459,6 +481,7 @@
<scope name="idea openapi" level="WARNING" enabled="true" />
<scope name="runtime.classes" level="ERROR" enabled="true" />
</inspection_tool>
<inspection_tool class="LambdaUnfriendlyMethodOverload" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
@@ -476,6 +499,7 @@
<inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MinMaxValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MinitestFrameworkSupportInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MisorderedAssertEqualsParameters" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MisspelledCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MisspelledHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
@@ -546,6 +570,7 @@
<option name="IGNORE_ANNOTATED_METHODS" value="true" />
<option name="IGNORE_SUSPICIOUS_METHOD_CALLS" value="true" />
</inspection_tool>
<inspection_tool class="RedundantSamConstructor" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantScopeBinding" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantToBinding" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantToProviderBinding" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -608,6 +633,11 @@
<constraint name="suffix" within="" contains="" />
<constraint name="dir" within="" contains="" />
</replaceConfiguration>
<searchConfiguration name="Consider explicit delete when file is not needed any more" text="$file$.deleteOnExit()" recursive="false" caseInsensitive="true" type="JAVA">
<constraint name="prefix" within="" contains="" />
<constraint name="suffix" within="" contains="" />
<constraint name="file" nameOfExprType="java.io.File" within="" contains="" />
</searchConfiguration>
<searchConfiguration name="Use RecursionManager?" text="class $Class$ { &#10; ThreadLocal&lt;$FieldType$&gt; $FieldName$ = $Init$;&#10;}" recursive="false" caseInsensitive="false" type="JAVA">
<constraint name="Class" script="&quot;&quot;" within="" contains="" />
<constraint name="FieldType" script="&quot;&quot;" regexp="Collection" withinHierarchy="true" maxCount="2147483647" target="true" wholeWordsOnly="true" within="" contains="" />
@@ -654,6 +684,37 @@
<replaceConfiguration name="StringUtil.stripQuotesAroundValue" text="com.intellij.openapi.util.text.StringUtil.stripQuotesAroundValue($Parameter$)" recursive="false" caseInsensitive="false" type="JAVA" reformatAccordingToStyle="true" shortenFQN="true" replacement="com.intellij.openapi.util.text.StringUtil.unquoteString($Parameter$)">
<constraint name="Parameter" within="" contains="" />
</replaceConfiguration>
<replaceConfiguration name="new String(byte[]) is default locale dependent; use new String(byte[], Charset) instead" text="new String($b$)" recursive="false" caseInsensitive="true" type="JAVA" reformatAccordingToStyle="true" shortenFQN="true" replacement="new String($b$, com.intellij.openapi.vfs.CharsetToolkit.UTF8_CHARSET)">
<constraint name="s" within="" contains="" />
<constraint name="type" within="" contains="" />
<constraint name="b" nameOfExprType="byte\[\]" exprTypeWithinHierarchy="true" within="" contains="" />
</replaceConfiguration>
<searchConfiguration name="Anonymous threads are discouraged; please supply name" text="new Thread()" recursive="true" caseInsensitive="true" type="JAVA">
<constraint name="s" within="" contains="" />
<constraint name="type" within="" contains="" />
</searchConfiguration>
<searchConfiguration name="Anonymous threads runnable are discouraged; please supply name" text="new Thread($runnable$)" recursive="true" caseInsensitive="true" type="JAVA">
<constraint name="s" within="" contains="" />
<constraint name="type" within="" contains="" />
<constraint name="runnable" nameOfExprType="java.lang.Runnable" exprTypeWithinHierarchy="true" within="" contains="" />
</searchConfiguration>
<searchConfiguration name="DBE model property is private (must be public)" text="class $Class$ {&#10; @StateProperty&#10; private $FieldType$ $FieldName$&#10;}" recursive="true" caseInsensitive="true" type="JAVA">
<constraint name="Class" within="" contains="" />
<constraint name="FieldType" within="" contains="" />
<constraint name="FieldName" target="true" within="" contains="" />
<constraint name="__context__" within="" contains="" />
</searchConfiguration>
<searchConfiguration name="DBE model property is package local (must be public)" text="class $Class$ {&#10; @StateProperty&#10; @Modifier(&quot;packageLocal&quot;) $FieldType$ $FieldName$&#10;}" recursive="true" caseInsensitive="true" type="JAVA">
<constraint name="Class" within="" contains="" />
<constraint name="FieldType" within="" contains="" />
<constraint name="FieldName" target="true" within="" contains="" />
</searchConfiguration>
<searchConfiguration name="DBE model property is protected (must be public)" text="class $Class$ {&#10; @StateProperty&#10; protected $FieldType$ $FieldName$&#10;}" recursive="true" caseInsensitive="true" type="JAVA">
<constraint name="Class" within="" contains="" />
<constraint name="FieldType" within="" contains="" />
<constraint name="FieldName" target="true" within="" contains="" />
<constraint name="__context__" within="" contains="" />
</searchConfiguration>
<replaceConfiguration name="can use StringUtil.trimStart" text="if ($s$.startsWith($e$)) {&#10; $s$ = $s$.substring($e$.length());&#10;}" recursive="false" caseInsensitive="true" type="JAVA" reformatAccordingToStyle="true" shortenFQN="true" replacement="$s$ = com.intellij.openapi.util.text.StringUtil.trimStart($s$, $e$);&#10;">
<constraint name="s" within="" contains="" />
<constraint name="e" within="" contains="" />
@@ -687,7 +748,14 @@
<constraint name="t" within="" contains="" />
<constraint name="b" nameOfExprType="boolean" exprTypeWithinHierarchy="true" within="" contains="" />
</searchConfiguration>
<replaceConfiguration name="&quot;var = volatile = E&quot; should be &quot;volatile = var = E&quot;" text="$var$ = $field$ = $e$;" recursive="false" caseInsensitive="true" type="JAVA" reformatAccordingToStyle="true" shortenFQN="true" useStaticImport="true" replacement="$field$ = $var$ = $e$;">
<constraint name="e" within="" contains="" />
<constraint name="var" within="" contains="" />
<constraint name="field" script="&quot;import com.intellij.psi.PsiField&#10;import com.intellij.psi.PsiModifier&#10;import com.intellij.psi.PsiReferenceExpression&#10;import com.intellij.psi.PsiVariable&#10;&#10;field instanceof PsiReferenceExpression &amp;&amp;&#10;((PsiReferenceExpression)field).resolve() instanceof PsiField &amp;&amp;&#10;((PsiField)((PsiReferenceExpression)field).resolve()).hasModifierProperty(PsiModifier.VOLATILE) &amp;&amp;&#10;var instanceof PsiReferenceExpression &amp;&amp;&#10;((PsiReferenceExpression)var).resolve() instanceof PsiVariable &amp;&amp;&#10;!((PsiVariable)((PsiReferenceExpression)var).resolve()).hasModifierProperty(PsiModifier.VOLATILE)&quot;" within="" contains="" />
<constraint name="__context__" target="true" within="" contains="" />
</replaceConfiguration>
</inspection_tool>
<inspection_tool class="SafeVarargsDetector" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SeamAnnotationIncorrectSignatureInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SeamAnnotationsInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SeamBijectionIllegalScopeParameterInspection" enabled="false" level="ERROR" enabled_by_default="false" />
@@ -715,6 +783,8 @@
<inspection_tool class="SpringFacetProgrammaticInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="StaticCallOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticFieldReferenceOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticPseudoFunctionalStyleMethod" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="StaticSuite" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConstructor" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignoreSubstringArguments" value="false" />
@@ -751,6 +821,7 @@
</inspection_tool>
<inspection_tool class="ThreadRun" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThrowFromFinallyBlock" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ThrowFromFinallyBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ThrowablePrintStackTrace" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="Tests" level="WARNING" enabled="false" />
@@ -759,6 +830,8 @@
<inspection_tool class="TrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TrivialIfJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TrivialStringConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TryFinallyCanBeTryWithResources" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TryWithIdenticalCatches" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UNCHECKED_WARNING" enabled="true" level="WARNING" enabled_by_default="true">
<option name="IGNORE_UNCHECKED_ASSIGNMENT" value="false" />
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -65,6 +65,7 @@
<module fileurl="file://$PROJECT_DIR$/android/tools-base/ddmlib/ddmlib.iml" filepath="$PROJECT_DIR$/android/tools-base/ddmlib/ddmlib.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/java/debugger/impl/debugger-impl.iml" filepath="$PROJECT_DIR$/java/debugger/impl/debugger-impl.iml" group="java" />
<module fileurl="file://$PROJECT_DIR$/java/debugger/openapi/debugger-openapi.iml" filepath="$PROJECT_DIR$/java/debugger/openapi/debugger-openapi.iml" group="java" />
<module fileurl="file://$PROJECT_DIR$/build/dependencies/dependencies.iml" filepath="$PROJECT_DIR$/build/dependencies/dependencies.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/devkit.iml" filepath="$PROJECT_DIR$/plugins/devkit/devkit.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/jps-plugin/devkit-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/devkit/jps-plugin/devkit-jps-plugin.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/devkit-tests.iml" filepath="$PROJECT_DIR$/plugins/devkit/devkit-tests.iml" group="plugins" />
@@ -167,7 +168,7 @@
<module fileurl="file://$PROJECT_DIR$/platform/lang-impl/lang-tests.iml" filepath="$PROJECT_DIR$/platform/lang-impl/lang-tests.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/android/layoutlib/layoutlib.iml" filepath="$PROJECT_DIR$/android/layoutlib/layoutlib.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/android/tools-base/layoutlib-api/layoutlib-api.iml" filepath="$PROJECT_DIR$/android/tools-base/layoutlib-api/layoutlib-api.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/android/tools-base/layoutlib-resources.iml" filepath="$PROJECT_DIR$/android/tools-base/layoutlib-resources.iml" group="android/sdktools"/>
<module fileurl="file://$PROJECT_DIR$/android/tools-base/layoutlib-resources.iml" filepath="$PROJECT_DIR$/android/tools-base/layoutlib-resources.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/android/tools-base/lint/libs/lint-api/lint-api.iml" filepath="$PROJECT_DIR$/android/tools-base/lint/libs/lint-api/lint-api.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/android/tools-base/lint/libs/lint-checks/lint-checks.iml" filepath="$PROJECT_DIR$/android/tools-base/lint/libs/lint-checks/lint-checks.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/platform/lvcs-api/lvcs-api.iml" filepath="$PROJECT_DIR$/platform/lvcs-api/lvcs-api.iml" group="platform" />
@@ -194,7 +195,7 @@
<module fileurl="file://$PROJECT_DIR$/android/tools-base/perflib/perflib.iml" filepath="$PROJECT_DIR$/android/tools-base/perflib/perflib.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/android/tools-base/pixelprobe/pixelprobe.iml" filepath="$PROJECT_DIR$/android/tools-base/pixelprobe/pixelprobe.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/platform/platform-api/platform-api.iml" filepath="$PROJECT_DIR$/platform/platform-api/platform-api.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/build-scripts/platform-build-scripts.iml" filepath="$PROJECT_DIR$/platform/build-scripts/platform-build-scripts.iml" group="platform"/>
<module fileurl="file://$PROJECT_DIR$/platform/build-scripts/platform-build-scripts.iml" filepath="$PROJECT_DIR$/platform/build-scripts/platform-build-scripts.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/platform-impl/platform-impl.iml" filepath="$PROJECT_DIR$/platform/platform-impl/platform-impl.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/platform-main/platform-main.iml" filepath="$PROJECT_DIR$/platform/platform-main/platform-main.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/platform-resources/platform-resources.iml" filepath="$PROJECT_DIR$/platform/platform-resources/platform-resources.iml" group="platform" />
@@ -263,7 +264,7 @@
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/extensions/testExtensions.iml" filepath="$PROJECT_DIR$/platform/testFramework/extensions/testExtensions.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/testFramework/testFramework.iml" filepath="$PROJECT_DIR$/platform/testFramework/testFramework.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/java/testFramework/testFramework-java.iml" filepath="$PROJECT_DIR$/java/testFramework/testFramework-java.iml" group="java" />
<module fileurl="file://$PROJECT_DIR$/platform/testGuiFramework/testGuiFramework.iml" filepath="$PROJECT_DIR$/platform/testGuiFramework/testGuiFramework.iml" group="platform"/>
<module fileurl="file://$PROJECT_DIR$/platform/testGuiFramework/testGuiFramework.iml" filepath="$PROJECT_DIR$/platform/testGuiFramework/testGuiFramework.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/testRunner/testRunner.iml" filepath="$PROJECT_DIR$/platform/testRunner/testRunner.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/plugins/testng/testng.iml" filepath="$PROJECT_DIR$/plugins/testng/testng.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/testng_rt/testng_rt.iml" filepath="$PROJECT_DIR$/plugins/testng_rt/testng_rt.iml" group="plugins" />
+18
View File
@@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="PyCharm Educational Edition" type="Application" factoryName="Application">
<log_file path="$PROJECT_DIR$/system/log/idea.log" checked="true" skipped="true" show_all="false" alias="idea.log" />
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
<option name="VM_PARAMETERS" value=" -ea -Xbootclasspath/p:../out/classes/production/boot -Xmx192m -Didea.is.internal=true -Didea.platform.prefix=PyCharmEdu" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bin" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<module name="main_pycharm_edu" />
<envs />
<method />
</configuration>
</component>
+55 -63
View File
@@ -21,15 +21,6 @@ message()
fi
}
isJDK()
{
if [ -z $1 ] || [ ! -x "$1/bin/java" ]; then
return 1
else
return 0
fi
}
UNAME=`which uname`
GREP=`which egrep`
GREP_OPTIONS=""
@@ -68,82 +59,83 @@ fi
# ---------------------------------------------------------------------
# Locate a JDK installation directory which will be used to run the IDE.
# Try (in order): @@product_uc@@_JDK, @@vm_options@@.jdk, ../jre, JDK_HOME, JAVA_HOME, "java" in PATH.
# Try (in order): @@product_uc@@_JDK, @@vm_options@@.jdk, ./jre64, JDK_HOME, JAVA_HOME, "java" in PATH.
# ---------------------------------------------------------------------
JDK=""
if isJDK $@@product_uc@@_JDK; then
if [ -n "$@@product_uc@@_JDK" -a -x "$@@product_uc@@_JDK/bin/java" ]; then
JDK="$@@product_uc@@_JDK"
fi
if [ "$JDK" = "" ] && [ -s "$HOME/.@@system_selector@@/config/@@vm_options@@.jdk" ]; then
JDK=`"$CAT" $HOME/.@@system_selector@@/config/@@vm_options@@.jdk`
if [ ! -d "$JDK" ]; then
JDK="$IDE_HOME/$JDK"
if [ -z "$JDK" -a -s "$HOME/.@@system_selector@@/config/@@vm_options@@.jdk" ]; then
USER_JRE=`"$CAT" $HOME/.@@system_selector@@/config/@@vm_options@@.jdk`
if [ ! -d "$USER_JRE" ]; then
USER_JRE="$IDE_HOME/$USER_JRE"
fi
if ! isJDK $JDK; then
JDK=""
if [ -x "$USER_JRE/bin/java" ]; then
JDK="$USER_JRE"
fi
fi
if [ "$JDK" = "" ] && [ "$OS_TYPE" = "Linux" ] &&
[ -x "$IDE_HOME/jre64/bin/java" ] && "$IDE_HOME/jre64/bin/java" -version > /dev/null 2>&1 ; then
JDK="$IDE_HOME/jre64"
if [ -z "$JDK" -a "$OS_TYPE" = "Linux" ] ; then
BUNDLED_JRE="$IDE_HOME/jre64"
if [ ! -d "$BUNDLED_JRE" ]; then
BUNDLED_JRE="$IDE_HOME/jre"
fi
if [ -x "$BUNDLED_JRE/bin/java" ] && "$BUNDLED_JRE/bin/java" -version > /dev/null 2>&1 ; then
JDK="$BUNDLED_JRE"
fi
fi
if [ "$JDK" = "" ] && [ -n "$JDK_HOME" -a -x "$JDK_HOME/bin/java" ]; then
if [ -z "$JDK" -a -n "$JDK_HOME" -a -x "$JDK_HOME/bin/java" ]; then
JDK="$JDK_HOME"
fi
if [ "$JDK" = "" ]; then
if isJDK $JAVA_HOME; then
JDK="$JAVA_HOME"
else
JAVA_BIN_PATH=`which java`
if [ -n "$JAVA_BIN_PATH" ]; then
if [ "$OS_TYPE" = "FreeBSD" -o "$OS_TYPE" = "MidnightBSD" ]; then
JAVA_LOCATION=`JAVAVM_DRYRUN=yes java | "$GREP" '^JAVA_HOME' | "$CUT" -c11-`
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
elif [ "$OS_TYPE" = "SunOS" ]; then
JAVA_LOCATION="/usr/jdk/latest"
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
elif [ "$OS_TYPE" = "Darwin" ]; then
JAVA_LOCATION=`/usr/libexec/java_home`
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
fi
fi
if [ -z "$JDK" -a -n "$JAVA_HOME" -a -x "$JAVA_HOME/bin/java" ]; then
JDK="$JAVA_HOME"
fi
if [ -z "$JDK" -a -x "$READLINK" -a -x "$XARGS" -a -x "$DIRNAME" ]; then
JAVA_LOCATION=`"$READLINK" -f "$JAVA_BIN_PATH"`
case "$JAVA_LOCATION" in
*/jre/bin/java)
JAVA_LOCATION=`echo "$JAVA_LOCATION" | "$XARGS" "$DIRNAME" | "$XARGS" "$DIRNAME" | "$XARGS" "$DIRNAME"`
if [ ! -d "$JAVA_LOCATION/bin" ]; then
JAVA_LOCATION="$JAVA_LOCATION/jre"
fi
;;
*)
JAVA_LOCATION=`echo "$JAVA_LOCATION" | "$XARGS" "$DIRNAME" | "$XARGS" "$DIRNAME"`
;;
esac
if [ -z "$JDK" ]; then
JDK_PATH=`which java`
if [ -n "$JDK_PATH" ]; then
if [ "$OS_TYPE" = "FreeBSD" -o "$OS_TYPE" = "MidnightBSD" ]; then
JAVA_LOCATION=`JAVAVM_DRYRUN=yes java | "$GREP" '^JAVA_HOME' | "$CUT" -c11-`
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
elif [ "$OS_TYPE" = "SunOS" ]; then
JAVA_LOCATION="/usr/jdk/latest"
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
elif [ "$OS_TYPE" = "Darwin" ]; then
JAVA_LOCATION=`/usr/libexec/java_home`
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
fi
fi
if [ -z "$JDK" -a -x "$READLINK" -a -x "$XARGS" -a -x "$DIRNAME" ]; then
JAVA_LOCATION=`"$READLINK" -f "$JDK_PATH"`
case "$JAVA_LOCATION" in
*/jre/bin/java)
JAVA_LOCATION=`echo "$JAVA_LOCATION" | "$XARGS" "$DIRNAME" | "$XARGS" "$DIRNAME" | "$XARGS" "$DIRNAME"`
if [ ! -d "$JAVA_LOCATION/bin" ]; then
JAVA_LOCATION="$JAVA_LOCATION/jre"
fi
;;
*)
JAVA_LOCATION=`echo "$JAVA_LOCATION" | "$XARGS" "$DIRNAME" | "$XARGS" "$DIRNAME"`
;;
esac
if [ -x "$JAVA_LOCATION/bin/java" ]; then
JDK="$JAVA_LOCATION"
fi
fi
fi
JAVA_BIN="$JDK/bin/java"
if [ ! -x "$JAVA_BIN" ]; then
JAVA_BIN="$JDK/jre/bin/java"
fi
if [ -z "$JDK" ] || [ ! -x "$JAVA_BIN" ]; then
if [ -z "$JDK" -o ! -x "$JAVA_BIN" ]; then
message "No JDK found. Please validate either @@product_uc@@_JDK, JDK_HOME or JAVA_HOME environment variable points to valid JDK installation."
exit 1
fi
+3 -2
View File
@@ -35,9 +35,10 @@ IF NOT "%JDK%" == "" (
IF EXIST "%IDE_HOME%\jre64" SET JDK=%IDE_HOME%\jre64
IF EXIST "%JDK%" GOTO check
IF EXIST "%IDE_HOME%\jre32" SET JDK=%IDE_HOME%\jre32
IF EXIST "%JDK%" GOTO check
IF EXIST "%IDE_HOME%\jre" SET JDK=%IDE_HOME%\jre
IF EXIST "%JDK%" GOTO check
IF EXIST "%JDK_HOME%" SET JDK=%JDK_HOME%
IF EXIST "%JDK%" GOTO check
@@ -49,7 +50,7 @@ SET JAVA_EXE=%JDK%\bin\java.exe
IF NOT EXIST "%JAVA_EXE%" SET JAVA_EXE=%JDK%\jre\bin\java.exe
IF NOT EXIST "%JAVA_EXE%" (
ECHO ERROR: cannot start IntelliJ IDEA.
ECHO No JDK found. Please validate either IDEA_JDK, JDK_HOME or JAVA_HOME points to valid JDK installation.
ECHO No JDK found. Please validate either @@product_uc@@_JDK, JDK_HOME or JAVA_HOME points to valid JDK installation.
ECHO
EXIT /B
)
+7 -10
View File
@@ -37,16 +37,13 @@
<target name="init">
<mkdir dir="${out.dir}"/>
<mkdir dir="${tmp.dir}"/>
<java classname="org.apache.tools.ant.Main" fork="true" failonerror="true" dir="${project.home}">
<sysproperty key="gant.script" value="${project.home}/build/scripts/download_kotlin.gant"/>
<classpath>
<fileset dir="${project.home}/lib/ant/lib">
<include name="*.jar"/>
</fileset>
</classpath>
<arg value="-f"/>
<arg value="${project.home}/build/gant.xml"/>
</java>
<condition property="gradle.executable" value="${project.home}/build/dependencies/gradlew.bat"
else="${project.home}/build/dependencies/gradlew">
<os family="windows"/>
</condition>
<exec executable="${gradle.executable}" dir="${project.home}/build/dependencies" failonerror="true">
<arg value="setupKotlin"/>
</exec>
</target>
<macrodef name="call_gant">
+1
View File
@@ -5,6 +5,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/scripts" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/groovy" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/dependencies/build" />
<excludeFolder url="file://$MODULE_DIR$/jdk" />
<excludeFolder url="file://$MODULE_DIR$/restApiDocGenerator/node_modules" />
</content>
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright 2000-2016 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.
*/
buildscript {
repositories {
maven { url "http://repo.labs.intellij.net/plugins-gradle-org/" }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "de.undercouch:gradle-download-task:3.2.0"
}
}
apply plugin: 'idea'
idea {
module {
inheritOutputDirs true
}
}
apply plugin: "de.undercouch.download"
apply plugin: 'base'
group 'com.intellij.build'
version '1.0'
try {
project.ext.inJetBrainsNetwork = InetAddress.getByName("repo.labs.intellij.net").isReachable(300)
}
catch (UnknownHostException ignore) {
project.ext.inJetBrainsNetwork = false
}
apply from: 'setupJdk.gradle'
apply from: 'setupJbre.gradle'
apply from: 'setupKotlin.gradle'
apply from: 'setupJetSign.gradle'
task setupDependencies(dependsOn: ['setupJdks', 'setupJbre', 'setupKotlinPlugin', 'setupJetSign'], group: 'dependencies')
clean.dependsOn('cleanSetupJdks', 'cleanSetupJbre', 'cleanSetupKotlinPlugin', 'cleanSetupJetSign')
task wrapper(type: Wrapper) {
// 2.14 is the latest version supports Java 6 (which is still present on TeamCity build agents)
gradleVersion = '2.14'
}
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="dependencies" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="com.intellij.build" external.system.module.version="1.0" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+5
View File
@@ -0,0 +1,5 @@
#The file might be automatically updated. Comments and empty lines will be removed.
#Sat Apr 01 15:26:37 MSK 2017
kotlinPluginBuild=1.1.1-release-IJ2017.1-1
jetSignBuild=42.30
jdkBuild=u112b809.1
Binary file not shown.
@@ -0,0 +1,6 @@
#Fri Feb 17 14:30:05 MSK 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-all.zip
Vendored Executable
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
+84
View File
@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2016 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.
@@ -13,13 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jps.classFilesIndex.indexer.api;
/**
* @author Dmitry Batkovich
*/
public interface ClassFileIndexerFactory<K, V> {
ClassFileIndexer<K, V> create();
}
rootProject.name = 'dependencies'
+100
View File
@@ -0,0 +1,100 @@
task setupJbre {}
def jdkRepo = inJetBrainsNetwork ? 'http://repo.labs.intellij.net/intellij-jdk' : 'https://dl.bintray.com/jetbrains/intellij-jdk'
jrePlatformsToDownload(targetOs).each { platform ->
archToDownload(platform).each { arch ->
def jbrexArtifactName = "jbrex8${jdkBuild}_${platform}_$arch"
def jbreArtifactName = "jbre8${jdkBuild}_${platform}_$arch"
task("downloadJbrex_${platform}_$arch") {
def outputDir = "$project.buildDir/jbre"
def outputFile = "$outputDir/${jbrexArtifactName}_origin.tar.gz"
inputs.property('build', jdkBuild)
outputs.file(outputFile)
doLast {
logger.info("Downloading $jbrexArtifactName to $outputFile")
download {
src "$jdkRepo/${jbrexArtifactName}.tar.gz"
dest outputFile
onlyIfNewer true
}
}
}
cleanSetupJbre.dependsOn("cleanDownloadJbrex_${platform}_$arch")
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
task("untarJbrex_${platform}_$arch", type: Copy, dependsOn: "downloadJbrex_${platform}_$arch") {
def downloadOutputs = tasks["downloadJbrex_${platform}_$arch"].outputs.files
from tarTree(downloadOutputs.singleFile)
into { "${downloadOutputs.singleFile.parent}/${downloadOutputs.singleFile.name - '.tar.gz'}/" }
rename('lib/tools.jar', 'jre/lib/tools.jar')
}
}
else {
task("untarJbrex_${platform}_$arch", type: Exec, dependsOn: "downloadJbrex_${platform}_$arch") {
def downloadOutputs = tasks["downloadJbrex_${platform}_$arch"].outputs.files
def outputDir = "${downloadOutputs.singleFile.absolutePath - '.tar.gz'}"
inputs.file(downloadOutputs.singleFile)
outputs.dir(outputDir)
doFirst { exec { commandLine 'mkdir', '-p', outputDir } }
commandLine 'tar', '-xpf', "${downloadOutputs.singleFile.absolutePath}", '--directory', outputDir
if (platform != 'osx') {
doLast { exec { commandLine 'mv', "$outputDir/lib/tools.jar", "$outputDir/jre/lib/" } }
}
}
}
cleanSetupJbre.dependsOn("cleanUntarJbrex_${platform}_$arch")
createTarJbreTask("tarJbrex_${platform}_$arch", "untarJbrex_${platform}_$arch", platform, jbrexArtifactName, true)
createTarJbreTask("tarJbre_${platform}_$arch", "untarJbrex_${platform}_$arch", platform, jbreArtifactName, false)
setupJbre.dependsOn("tarJbre_${platform}_$arch", "tarJbrex_${platform}_$arch")
cleanSetupJbre.dependsOn("cleanTarJbre_${platform}_$arch", "cleanTarJbrex_${platform}_$arch")
}
}
def createTarJbreTask(String taskName, String untarTaskName, String platform, String archiveName, boolean includeToolsJar) {
def dirToTar = platform == 'osx' ? 'jdk' : 'jre'
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
task(taskName, type: Tar) {
def untarOutputs = tasks[untarTaskName].outputs.files
from "$untarOutputs.singleFile/$dirToTar"
if (!includeToolsJar) {
exclude "**/tools.jar"
}
compression = Compression.GZIP
archiveName = "${archiveName}.tar.gz"
destinationDir = untarOutputs.singleFile.parentFile
}
}
else {
task(taskName, type: Exec) {
def untarOutputs = tasks[untarTaskName].outputs.files
def outputFile = "${untarOutputs.singleFile.parentFile}/${archiveName}.tar.gz"
inputs.files(untarOutputs)
outputs.file(outputFile)
def arguments = ['tar', '-czf', outputFile, '-C', untarOutputs.singleFile.absolutePath]
if (!includeToolsJar) {
arguments += ['--exclude', "**/tools.jar"]
}
arguments += [dirToTar]
commandLine arguments
}
}
}
// see org.jetbrains.intellij.build.BuildOptions.targetOS
static def jrePlatformsToDownload(targetOs) {
def jrePlatformToDownload = new HashSet<String>()
if (targetOs == 'all' || targetOs == 'linux') jrePlatformToDownload.add('linux')
if (targetOs == 'all' || targetOs == 'windows') jrePlatformToDownload.add('windows')
if (targetOs == 'all' || targetOs == 'mac') jrePlatformToDownload.add('osx')
jrePlatformToDownload
}
static def archToDownload(targetOs) {
targetOs == 'windows' ? ['x86', 'x64'] : ['x64']
}
+141
View File
@@ -0,0 +1,141 @@
/*
* Copyright 2000-2016 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.
*/
task setupJdks(dependsOn: ['setupJdk18', 'setupJdk16'])
cleanSetupJdks.dependsOn('cleanSetupJdk18', 'cleanSetupJdk16', 'cleanDownloadJdk18')
def jdkRepo = inJetBrainsNetwork ? 'http://repo.labs.intellij.net' : 'https://dl.bintray.com/jetbrains/'
def checkoutDir = intellijProjectDir()
def jdkDir = "$checkoutDir/build/jdk"
project.ext.jdk18OutputDir = "${System.getProperty("intellij.jdk18.output.dir", "$jdkDir/1.8")}"
project.ext.targetOs = "${System.getProperty("intellij.build.target.os", "all")}"
task downloadJdk18 {
def os = org.gradle.internal.os.OperatingSystem.current()
def arch = !os.isWindows() || !os.nativePrefix.endsWith('x86') ? 'x64' : 'x86'
def platform = currentPlatformName()
def artifactName = "jbsdk8${jdkBuild}_${platform}_${arch}.tar.gz"
def outputFile = "$project.buildDir/jbsdk/${artifactName}"
inputs.property('build', jdkBuild)
outputs.file(outputFile)
doLast {
logger.info("Downloading up JDK 1.8 to compile (using $jdkRepo repo)")
download {
src "$jdkRepo/intellij-jdk/${artifactName}"
dest outputFile
onlyIfNewer true
}
}
}
task setupJdk18(dependsOn: downloadJdk18) {
def outputDir = jdk18OutputDir
def downloadOutputs = downloadJdk18.outputs.files
inputs.files(downloadOutputs)
inputs.property("jdk18OutputDir", outputDir)
outputs.dir(outputDir)
doLast {
logger.info("Setting up JDK 1.8 to compile")
unpackJdk(downloadOutputs.singleFile, outputDir)
}
}
def unpackJdk(jdkArchive, outputDir) {
logger.info("Unpacking $jdkArchive to ${outputDir}")
file(outputDir).deleteDir()
def currentOs = org.gradle.internal.os.OperatingSystem.current()
if (currentOs.isWindows()) {
copy {
from tarTree(jdkArchive)
into outputDir
}
}
else {
exec { commandLine 'mkdir', '-p', outputDir }
exec { commandLine 'tar', 'xpf', "$jdkArchive.absolutePath", '--directory', outputDir }
def jdkContents = file("${outputDir}/jdk/Contents")
if (currentOs.isMacOsX() && jdkContents.exists()) {
jdkContents.listFiles().each { file ->
exec { commandLine 'mv', "$file.absolutePath", outputDir }
}
}
}
}
static def currentPlatformName() {
def os = org.gradle.internal.os.OperatingSystem.current()
if (os.isWindows()) {
"windows"
}
else if (os.isMacOsX()) {
"osx"
}
else {
"linux"
}
}
// JDK 1.6
repositories {
maven {
url 'http://repo.labs.intellij.net/java'
}
}
configurations {
jdk16
}
dependencies {
jdk16 "jetbrains:jre:${jdk16Version()}@tar.gz"
}
task setupJdk16(dependsOn: configurations.jdk16) {
if (!inJetBrainsNetwork) {
return
}
def jdkArchive = { configurations.jdk16.singleFile }
def outputDir = "$jdkDir/1.6"
inputs.file(jdkArchive)
outputs.dir(outputDir)
doLast {
logger.info("Setting up JDK 1.6 to compile")
unpackJdk(jdkArchive.call(), outputDir)
}
}
def intellijProjectDir() {
def communityDir = project.file("../..")
communityDir.name == 'community' ? communityDir.parent : communityDir
}
static def jdk16Version() {
def os = org.gradle.internal.os.OperatingSystem.current()
if (os.isWindows()) {
def suffix = os.nativePrefix.endsWith('x86') ? "_i586" : "x64"
return "6.45:windows_$suffix"
}
else if (os.isMacOsX()) {
return '6.65:macosx_x64'
}
return '6.45:linux_x64'
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2016 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.
*/
repositories {
maven {
url 'http://repo.labs.intellij.net/jet-sign'
}
}
configurations {
jetSign
}
dependencies {
jetSign "com.jetbrains:jet-sign:${jetSignBuild}"
}
task setupJetSign(dependsOn: configurations.jetSign) {
if (!inJetBrainsNetwork) {
return
}
def ultimateProjectDir = ultimateProjectDir()
if (!ultimateProjectDir) {
return
}
doFirst { logger.info("Setting up JetSign") }
def jetSignJar = { configurations.jetSign.singleFile }
def outputDir = file("$ultimateProjectDir/build/lib/")
inputs.file(jetSignJar)
outputs.file("$outputDir/jet-sign.jar")
doLast {
logger.info("Copying $jetSignJar to $outputDir")
copy {
from file(jetSignJar)
into outputDir
rename '.+\\.jar', 'jet-sign.jar'
}
}
}
def ultimateProjectDir() {
def communityDir = project.file("../..")
communityDir.name == 'community' ? communityDir.parent : null
}
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2016 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.
*/
repositories {
maven {
url 'http://repo.labs.intellij.net/plugins.jetbrains.com'
}
maven {
url 'http://plugins.jetbrains.com/maven/'
}
}
configurations {
kotlinPlugin
}
dependencies {
kotlinPlugin "com.jetbrains.plugins:org.jetbrains.kotlin:$kotlinPluginBuild@zip"
}
task setupKotlinPlugin(dependsOn: configurations.kotlinPlugin) {
def kotlinPluginArchive = { configurations.kotlinPlugin.singleFile }
inputs.file(kotlinPluginArchive)
def outputDir = project.buildDir
outputs.dir("$outputDir/Kotlin")
doFirst { logger.info("Setting up Kotlin") }
doLast {
logger.info("Unpack ${kotlinPluginArchive.call()} to $outputDir")
copy {
from zipTree(kotlinPluginArchive.call())
into outputDir
}
}
}
+3 -3
View File
@@ -21,14 +21,14 @@
<pathelement path="${project.home}/platform/build-scripts/groovy"/>
<pathelement path="${project.home}/build/groovy"/>
<fileset file="${project.home}/jps/lib/optimizedFileManager.jar"/>
<fileset dir="${project.home}/build/kotlinc/jps" erroronmissingdir="false" if:true="${include.kotlin.jars.to.classpath}">
<fileset dir="${project.home}/build/dependencies/build/Kotlin/lib/jps" erroronmissingdir="false" if:true="${include.kotlin.jars.to.classpath}">
<include name="*.jar"/>
</fileset>
<fileset dir="${project.home}/build/kotlinc/lib" erroronmissingdir="false" if:true="${include.kotlin.jars.to.classpath}">
<fileset dir="${project.home}/build/dependencies/build/Kotlin/kotlinc/lib" erroronmissingdir="false" if:true="${include.kotlin.jars.to.classpath}">
<include name="kotlin-runtime.jar"/>
<include name="kotlin-reflect.jar"/>
</fileset>
<fileset dir="${project.home}/build/kotlinc/plugin/Kotlin/lib" erroronmissingdir="false" if:true="${include.kotlin.jars.to.classpath}">
<fileset dir="${project.home}/build/dependencies/build/Kotlin/lib" erroronmissingdir="false" if:true="${include.kotlin.jars.to.classpath}">
<include name="kotlin-plugin.jar"/>
</fileset>
<fileset dir="${idea.lib}">
@@ -128,7 +128,7 @@ abstract class BaseIdeaProperties extends ProductProperties {
}
}
context.ant.copy(todir: "$targetDirectory/plugins/Kotlin") {
fileset(dir: "$context.paths.communityHome/build/kotlinc/plugin/Kotlin")
fileset(dir: "$context.paths.communityHome/build/dependencies/build/Kotlin")
}
context.ant.move(file: "$targetDirectory/lib/annotations-java8.jar", tofile: "$targetDirectory/redist/annotations-java8.jar")
}
-111
View File
@@ -1,111 +0,0 @@
/*
* Copyright 2000-2017 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 static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant")
requireProperty("out", "$home/out")
target(compile: "Compile project") {
ant.delete(failonerror: false) {
fileset(dir: "$home/reports")
fileset(dir: "$home/bin", includes: "*.hprof")
}
loadProject()
prepareOutputFolder()
if (System.getProperty("tests.only")) {
ant.delete(dir: "$home/out")
ant.unzip(src: "$home/out.zip", dest: "$home/out")
return
}
if (!isDefined("avoid.project.rebuild")) {
projectBuilder.cleanOutput()
projectBuilder.buildAll()
}
}
private pass(List<String> args, String prop) {
if (isDefined(prop)) {
args << "-D$prop=${p(prop)}"
}
}
target('run_tests': 'Run java tests') {
depends([compile])
def classpathFile = "$home/junit.classpath"
//todo[nik] currently runtime classpath includes path to JDKs from all modules in it so we need to manually exclude paths from JDK 1.6
List<String> testRuntimeClasspath = removeJdkJarFiles(projectBuilder.moduleRuntimeClasspath(findModule("community-main"), true))
testRuntimeClasspath << "${jdk8Home}/lib/tools.jar"
projectBuilder.info("Test runtime classpath=" + testRuntimeClasspath)
new File(classpathFile).text = testRuntimeClasspath.findAll({ new File((String)it).exists() }).join('\n')
List<String> bootstrapClasspath = removeJdkJarFiles(projectBuilder.moduleRuntimeClasspath(findModule("tests_bootstrap"), false))
bootstrapClasspath << "${jdk8Home}/lib/tools.jar"
projectBuilder.info("Bootstrap classpath=" + bootstrapClasspath)
testcases.each { testCase ->
List<String> jvmArgs = [
"-Dclasspath.file=${classpathFile}",
"-Didea.platform.prefix=Idea",
"-Dbootstrap.testcases=$testCase"
]
[
"idea.test.group",
"idea.test.patterns",
"idea.coverage.enabled.build",
"teamcity.tests.recentlyFailedTests.file"
].each { pass(jvmArgs, it) }
def tempDir = p("teamcity.build.tempDir", p("java.io.tmpdir"))
jvmArgs << "-Djava.io.tmpdir=${tempDir}"
jvmArgs << "-Dteamcity.build.tempDir=${tempDir}"
System.getProperties().entrySet().each {
if (it.key.startsWith("pass.")) {
def trimmed = it.key.substring("pass.".length());
jvmArgs << "-D${trimmed}=${it.value}"
};
}
jvmArgs.addAll(commonJvmArgsForTests())
if (isDefined("jvm_args")) {
jvmArgs.addAll(jvm_args)
}
projectBuilder.info("Starting JUnit $testCase, JVM options: $jvmArgs")
ant.junit(fork: "yes", showoutput: "true", logfailedtests: false) {
jvmArgs.each {
jvmarg(value: it)
}
classpath {
bootstrapClasspath.each {
pathelement(location: it)
}
}
test(name: 'com.intellij.tests.BootstrapTests')
}
}
}
target('default' : "Run all tests") {
depends([compile, run_tests])
}
-39
View File
@@ -1,39 +0,0 @@
/*
* Copyright 2000-2015 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 static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
def home = guessHome(this)
includeTargets << new File("${home}/build/scripts/common_tests.gant")
def args = []
def mem = System.getProperty("test.jvm.memory")
if (mem != null) {
args.addAll(mem.split())
}
else {
args += [
"-Xmx450m",
"-Dsun.io.useCanonCaches=false"
]
}
args << "-Djna.nosys=true"
setProperty("jvm_args", args)
setProperty("testcases", ["com.intellij.AllTests"])
+16 -76
View File
@@ -1,9 +1,5 @@
import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.util.io.FileUtilRt
import org.apache.tools.ant.BuildException
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -19,79 +15,23 @@ import org.apache.tools.ant.BuildException
*/
target(default: "Unpack JDKs") {
unpackJdks()
def workingDirectory = getDependenciesProjectDir()
def gradleScript = System.getProperty('os.name').toLowerCase().contains('windows') ? "gradlew.bat" : "gradlew"
def process = new ProcessBuilder("${workingDirectory.absolutePath}/$gradleScript", 'setupJdks', '--stacktrace', '--info')
.directory(workingDirectory)
.start()
process.consumeProcessOutputStream((OutputStream)System.out)
process.consumeProcessErrorStream((OutputStream)System.err)
process.waitFor()
if (process.exitValue() != 0) {
projectBuilder.error("Cannot unpack JDK")
}
}
def unpackJdks() {
private File getDependenciesProjectDir() {
String home = guessHome(this)
def osDirName = SystemInfoRt.isWindows ? "win" : SystemInfoRt.isMac ? "mac" : "linux"
String basePath
if (new File(home).getName().equals("community")) {
basePath = new File(home).getParent()
}
else {
basePath = home
}
def jdkDir = new File(basePath, "build/jdk")
def osDir = new File(jdkDir, osDirName)
if (!osDir.isDirectory()) {
ant.project.log("Cannot unpack JDK: $osDir not found")
return
}
unpackJdk(osDir, jdkDir, "jre6", "1.6")
unpackJdk(osDir, jdkDir, "jbsdk8", "1.8")
}
private void unpackJdk(File osDir, File jdkDir, String archiveFileNamePrefix, String targetDirectoryName) {
def jdkFiles = osDir.listFiles().findAll { it.name.startsWith(archiveFileNamePrefix) }
if (SystemInfoRt.isWindows) {
def arch = System.getenv("ProgramFiles(x86)") != null ? "x64" : "x86"
jdkFiles = jdkFiles.findAll { it.name.endsWith("_${arch}.tar.gz") }
}
if (SystemInfoRt.isLinux) {
jdkFiles = jdkFiles.findAll { it.name.endsWith("64.tar.gz") }
}
if (jdkFiles.empty) {
throw new BuildException("Cannot unpack JDK: $archiveFileNamePrefix not found in $osDir")
}
if (jdkFiles.size() > 1) {
throw new BuildException("Cannot unpack JDK: several matching files are found ($jdkFiles)")
}
File jdkFile = jdkFiles.first()
def destDir = new File(jdkDir, targetDirectoryName)
FileUtilRt.delete(destDir)
ant.project.log("Extracting $jdkFile to $destDir")
ant.mkdir(dir: destDir)
if (jdkFile.name.endsWith(".tar.gz")) {
if (SystemInfoRt.isWindows) {
ant.untar(src: jdkFile, dest: destDir, compression: 'gzip')
}
else {
//'tar' and 'mv' commands are used instead of Ant tasks to ensure that executable flag and symlink will be preserved
ant.exec(executable: "tar", dir: jdkFile.getParent()) {
arg(value: "-xf")
arg(value: jdkFile.name)
arg(value: "--directory")
arg(value: destDir)
}
def jdkContents = new File(destDir, "jdk/Contents")
if (SystemInfoRt.isMac && jdkContents.exists()) {
jdkContents.listFiles().each { file ->
ant.exec(executable: "mv", dir: destDir) {
arg(value: file.absolutePath)
arg(value: destDir)
}
}
}
}
}
else {
throw new BuildException("Cannot unpack JDK: unknown extension of file '${jdkFile.name}'")
}
File community = new File(home, 'community')
return new File(community.exists() ? community : new File(home), "build/dependencies")
}
static String guessHome(Script script) {
@@ -106,4 +46,4 @@ static String guessHome(Script script) {
}
return null
}
}
+49 -5
View File
@@ -17,6 +17,7 @@
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.intellij.build.impl.BuildUtils
import org.jetbrains.jps.gant.JpsGantTool
import org.jetbrains.jps.gant.TeamCityBuildInfoPrinter
import org.jetbrains.jps.model.java.JdkVersionDetector
@@ -35,7 +36,7 @@ binding.setVariable("p", {String key, String defaultValue = null ->
if (defaultValue != null) {
return defaultValue
}
throw e;
throw e
}
})
@@ -106,15 +107,20 @@ binding.setVariable("guessHome", {
binding.setVariable("loadProject", {
defineJdk("IDEA jdk", setupJdkPath("jdkHome", "$home/build/jdk/1.6", "JDK_16_x64"))
defineJdk("1.8", setupJdkPath("jdk8Home", "$home/build/jdk/1.8", "JDK_18_x64"))
def bundledKotlinPath = "$home/build/kotlinc"
setupKotlin()
def bundledKotlinPath = "$home/build/dependencies/build/Kotlin/kotlinc"
if (!new File(bundledKotlinPath, "lib/kotlin-runtime.jar").exists()) {
bundledKotlinPath = "$home/community/build/kotlinc"
bundledKotlinPath = "$home/community/build/dependencies/build/Kotlin/kotlinc"
}
if (!new File(bundledKotlinPath, "lib/kotlin-runtime.jar").exists()) {
projectBuilder.error("Could not find Kotlin runtime at $bundledKotlinPath/lib/kotlin-runtime.jar: run download_kotlin.gant script to download Kotlin JARs")
projectBuilder.error("Could not find Kotlin runtime at $bundledKotlinPath/lib/kotlin-runtime.jar: run `./gradlew setupKotlin` in dependencies module to download Kotlin JARs")
return
}
setPathVariable("KOTLIN_BUNDLED", bundledKotlinPath)
if (!ensureKotlinCompilerAddedToClassPath()) {
return
}
projectBuilder.buildIncrementally = Boolean.parseBoolean(p("jps.build.incrementally", "false"))
def dataDirName = projectBuilder.buildIncrementally ? ".jps-incremental-build" : ".jps-build-data"
projectBuilder.dataStorageRoot = new File("$home/$dataDirName")
@@ -136,6 +142,44 @@ binding.setVariable("removeJdkJarFiles", { Collection<String> classpath ->
return classpath.findAll { jarPath -> jdkHomePaths.every { !FileUtil.isAncestor(it, jarPath, false) } }
})
private void setupKotlin() {
def workingDirectory = getDependenciesProjectDir()
def gradleScript = System.getProperty('os.name').toLowerCase().contains('windows') ? "gradlew.bat" : "gradlew"
def process = new ProcessBuilder("${workingDirectory.absolutePath}/$gradleScript", 'setupKotlinPlugin', '--stacktrace', '--info')
.directory(workingDirectory)
.start()
process.consumeProcessOutputStream((OutputStream)System.out)
process.consumeProcessErrorStream((OutputStream)System.err)
process.waitFor()
}
private boolean ensureKotlinCompilerAddedToClassPath() {
try {
Class.forName("org.jetbrains.kotlin.jps.build.KotlinBuilder")
return
}
catch (ClassNotFoundException ignored) {
}
def kotlinPluginLibPath = "$home/build/dependencies/build/Kotlin/lib"
if (!new File(kotlinPluginLibPath).exists()) {
kotlinPluginLibPath = "$home/community/build/dependencies/build/Kotlin/lib"
}
if (!new File(kotlinPluginLibPath, "kotlin-runtime.jar").exists()) {
projectBuilder.error("Could not find Kotlin JARs at $kotlinPluginLibPath: run `./gradlew setupKotlin` in dependencies module " +
"to download Kotlin JARs")
return false
}
["jps/kotlin-jps-plugin.jar", "kotlin-plugin.jar", "kotlin-runtime.jar", "kotlin-reflect.jar"].each {
BuildUtils.addToJpsClassPath("$kotlinPluginLibPath/$it", ant)
}
return true
}
private File getDependenciesProjectDir() {
return new File(home, new File(home).name == "community" ? "build/dependencies" : "community/build/dependencies")
}
private String setupJdkPath(String propertyName, String defaultDir, String envVarName) {
try {
this[propertyName]
@@ -308,7 +352,7 @@ binding.setVariable("forceDelete", { String dirPath ->
})
binding.setVariable("collectUsedJars", { List modules, List approvedJars, List forbiddenJars, List modulesToBuild ->
def usedJars = new HashSet();
def usedJars = new HashSet()
modules.each {
def module = findModule(it)
+7 -13
View File
@@ -25,19 +25,13 @@
<attribute name="deploy"/>
<sequential>
<java classname="org.apache.tools.ant.Main" fork="true" failonerror="true" dir="${project.home}">
<sysproperty key="workIdeaHome" value="${work.idea.home}"/>
<sysproperty key="modulesOutput" value="${modules.output}"/>
<sysproperty key="gant.script" value="${project.home}/build/scripts/download_kotlin.gant"/>
<sysproperty key="include.kotlin.jars.to.classpath" value="false"/>
<classpath>
<fileset dir="${project.home}/lib/ant/lib">
<include name="*.jar"/>
</fileset>
</classpath>
<arg value="-f"/>
<arg value="${project.home}/build/gant.xml"/>
</java>
<condition property="gradle.executable" value="${project.home}/build/dependencies/gradlew.bat"
else="${project.home}/build/dependencies/gradlew">
<os family="windows"/>
</condition>
<exec executable="${gradle.executable}" dir="${project.home}/build/dependencies" failonerror="true">
<arg value="setupKotlin"/>
</exec>
<java failonerror="true" classname="org.apache.tools.ant.Main" fork="true">
<jvmarg line="-Xms64m -Xmx512m"/>
<jvmarg line="&quot;-Ddeploy=@{deploy}&quot;"/>
@@ -41,9 +41,9 @@ class CompilerHierarchyInfoImpl implements CompilerDirectHierarchyInfo {
private final Project myProject;
private final FileType mySearchFileType;
private final CompilerHierarchySearchType mySearchType;
private final Map<VirtualFile, Object[]> myCandidatePerFile;
private final Map<VirtualFile, SearchId[]> myCandidatePerFile;
CompilerHierarchyInfoImpl(Map<VirtualFile, Object[]> candidatesPerFile,
CompilerHierarchyInfoImpl(Map<VirtualFile, SearchId[]> candidatesPerFile,
PsiNamedElement baseClass,
GlobalSearchScope dirtyScope,
GlobalSearchScope searchScope,
@@ -63,14 +63,14 @@ class CompilerHierarchyInfoImpl implements CompilerDirectHierarchyInfo {
@NotNull
public Stream<PsiElement> getHierarchyChildren() {
PsiManager psiManager = PsiManager.getInstance(myProject);
final LanguageLightRefAdapter adapter = ObjectUtils.notNull(CompilerReferenceServiceImpl.findAdapterForFileType(mySearchFileType));
final LanguageLightRefAdapter adapter = ObjectUtils.notNull(LanguageLightRefAdapter.findAdapter(mySearchFileType));
return myCandidatePerFile
.entrySet()
.stream()
.filter(e -> mySearchScope.contains(e.getKey()))
.flatMap(e -> {
final VirtualFile file = e.getKey();
final Object[] definitions = e.getValue();
final SearchId[] definitions = e.getValue();
final PsiElement[] hierarchyChildren = ReadAction.compute(() -> {
final PsiFileWithStubSupport psiFile = (PsiFileWithStubSupport)psiManager.findFile(file);
@@ -26,11 +26,11 @@ import java.util.Collection;
enum CompilerHierarchySearchType {
DIRECT_INHERITOR {
@Override
PsiElement[] performSearchInFile(Object[] definitions,
PsiElement[] performSearchInFile(SearchId[] definitions,
PsiNamedElement baseElement,
PsiFileWithStubSupport file,
LanguageLightRefAdapter adapter) {
return adapter.findDirectInheritorCandidatesInFile((String[])definitions, file, baseElement);
return adapter.findDirectInheritorCandidatesInFile(definitions, file);
}
@Override
@@ -39,17 +39,19 @@ enum CompilerHierarchySearchType {
}
@Override
Object[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator) {
return lightRef.stream().map(r -> nameEnumerator.getName(((LightRef.LightClassHierarchyElementDef)r).getName())).toArray(String[]::new);
SearchId[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator) {
return lightRef.stream().map(r -> r instanceof LightRef.JavaLightAnonymousClassRef
? new SearchId(((LightRef.JavaLightAnonymousClassRef)r).getName())
: new SearchId(nameEnumerator.getName(((LightRef.LightClassHierarchyElementDef)r).getName()))).toArray(SearchId[]::new);
}
},
FUNCTIONAL_EXPRESSION {
@Override
PsiElement[] performSearchInFile(Object[] definitions,
PsiElement[] performSearchInFile(SearchId[] definitions,
PsiNamedElement baseElement,
PsiFileWithStubSupport file,
LanguageLightRefAdapter adapter) {
return adapter.findFunExpressionsInFile((Integer[])definitions, file);
return adapter.findFunExpressionsInFile(definitions, file);
}
@Override
@@ -58,17 +60,18 @@ enum CompilerHierarchySearchType {
}
@Override
Object[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator) {
return lightRef.stream().map(r -> ((LightRef.LightFunExprDef) r).getId()).toArray(Integer[]::new);
SearchId[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator) {
return lightRef.stream().map(r -> ((LightRef.LightFunExprDef) r).getId()).map(SearchId::new).toArray(SearchId[]::new);
}
};
abstract PsiElement[] performSearchInFile(Object[] definitions,
abstract PsiElement[] performSearchInFile(SearchId[] definitions,
PsiNamedElement baseElement,
PsiFileWithStubSupport file,
LanguageLightRefAdapter adapter);
abstract Class<? extends LightRef> getRequiredClass(LanguageLightRefAdapter adapter);
abstract Object[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator);
abstract SearchId[] convertToIds(Collection<LightRef> lightRef, NameEnumerator nameEnumerator);
}
@@ -24,15 +24,17 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.Queue;
import com.intellij.util.indexing.InvertedIndexUtil;
import com.intellij.util.indexing.StorageException;
import com.intellij.util.indexing.ValueContainer;
import gnu.trove.THashSet;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.backwardRefs.NameEnumerator;
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex;
import org.jetbrains.jps.backwardRefs.LightRef;
import org.jetbrains.jps.backwardRefs.NameEnumerator;
import org.jetbrains.jps.backwardRefs.SignatureData;
import org.jetbrains.jps.backwardRefs.index.CompilerIndices;
import java.io.File;
@@ -74,17 +76,17 @@ class CompilerReferenceReader {
* 2nd map: candidates. One need to check that these classes are really direct inheritors
*/
@NotNull
Map<VirtualFile, Object[]> getDirectInheritors(@NotNull LightRef searchElement,
Map<VirtualFile, SearchId[]> getDirectInheritors(@NotNull LightRef searchElement,
@NotNull GlobalSearchScope searchScope,
@NotNull GlobalSearchScope dirtyScope,
@NotNull FileType fileType,
@NotNull CompilerHierarchySearchType searchType) throws StorageException {
GlobalSearchScope effectiveSearchScope = GlobalSearchScope.notScope(dirtyScope).intersectWith(searchScope);
LanguageLightRefAdapter adapter = CompilerReferenceServiceImpl.findAdapterForFileType(fileType);
LanguageLightRefAdapter adapter = LanguageLightRefAdapter.findAdapter(fileType);
LOG.assertTrue(adapter != null, "adapter is null for file type: " + fileType);
Class<? extends LightRef> requiredLightRefClass = searchType.getRequiredClass(adapter);
Map<VirtualFile, Object[]> candidatesPerFile = new HashMap<>();
Map<VirtualFile, SearchId[]> candidatesPerFile = new HashMap<>();
myIndex.get(CompilerIndices.BACK_HIERARCHY).getData(searchElement).forEach((fileId, defs) -> {
final List<LightRef> requiredCandidates = defs.stream().filter(requiredLightRefClass::isInstance).collect(toList());
if (requiredCandidates.isEmpty()) return true;
@@ -97,6 +99,64 @@ class CompilerReferenceReader {
return candidatesPerFile.isEmpty() ? Collections.emptyMap() : candidatesPerFile;
}
@Nullable
Integer getAnonymousCount(@NotNull LightRef.LightClassHierarchyElementDef classDef, boolean checkDefinitions) {
try {
if (checkDefinitions && hasMultipleDefinitions(classDef)) {
return null;
}
final int[] count = {0};
myIndex.get(CompilerIndices.BACK_HIERARCHY).getData(classDef).forEach(new ValueContainer.ContainerAction<Collection<LightRef>>() {
@Override
public boolean perform(int id, Collection<LightRef> value) {
count[0] += value.size();
return true;
}
});
return count[0];
}
catch (StorageException e) {
throw new RuntimeException(e);
}
}
int getOccurrenceCount(@NotNull LightRef element) {
try {
int[] result = new int[]{0};
myIndex.get(CompilerIndices.BACK_USAGES).getData(element).forEach(
new ValueContainer.ContainerAction<Integer>() {
@Override
public boolean perform(int id, Integer value) {
result[0] += value;
return true;
}
});
return result[0];
}
catch (StorageException e) {
throw new RuntimeException(e);
}
}
@NotNull
List<LightRef> getMembersFor(@NotNull SignatureData data) {
try {
List<LightRef> result = new ArrayList<>();
myIndex.get(CompilerIndices.BACK_MEMBER_SIGN).getData(data).forEach((id, refs) -> {
result.addAll(refs);
return true;
});
return result;
} catch (StorageException e) {
throw new RuntimeException(e);
}
}
@NotNull
TIntHashSet getAllContainingFileIds(@NotNull LightRef ref) throws StorageException {
return InvertedIndexUtil.collectInputIdsContainingAllKeys(myIndex.get(CompilerIndices.BACK_USAGES), Collections.singletonList(ref), null, null, null);
}
@NotNull
NameEnumerator getNameEnumerator() {
return myIndex.getByteSeqEum();
@@ -109,6 +169,10 @@ class CompilerReferenceReader {
}
}
public CompilerBackwardReferenceIndex getIndex() {
return myIndex;
}
static boolean exists(Project project) {
File buildDir = BuildManager.getInstance().getProjectSystemDirectory(project);
if (buildDir == null || CompilerBackwardReferenceIndex.versionDiffers(buildDir)) {
@@ -130,9 +194,9 @@ class CompilerReferenceReader {
private void addUsages(LightRef usage, TIntHashSet sink) throws StorageException {
myIndex.get(CompilerIndices.BACK_USAGES).getData(usage).forEach(
new ValueContainer.ContainerAction<Void>() {
new ValueContainer.ContainerAction<Integer>() {
@Override
public boolean perform(int id, Void value) {
public boolean perform(int id, Integer value) {
final VirtualFile file = findFile(id);
if (file != null) {
sink.add(((VirtualFileWithId)file).getId());
@@ -163,14 +227,7 @@ class CompilerReferenceReader {
LightRef.NamedLightRef curClass = q.pullFirst();
if (result.add(curClass)) {
if (checkBaseClassAmbiguity || curClass != hierarchyElement) {
DefCount count = getDefinitionCount(curClass);
if (count == DefCount.NONE) {
//diagnostic
String baseHierarchyElement = getNameEnumerator().getName(hierarchyElement.getName());
String curHierarchyElement = getNameEnumerator().getName(curClass.getName());
LOG.error("Can't get definition files for: " + curHierarchyElement + " base class: " + baseHierarchyElement);
}
if (count != DefCount.ONE) {
if (hasMultipleDefinitions(curClass)) {
return null;
}
}
@@ -188,8 +245,7 @@ class CompilerReferenceReader {
}
private enum DefCount { NONE, ONE, MANY}
@NotNull
private DefCount getDefinitionCount(LightRef def) throws StorageException {
private boolean hasMultipleDefinitions(LightRef.NamedLightRef def) throws StorageException {
DefCount[] result = new DefCount[]{DefCount.NONE};
myIndex.get(CompilerIndices.BACK_CLASS_DEF).getData(def).forEach(new ValueContainer.ContainerAction<Void>() {
@Override
@@ -205,6 +261,11 @@ class CompilerReferenceReader {
return false;
}
});
return result[0];
if (result[0] == DefCount.NONE) {
//diagnostic
String name = def instanceof LightRef.LightAnonymousClassDef ? String.valueOf(def.getName()) : getNameEnumerator().getName(def.getName());
LOG.error("Can't get definition files for: " + name + ", class: " + def.getClass());
}
return result[0] == DefCount.MANY;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2017 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.compiler.backwardRefs;
import com.intellij.compiler.CompilerReferenceService;
import com.intellij.compiler.chainsSearch.OccurrencesAware;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.backwardRefs.LightRef;
import java.util.SortedSet;
/**
* The service is used for java relevant chain completion
*/
public abstract class CompilerReferenceServiceEx extends CompilerReferenceService {
protected CompilerReferenceServiceEx(Project project) {
super(project);
}
@NotNull
public abstract SortedSet<OccurrencesAware<MethodIncompleteSignature>> findMethodReferenceOccurrences(@NotNull String rawReturnType)
throws ReferenceIndexUnavailableException;
public abstract boolean mayHappen(@NotNull LightRef qualifier, @NotNull LightRef base, int probabilityThreshold)
throws ReferenceIndexUnavailableException;
@NotNull
public abstract String getName(int idx)
throws ReferenceIndexUnavailableException;
}
@@ -16,16 +16,19 @@
package com.intellij.compiler.backwardRefs;
import com.intellij.compiler.CompilerDirectHierarchyInfo;
import com.intellij.compiler.CompilerReferenceService;
import com.intellij.compiler.backwardRefs.view.CompilerReferenceFindUsagesTestInfo;
import com.intellij.compiler.backwardRefs.view.CompilerReferenceHierarchyTestInfo;
import com.intellij.compiler.backwardRefs.view.DirtyScopeTestInfo;
import com.intellij.compiler.chainsSearch.OccurrencesAware;
import com.intellij.compiler.server.BuildManager;
import com.intellij.compiler.server.BuildManagerListener;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.compiler.CompilationStatusListener;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
@@ -57,6 +60,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jps.backwardRefs.LightRef;
import org.jetbrains.jps.backwardRefs.SignatureData;
import java.io.IOException;
import java.util.*;
@@ -69,8 +73,8 @@ import java.util.stream.Stream;
import static com.intellij.psi.search.GlobalSearchScope.getScopeRestrictedByFileTypes;
import static com.intellij.psi.search.GlobalSearchScope.notScope;
public class CompilerReferenceServiceImpl extends CompilerReferenceService implements ModificationTracker {
private final static Logger LOG = Logger.getInstance(CompilerReferenceServiceImpl.class);
public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx implements ModificationTracker {
private static final Logger LOG = Logger.getInstance(CompilerReferenceServiceImpl.class);
private final Set<FileType> myFileTypes;
private final DirtyScopeHolder myDirtyScopeHolder;
@@ -171,9 +175,6 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
PsiModificationTracker.MODIFICATION_COUNT,
this));
}
catch (ProcessCanceledException e) {
throw e;
}
catch (RuntimeException e) {
return onException(e, "scope without code references");
}
@@ -197,6 +198,133 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
return getHierarchyInfo(functionalInterface, useScope, searchScope, searchFileType, CompilerHierarchySearchType.FUNCTIONAL_EXPRESSION);
}
@Nullable
@Override
public Integer getCompileTimeOccurrenceCount(@NotNull PsiElement element, boolean isConstructorSuggestion) {
if (!isServiceEnabledFor(element)) return null;
try {
return CachedValuesManager.getCachedValue(element,
() -> CachedValueProvider.Result.create(new ConcurrentFactoryMap<Boolean, Integer>() {
@Nullable
@Override
protected Integer create(Boolean constructorSuggestion) {
return calculateOccurrenceCount(element, constructorSuggestion.booleanValue());
}
},
PsiModificationTracker.MODIFICATION_COUNT,
this)).get(Boolean.valueOf(isConstructorSuggestion));
}
catch (RuntimeException e) {
return onException(e, "weighting for completion");
}
}
@NotNull
@Override
public SortedSet<OccurrencesAware<MethodIncompleteSignature>> findMethodReferenceOccurrences(@NotNull String rawReturnType) {
try {
myReadDataLock.lock();
if (myReader == null) throw new ReferenceIndexUnavailableException();
try {
final int type = myReader.getNameEnumerator().tryEnumerate(rawReturnType);
if (type == 0) return Collections.emptySortedSet();
return Stream.of(new SignatureData(type, true), new SignatureData(type, false))
.flatMap(sd -> myReader.getMembersFor(sd)
.stream()
.filter(r -> r instanceof LightRef.JavaLightMethodRef)
.map(r -> new OccurrencesAware<>(
new MethodIncompleteSignature((LightRef.JavaLightMethodRef)r, sd, this),
myReader.getOccurrenceCount(r))))
.collect(Collectors.toCollection(TreeSet::new));
}
catch (Exception e) {
//noinspection ConstantConditions
return onException(e, "find methods");
}
} finally {
myReadDataLock.unlock();
}
}
/**
* conditional probability P(ref1 | ref2) = P(ref1 * ref2) / P(ref2) > 1 - 1 / threshold
*
* where P(ref) is a probability that ref is occurred in a file.
*/
@Override
public boolean mayHappen(@NotNull LightRef qualifier, @NotNull LightRef base, int probabilityThreshold) {
try {
myReadDataLock.lock();
if (myReader == null) throw new ReferenceIndexUnavailableException();
try {
final TIntHashSet ids1 = myReader.getAllContainingFileIds(qualifier);
final TIntHashSet ids2 = myReader.getAllContainingFileIds(base);
final TIntHashSet intersection = intersection(ids1, ids2);
if ((ids2.size() - intersection.size()) * probabilityThreshold < ids2.size()) {
return true;
}
return false;
}
catch (Exception e) {
//noinspection ConstantConditions
return onException(e, "correlation");
}
} finally {
myReadDataLock.unlock();
}
}
@NotNull
@Override
public String getName(int idx) throws ReferenceIndexUnavailableException {
myReadDataLock.lock();
try {
if (myReader == null) throw new ReferenceIndexUnavailableException();
return myReader.getNameEnumerator().getName(idx);
} finally {
myReadDataLock.unlock();
}
}
private Integer calculateOccurrenceCount(@NotNull PsiElement element, boolean isConstructorSuggestion) {
LanguageLightRefAdapter adapter = null;
if (isConstructorSuggestion) {
adapter = ReadAction.compute(() -> LanguageLightRefAdapter.findAdapter(element));
if (!adapter.isClass(element)) {
return null;
}
}
final CompilerElementInfo searchElementInfo = asCompilerElements(element, false, false);
if (searchElementInfo == null) return null;
myReadDataLock.lock();
try {
if (myReader == null) return null;
try {
if (isConstructorSuggestion) {
int constructorOccurrences = 0;
for (PsiElement constructor : adapter.getInstantiableConstructors(element)) {
final LightRef lightConstructor = adapter.asLightUsage(constructor, myReader.getNameEnumerator());
if (lightConstructor != null) {
constructorOccurrences += myReader.getOccurrenceCount(lightConstructor);
}
}
final Integer anonymousCount = myReader.getAnonymousCount((LightRef.LightClassHierarchyElementDef)searchElementInfo.searchElements[0], searchElementInfo.place == ElementPlace.SRC);
return anonymousCount == null ? constructorOccurrences : (constructorOccurrences + anonymousCount);
} else {
return myReader.getOccurrenceCount(searchElementInfo.searchElements[0]);
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
} finally {
myReadDataLock.unlock();
}
}
@Nullable
private CompilerHierarchyInfoImpl getHierarchyInfo(@NotNull PsiNamedElement aClass,
@NotNull GlobalSearchScope useScope,
@@ -206,13 +334,13 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
if (!isServiceEnabledFor(aClass) || searchScope == LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope()) return null;
try {
Map<VirtualFile, Object[]> candidatesPerFile = ReadAction.compute(() -> {
Map<VirtualFile, SearchId[]> candidatesPerFile = ReadAction.compute(() -> {
if (myProject.isDisposed()) throw new ProcessCanceledException();
return CachedValuesManager.getCachedValue(aClass, () -> CachedValueProvider.Result.create(
new ConcurrentFactoryMap<HierarchySearchKey, Map<VirtualFile, Object[]>>() {
new ConcurrentFactoryMap<HierarchySearchKey, Map<VirtualFile, SearchId[]>>() {
@Nullable
@Override
protected Map<VirtualFile, Object[]> create(HierarchySearchKey key) {
protected Map<VirtualFile, SearchId[]> create(HierarchySearchKey key) {
return calculateDirectInheritors(aClass,
useScope,
key.mySearchFileType,
@@ -237,20 +365,21 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
}
private boolean isServiceEnabledFor(PsiElement element) {
if (!isServiceEnabled()) return false;
if (!isActive()) return false;
PsiFile file = ReadAction.compute(() -> element.getContainingFile());
return file != null && !InjectedLanguageManager.getInstance(myProject).isInjectedFragment(file);
}
private boolean isServiceEnabled() {
@Override
public boolean isActive() {
return myReader != null && isEnabled();
}
private Map<VirtualFile, Object[]> calculateDirectInheritors(@NotNull PsiNamedElement aClass,
private Map<VirtualFile, SearchId[]> calculateDirectInheritors(@NotNull PsiNamedElement aClass,
@NotNull GlobalSearchScope useScope,
@NotNull FileType searchFileType,
@NotNull CompilerHierarchySearchType searchType) {
final CompilerElementInfo searchElementInfo = asCompilerElements(aClass, false);
final CompilerElementInfo searchElementInfo = asCompilerElements(aClass, false, true);
if (searchElementInfo == null) return null;
LightRef searchElement = searchElementInfo.searchElements[0];
@@ -280,7 +409,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
@Nullable
private TIntHashSet getReferentFileIds(@NotNull PsiElement element) {
final CompilerElementInfo compilerElementInfo = asCompilerElements(element, true);
final CompilerElementInfo compilerElementInfo = asCompilerElements(element, true, true);
if (compilerElementInfo == null) return null;
myReadDataLock.lock();
@@ -305,17 +434,21 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
}
@Nullable
private CompilerElementInfo asCompilerElements(@NotNull PsiElement psiElement, boolean buildHierarchyForLibraryElements) {
private CompilerElementInfo asCompilerElements(@NotNull PsiElement psiElement,
boolean buildHierarchyForLibraryElements,
boolean checkNotDirty) {
myReadDataLock.lock();
try {
if (myReader == null) return null;
VirtualFile file = PsiUtilCore.getVirtualFile(psiElement);
if (file == null) return null;
ElementPlace place = ElementPlace.get(file, myProjectFileIndex);
if (place == null || (place == ElementPlace.SRC && myDirtyScopeHolder.contains(file))) {
return null;
if (checkNotDirty) {
if (place == null || (place == ElementPlace.SRC && myDirtyScopeHolder.contains(file))) {
return null;
}
}
final LanguageLightRefAdapter adapter = findAdapterForFileType(file.getFileType());
final LanguageLightRefAdapter adapter = LanguageLightRefAdapter.findAdapter(file);
if (adapter == null) return null;
final LightRef ref = adapter.asLightUsage(psiElement, myReader.getNameEnumerator());
if (ref == null) return null;
@@ -379,15 +512,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
return myProject;
}
@Nullable
static LanguageLightRefAdapter findAdapterForFileType(@NotNull FileType fileType) {
for (LanguageLightRefAdapter adapter : LanguageLightRefAdapter.INSTANCES) {
if (adapter.getFileTypes().contains(fileType)) {
return adapter;
}
}
return null;
}
private static void executeOnBuildThread(Runnable compilationFinished) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
@@ -534,12 +659,23 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
}
@Nullable
private <T> T onException(@NotNull RuntimeException e, @NotNull String actionName) {
final Throwable cause = e.getCause();
if (cause instanceof PersistentEnumeratorBase.CorruptedException || cause instanceof StorageException) {
private <T> T onException(@NotNull Exception e, @NotNull String actionName) {
if (e instanceof ProcessCanceledException) {
throw (ProcessCanceledException)e;
}
Throwable unwrapped = e instanceof RuntimeException ? e.getCause() : e;
if (unwrapped instanceof PersistentEnumeratorBase.CorruptedException || unwrapped instanceof StorageException) {
closeReaderIfNeed(true);
}
LOG.error("an exception during " + actionName + " calculation", e);
return null;
}
@NotNull
private static TIntHashSet intersection(@NotNull TIntHashSet set1, @NotNull TIntHashSet set2) {
TIntHashSet result = (TIntHashSet)set1.clone();
result.retainAll(set2.toArray());
return result;
}
}
@@ -25,19 +25,18 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFunctionalExpression;
import com.intellij.psi.PsiNameHelper;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.impl.source.PsiFileWithStubSupport;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.stubs.StubBase;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubTree;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -82,111 +81,16 @@ public class JavaCompilerElementRetriever {
}
@NotNull
static PsiClass[] retrieveClassesByInternalNames(@NotNull String[] internalNames,
@NotNull PsiNamedElement baseClass,
@NotNull PsiFileWithStubSupport psiFile) {
Collection<InternalClassMatcher> matchers = createClassMatcher(internalNames, baseClass);
return ReadAction.compute(() -> retrieveMatchedClasses(psiFile, matchers).toArray(PsiClass.EMPTY_ARRAY));
static PsiClass[] retrieveClassesByInternalIds(@NotNull SearchId[] internalIds,
@NotNull PsiFileWithStubSupport psiFile) {
ClassMatcher matcher = ClassMatcher.create(internalIds);
return ReadAction.compute(() -> matcher.retrieveClasses(psiFile));
}
private static List<PsiClass> retrieveMatchedClasses(PsiFileWithStubSupport psiFile, Collection<InternalClassMatcher> matchers) {
final List<PsiClass> result = new ArrayList<>(matchers.size());
StubTree tree = psiFile.getStubTree();
boolean foreign = tree == null;
if (foreign) {
tree = ((PsiFileImpl)psiFile).calcStubTree();
}
for (StubElement<?> element : tree.getPlainList()) {
if (element instanceof PsiClassStub && match((PsiClassStub)element, matchers)) {
result.add(((StubBase<PsiClass>)element).getPsi());
}
}
return result;
}
private static boolean match(PsiClassStub stub, Collection<InternalClassMatcher> matchers) {
for (InternalClassMatcher matcher : matchers) {
if (matcher.matches(stub)) {
//qualified name is unique among file's classes
if (matcher instanceof InternalClassMatcher.ByQualifiedName) {
matchers.remove(matcher);
}
return true;
}
}
return false;
}
private static Collection<InternalClassMatcher> createClassMatcher(@NotNull String[] internalNames, @NotNull PsiNamedElement baseClass) {
boolean matcherBySuperNameAdded = false;
final List<InternalClassMatcher> matchers = new ArrayList<>(internalNames.length);
for (String internalName : internalNames) {
int curLast = internalName.length() - 1;
while (true) {
int lastIndex = internalName.lastIndexOf('$', curLast);
if (lastIndex > -1 && lastIndex < internalName.length() - 1) {
final int followingIndex = lastIndex + 1;
final boolean digit = Character.isDigit(internalName.charAt(followingIndex));
if (digit) {
if (curLast == internalName.length() - 1) {
final int nextNonDigit = getNextNonDigitIndex(internalName, followingIndex);
if (nextNonDigit == -1) {
if (matcherBySuperNameAdded) {
break;
}
matcherBySuperNameAdded = true;
//anonymous
matchers.add(new InternalClassMatcher.BySuperName(ReadAction.compute(() -> baseClass.getName())));
break;
} else {
//declared inside method
matchers.add(new InternalClassMatcher.ByName(internalName.substring(nextNonDigit)));
}
}
else {
//declared in anonymous
matchers.add(new InternalClassMatcher.ByName(StringUtil.getShortName(internalName, '$')));
break;
}
}
}
else {
matchers.add(new InternalClassMatcher.ByQualifiedName(StringUtil.replace(internalName, "$", ".")));
break;
}
curLast = lastIndex - 1;
}
}
return matchers;
}
private static int getNextNonDigitIndex(String name, int digitIndex) {
for (int i = digitIndex + 1; i < name.length(); i++) {
if (!Character.isDigit(name.charAt(i))) {
return i;
}
}
return -1;
}
private interface InternalClassMatcher {
private interface InternalNameMatcher {
boolean matches(PsiClassStub stub);
class BySuperName implements InternalClassMatcher {
private final String mySuperName;
public BySuperName(String name) {mySuperName = name;}
@Override
public boolean matches(PsiClassStub stub) {
return stub.isAnonymous() && mySuperName.equals(PsiNameHelper.getShortClassName(stub.getBaseClassReferenceText()));
}
}
class ByName implements InternalClassMatcher {
class ByName implements InternalNameMatcher {
private final String myName;
public ByName(String name) {myName = name;}
@@ -197,7 +101,7 @@ public class JavaCompilerElementRetriever {
}
}
class ByQualifiedName implements InternalClassMatcher {
class ByQualifiedName implements InternalNameMatcher {
private final String myQName;
public ByQualifiedName(String name) {myQName = name;}
@@ -208,4 +112,114 @@ public class JavaCompilerElementRetriever {
}
}
}
private static class ClassMatcher {
@Nullable
private final TIntHashSet myAnonymousIndices;
@NotNull
private final Collection<InternalNameMatcher> myClassNameMatchers;
private ClassMatcher(@Nullable TIntHashSet anonymousIndices,
@NotNull Collection<InternalNameMatcher> nameMatchers) {
myAnonymousIndices = anonymousIndices;
myClassNameMatchers = nameMatchers;
}
private PsiClass[] retrieveClasses(PsiFileWithStubSupport file) {
StubTree tree = file.getStubTree();
boolean foreign = tree == null;
if (foreign) {
tree = ((PsiFileImpl)file).calcStubTree();
}
List<PsiClass> result = new ArrayList<>(myClassNameMatchers.size() + (myAnonymousIndices == null ? 0 : myAnonymousIndices.size()));
int anonymousId = 0;
for (StubElement<?> element : tree.getPlainList()) {
if (element instanceof PsiClassStub) {
if (((PsiClassStub)element).isAnonymous()) {
if (myAnonymousIndices != null && !myAnonymousIndices.isEmpty()) {
if (myAnonymousIndices.contains(anonymousId)) {
result.add((PsiClass)element.getPsi());
}
anonymousId++;
}
}
else if (match((PsiClassStub)element, myClassNameMatchers)) {
result.add((PsiClass)element.getPsi());
}
}
}
return result.toArray(PsiClass.EMPTY_ARRAY);
}
private static boolean match(PsiClassStub stub, Collection<InternalNameMatcher> matchers) {
for (InternalNameMatcher matcher : matchers) {
if (matcher.matches(stub)) {
//qualified name is unique among file's classes
if (matcher instanceof InternalNameMatcher.ByQualifiedName) {
matchers.remove(matcher);
}
return true;
}
}
return false;
}
private static ClassMatcher create(@NotNull SearchId[] internalIds) {
List<InternalNameMatcher> nameMatchers = new SmartList<>();
TIntHashSet anonymousIndices = null;
for (SearchId internalId : internalIds) {
if (internalId.getId() != -1) {
if (anonymousIndices == null) {
anonymousIndices = new TIntHashSet();
}
anonymousIndices.add(internalId.getId());
}
else {
String internalName = internalId.getDeserializedName();
int curLast = internalName.length() - 1;
while (true) {
int lastIndex = internalName.lastIndexOf('$', curLast);
if (lastIndex > -1 && lastIndex < internalName.length() - 1) {
final int followingIndex = lastIndex + 1;
final boolean digit = Character.isDigit(internalName.charAt(followingIndex));
if (digit) {
if (curLast == internalName.length() - 1) {
final int nextNonDigit = getNextNonDigitIndex(internalName, followingIndex);
if (nextNonDigit != -1) {
//declared inside method
nameMatchers.add(new InternalNameMatcher.ByName(internalName.substring(nextNonDigit)));
}
else {
throw new IllegalStateException();
}
}
else {
//declared in anonymous
nameMatchers.add(new InternalNameMatcher.ByName(StringUtil.getShortName(internalName, '$')));
break;
}
}
}
else {
nameMatchers.add(new InternalNameMatcher.ByQualifiedName(StringUtil.replace(internalName, "$", ".")));
break;
}
curLast = lastIndex - 1;
}
}
}
return new ClassMatcher(anonymousIndices, nameMatchers);
}
private static int getNextNonDigitIndex(String name, int digitIndex) {
for (int i = digitIndex + 1; i < name.length(); i++) {
if (!Character.isDigit(name.charAt(i))) {
return i;
}
}
return -1;
}
}
}
@@ -30,13 +30,14 @@ import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.backwardRefs.NameEnumerator;
import org.jetbrains.jps.backwardRefs.LightRef;
import org.jetbrains.jps.backwardRefs.NameEnumerator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
@NotNull
@@ -126,7 +127,7 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
@NotNull
@Override
public Class<? extends LightRef.LightClassHierarchyElementDef> getHierarchyObjectClass() {
return LightRef.JavaLightClassRef.class;
return LightRef.LightClassHierarchyElementDef.class;
}
@NotNull
@@ -137,23 +138,41 @@ public class JavaLightUsageAdapter implements LanguageLightRefAdapter {
@NotNull
@Override
public PsiClass[] findDirectInheritorCandidatesInFile(@NotNull String[] internalNames,
@NotNull PsiFileWithStubSupport file,
@NotNull PsiNamedElement superClass) {
return JavaCompilerElementRetriever.retrieveClassesByInternalNames(internalNames, superClass, file);
public PsiClass[] findDirectInheritorCandidatesInFile(@NotNull SearchId[] internalNames,
@NotNull PsiFileWithStubSupport file) {
return JavaCompilerElementRetriever.retrieveClassesByInternalIds(internalNames, file);
}
@NotNull
@Override
public PsiFunctionalExpression[] findFunExpressionsInFile(@NotNull Integer[] funExpressions,
public PsiFunctionalExpression[] findFunExpressionsInFile(@NotNull SearchId[] funExpressions,
@NotNull PsiFileWithStubSupport file) {
TIntHashSet requiredIndices = new TIntHashSet(funExpressions.length);
for (int funExpr : funExpressions) {
requiredIndices.add(funExpr);
for (SearchId funExpr : funExpressions) {
requiredIndices.add(funExpr.getId());
}
return JavaCompilerElementRetriever.retrieveFunExpressionsByIndices(requiredIndices, file);
}
@Override
public boolean isClass(@NotNull PsiElement element) {
return element instanceof PsiClass;
}
@NotNull
@Override
public PsiElement[] getInstantiableConstructors(@NotNull PsiElement aClass) {
if (!(aClass instanceof PsiClass)) {
throw new IllegalArgumentException("parameter should be an instance of PsiClass: " + aClass);
}
PsiClass theClass = (PsiClass)aClass;
if (theClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
return PsiElement.EMPTY_ARRAY;
}
return Stream.of(theClass.getConstructors()).filter(c -> !c.hasModifierProperty(PsiModifier.PRIVATE)).toArray(s -> PsiElement.ARRAY_FACTORY.create(s));
}
@Override
public boolean isDirectInheritor(PsiElement candidate, PsiNamedElement baseClass) {
return ((PsiClass) candidate).isInheritor((PsiClass) baseClass, false);
@@ -16,10 +16,12 @@
package com.intellij.compiler.backwardRefs;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.impl.source.PsiFileWithStubSupport;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.backwardRefs.LightRef;
@@ -35,6 +37,28 @@ import java.util.Set;
public interface LanguageLightRefAdapter {
LanguageLightRefAdapter[] INSTANCES = new LanguageLightRefAdapter[]{new JavaLightUsageAdapter()};
@Nullable
static LanguageLightRefAdapter findAdapter(@NotNull VirtualFile file) {
final FileType fileType = file.getFileType();
return findAdapter(fileType);
}
@Nullable
static LanguageLightRefAdapter findAdapter(@NotNull FileType fileType) {
for (LanguageLightRefAdapter adapter : INSTANCES) {
if (adapter.getFileTypes().contains(fileType)) {
return adapter;
}
}
return null;
}
@Nullable
static LanguageLightRefAdapter findAdapter(@NotNull PsiElement element) {
final VirtualFile file = PsiUtilCore.getVirtualFile(element);
return file == null ? null : findAdapter(file);
}
@NotNull
Set<FileType> getFileTypes();
@@ -77,17 +101,21 @@ public interface LanguageLightRefAdapter {
* found elements really inheritors.
*/
@NotNull
PsiElement[] findDirectInheritorCandidatesInFile(@NotNull String[] internalNames,
@NotNull PsiFileWithStubSupport file,
@NotNull PsiNamedElement superClass);
PsiElement[] findDirectInheritorCandidatesInFile(@NotNull SearchId[] internalNames,
@NotNull PsiFileWithStubSupport file);
/**
* @param indices - ordinal-numbers (corresponding to compiler tree index visitor) of required functional expressions.
* @return functional expressions for given functional type. Should return
*/
@NotNull
PsiElement[] findFunExpressionsInFile(@NotNull Integer[] indices,
PsiElement[] findFunExpressionsInFile(@NotNull SearchId[] indices,
@NotNull PsiFileWithStubSupport file);
boolean isClass(@NotNull PsiElement element);
@NotNull
PsiElement[] getInstantiableConstructors(@NotNull PsiElement aClass);
boolean isDirectInheritor(PsiElement candidate, PsiNamedElement baseClass);
}
@@ -0,0 +1,90 @@
/*
* Copyright 2000-2017 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.compiler.backwardRefs
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jps.backwardRefs.LightRef
import org.jetbrains.jps.backwardRefs.SignatureData
class MethodIncompleteSignature(val ref: LightRef.JavaLightMethodRef,
private val signatureData: SignatureData,
private val refService: CompilerReferenceServiceEx) {
companion object {
val CONSTRUCTOR_METHOD_NAME = "<init>"
}
val name: String by lazy {
refService.getName(ref.name)
}
val owner: String by lazy {
refService.getName(ref.owner.name)
}
val rawReturnType: String by lazy {
refService.getName(signatureData.rawReturnType)
}
val parameterCount: Int
get() = ref.parameterCount
val isStatic: Boolean
get() = signatureData.isStatic
fun resolveQualifier(project: Project, resolveScope: GlobalSearchScope) = JavaPsiFacade.getInstance(project).findClass(owner, resolveScope)
fun resolve(project: Project, resolveScope: GlobalSearchScope): Array<PsiMethod> {
if (CONSTRUCTOR_METHOD_NAME == name) {
return PsiMethod.EMPTY_ARRAY
}
val aClass = resolveQualifier(project, resolveScope) ?: return PsiMethod.EMPTY_ARRAY
return aClass.findMethodsByName(name, true)
.filter { it.hasModifierProperty(PsiModifier.STATIC) == isStatic }
.filter {
val returnType = it.returnType
returnType is PsiClassType && returnType.resolve()?.qualifiedName == rawReturnType
}
.sortedBy({ it.parameterList.parametersCount })
.toTypedArray()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as MethodIncompleteSignature
if (ref != other.ref) return false
if (signatureData != other.signatureData) return false
return true
}
override fun hashCode(): Int {
var result = ref.hashCode()
result = 31 * result + signatureData.hashCode()
return result
}
override fun toString(): String {
return owner + (if (isStatic) "" else "#") + name + "(" + parameterCount + ")"
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,13 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.api.index;
package com.intellij.compiler.backwardRefs;
/**
* @author Dmitry Batkovich
*/
public interface ConfigureVisitor {
void visit(ClassFilesIndexConfigure<?, ?> configure, boolean isAvailable);
import com.intellij.openapi.diagnostic.ControlFlowException;
public class ReferenceIndexUnavailableException extends RuntimeException implements ControlFlowException {
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2017 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.compiler.backwardRefs;
import org.jetbrains.annotations.Nullable;
public class SearchId {
private final String myDeserializedName;
private final int myId;
SearchId(@Nullable String deserializedName, int id) {
myDeserializedName = deserializedName;
myId = id;
}
SearchId(@Nullable String deserializedName) {
this(deserializedName, -1);
}
SearchId(int id) {
this(null, id);
}
public String getDeserializedName() {
return myDeserializedName;
}
public int getId() {
return myId;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import com.intellij.psi.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* @author Dmitry Batkovich
*/
public final class ChainCompletionStringUtil {
private ChainCompletionStringUtil() {}
/**
* CAUTION: isPrimitiveOrArrayOfPrimitives("java.lang.String") == true,
* isPrimitiveOrArrayOfPrimitives("java.lang.Object") == true
* isPrimitiveOrArrayOfPrimitives("java.lang.Class") == true
*/
public static boolean isPrimitiveOrArrayOfPrimitives(@NotNull PsiType type) {
type = type.getDeepComponentType();
if (type instanceof PsiPrimitiveType) return true;
if (!(type instanceof PsiClassType)) return false;
if (PRIMITIVES_SHORT_NAMES.contains(((PsiClassType)type).getClassName())) return false;
final PsiClass resolvedClass = ((PsiClassType)type).resolve();
if (resolvedClass == null) return false;
final String qName = resolvedClass.getQualifiedName();
if (qName == null) return false;
for (String name : PRIMITIVES_NAMES) {
if (name.equals(qName)) {
return true;
}
}
return false;
}
private static final String[] PRIMITIVES_NAMES = new String [] {CommonClassNames.JAVA_LANG_STRING,
CommonClassNames.JAVA_LANG_OBJECT,
CommonClassNames.JAVA_LANG_CLASS};
private static final Set<String> PRIMITIVES_SHORT_NAMES = ContainerUtil.set("String", "Object", "Class");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch;
package com.intellij.compiler.chainsSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
@@ -0,0 +1,41 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
/**
* The class contains all magic constants used in relevant chain search
*/
public interface ChainSearchMagicConstants {
/**
* Used to know do 2 methods frequently occurred in one file simultaneously
*/
int CORRELATION = 5;
/**
* Maximum count of completion contributor response chains
*/
int MAX_SEARCH_RESULT_SIZE = 5;
/**
* Maximum method calls count in a chain
*/
int MAX_CHAIN_SIZE = 4;
/**
* Relative coefficient to filter out rarely used methods
*/
int FILTER_RATIO = 10;
}
@@ -0,0 +1,272 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import com.intellij.compiler.backwardRefs.CompilerReferenceServiceEx;
import com.intellij.compiler.backwardRefs.MethodIncompleteSignature;
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.chainsSearch.context.TargetType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.psi.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Dmitry Batkovich
*/
public class ChainsSearcher {
private static final Logger LOG = Logger.getInstance(ChainsSearcher.class);
private ChainsSearcher() {
}
@NotNull
public static List<MethodsChain> search(int pathMaximalLength,
TargetType targetType,
int maxResultSize,
ChainCompletionContext context,
CompilerReferenceServiceEx compilerReferenceServiceEx) {
SearchInitializer initializer = createInitializer(targetType, compilerReferenceServiceEx, context);
return search(compilerReferenceServiceEx,
initializer,
pathMaximalLength,
maxResultSize,
targetType.getClassQName(),
context);
}
@NotNull
private static SearchInitializer createInitializer(TargetType target,
CompilerReferenceServiceEx compilerReferenceServiceEx,
ChainCompletionContext context) {
SortedSet<OccurrencesAware<MethodIncompleteSignature>> methods = compilerReferenceServiceEx.findMethodReferenceOccurrences(target.getClassQName());
return new SearchInitializer(methods, context);
}
@NotNull
private static List<MethodsChain> search(CompilerReferenceServiceEx indexReader,
SearchInitializer initializer,
int pathMaximalLength,
int maxResultSize,
String targetQName,
ChainCompletionContext context) {
SearchInitializer.InitResult initResult = initializer.init(Collections.emptySet());
Map<MethodIncompleteSignature, MethodsChain> knownDistance = initResult.getChains();
LinkedList<OccurrencesAware<MethodsChain>> q = initResult
.getVertices()
.stream()
.map(
signAndWeight -> new OccurrencesAware<>(MethodsChain.create(signAndWeight.getUnderlying(), signAndWeight.getOccurrences(), context),
signAndWeight.getOccurrences()))
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedList::new));
ResultHolder result = new ResultHolder(context.getPsiManager());
while (!q.isEmpty()) {
ProgressManager.checkCanceled();
OccurrencesAware<MethodsChain> currentVertex = q.poll();
int currentVertexDistance = currentVertex.getOccurrences();
MethodsChain currentChain = currentVertex.getUnderlying();
MethodIncompleteSignature headSignature = currentChain.getHeadSignature();
MethodsChain currentVertexMethodsChain = knownDistance.get(headSignature);
if (currentVertexDistance != currentVertexMethodsChain.getChainWeight()) {
continue;
}
if (headSignature.isStatic() || context.hasQualifier(context.resolveQualifierClass(headSignature))) {
result.add(currentChain);
continue;
}
String currentReturnType = headSignature.getOwner();
SortedSet<OccurrencesAware<MethodIncompleteSignature>> nextMethods = indexReader.findMethodReferenceOccurrences(currentReturnType);
MaxSizeTreeSet<OccurrencesAware<MethodIncompleteSignature>> currentSignatures =
new MaxSizeTreeSet<>(maxResultSize);
for (OccurrencesAware<MethodIncompleteSignature> indexValue : nextMethods) {
MethodIncompleteSignature vertex = indexValue.getUnderlying();
int occurrences = indexValue.getOccurrences();
if (vertex.isStatic() || !vertex.getOwner().equals(targetQName)) {
int vertexDistance = Math.min(currentVertexDistance, occurrences);
MethodsChain knownVertexMethodsChain = knownDistance.get(vertex);
if ((knownVertexMethodsChain == null || knownVertexMethodsChain.getChainWeight() < vertexDistance)) {
if (currentSignatures.isEmpty() || currentSignatures.last().getOccurrences() < vertexDistance) {
if (currentVertexMethodsChain.size() < pathMaximalLength - 1) {
MethodsChain newBestMethodsChain =
currentVertexMethodsChain.continuation(indexValue.getUnderlying(), indexValue.getOccurrences(), context);
if (newBestMethodsChain != null) {
currentSignatures
.add(new OccurrencesAware<>(indexValue.getUnderlying(), vertexDistance));
knownDistance.put(vertex, newBestMethodsChain);
}
}
}
}
else {
break;
}
}
}
boolean updated = false;
if (!currentSignatures.isEmpty()) {
boolean isBreak = false;
for (OccurrencesAware<MethodIncompleteSignature> sign : currentSignatures) {
if (!isBreak) {
if (indexReader.mayHappen(sign.getUnderlying().getRef(), headSignature.getRef(), ChainSearchMagicConstants.CORRELATION)) {
boolean stopChain = sign.getUnderlying().isStatic() || context.hasQualifier(context.resolveQualifierClass(sign.getUnderlying()));
if (stopChain) {
updated = true;
MethodsChain continuation = currentChain.continuation(sign.getUnderlying(), sign.getOccurrences(), context);
if (continuation != null) {
result.add(continuation);
}
continue;
}
else {
updated = true;
MethodsChain methodsChain =
currentChain.continuation(sign.getUnderlying(), sign.getOccurrences(), context);
if (methodsChain != null) {
q.addFirst(new OccurrencesAware<>(methodsChain, sign.getOccurrences()));
continue;
}
}
}
}
isBreak = true;
}
}
if (!updated &&
(headSignature.isStatic() ||
!targetQName.equals(headSignature.getOwner()))) {
result.add(currentVertex.getUnderlying());
}
if (result.size() > maxResultSize) {
return result.getResult();
}
}
return result.getResult();
}
private static MethodsChain createChainFromFirstElement(MethodsChain chain, PsiClass newQualifierClass) {
//TODO
return new MethodsChain(newQualifierClass, Collections.singletonList(chain.getFirst()), null, chain.getChainWeight());
}
private static class ResultHolder {
private final List<MethodsChain> myResult;
private final PsiManager myContext;
private ResultHolder(PsiManager psiManager) {
myContext = psiManager;
myResult = new ArrayList<>();
}
public void add(MethodsChain newChain) {
if (myResult.isEmpty()) {
myResult.add(newChain);
return;
}
boolean doAdd = true;
Stack<Integer> indexesToRemove = new Stack<>();
for (int i = 0; i < myResult.size(); i++) {
MethodsChain chain = myResult.get(i);
//
MethodsChain.CompareResult r = MethodsChain.compare(chain, newChain);
switch (r) {
case LEFT_CONTAINS_RIGHT:
indexesToRemove.add(i);
break;
case RIGHT_CONTAINS_LEFT:
case EQUAL:
doAdd = false;
break;
case NOT_EQUAL:
break;
}
}
while (!indexesToRemove.empty()) {
myResult.remove((int)indexesToRemove.pop());
}
if (doAdd) {
myResult.add(newChain);
}
}
public List<MethodsChain> getRawResult() {
return myResult;
}
public List<MethodsChain> getResult() {
return findSimilar(reduceChainsSize(myResult, PsiManager.getInstance(myContext.getProject())), myContext);
}
public int size() {
return myResult.size();
}
private static List<MethodsChain> reduceChainsSize(List<MethodsChain> chains, PsiManager psiManager) {
return ContainerUtil.map(chains, chain -> {
Iterator<PsiMethod[]> chainIterator = chain.iterator();
if (!chainIterator.hasNext()) {
LOG.error("empty chain");
return chain;
}
PsiMethod[] first = chainIterator.next();
while (chainIterator.hasNext()) {
PsiMethod psiMethod = chainIterator.next()[0];
if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
continue;
}
PsiClass current = psiMethod.getContainingClass();
if (current == null) {
LOG.error("containing class must be not null");
return chain;
}
PsiMethod[] currentMethods = current.findMethodsByName(first[0].getName(), true);
if (currentMethods.length != 0) {
for (PsiMethod f : first) {
PsiMethod[] fSupers = f.findDeepestSuperMethods();
PsiMethod fSuper = fSupers.length == 0 ? first[0] : fSupers[0];
for (PsiMethod currentMethod : currentMethods) {
if (psiManager.areElementsEquivalent(currentMethod, fSuper)) {
return createChainFromFirstElement(chain, currentMethod.getContainingClass());
}
for (PsiMethod method : currentMethod.findDeepestSuperMethods()) {
if (psiManager.areElementsEquivalent(method, fSuper)) {
return createChainFromFirstElement(chain, method.getContainingClass());
}
}
}
}
}
}
return chain;
});
}
private static List<MethodsChain> findSimilar(List<MethodsChain> chains, PsiManager psiManager) {
ResultHolder resultHolder = new ResultHolder(psiManager);
for (MethodsChain chain : chains) {
resultHolder.add(chain);
}
return resultHolder.getRawResult();
}
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import java.util.Comparator;
import java.util.TreeSet;
/**
* @author Dmitry Batkovich
*/
public class MaxSizeTreeSet<E extends Comparable<E>> extends TreeSet<E> {
private final int myMaxSize;
public MaxSizeTreeSet(int maxSize) {
myMaxSize = maxSize;
}
public boolean add(final E e) {
if (size() == myMaxSize) {
//noinspection ConstantConditions
final Comparator<? super E> comparator = comparator();
if ((comparator == null ? e.compareTo(last()) : comparator.compare(e, last())) < 0) {
final boolean isAdded = super.add(e);
if (isAdded) {
pollLast();
return true;
}
}
return false;
}
return super.add(e);
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.text.EditDistance;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.Set;
import java.util.stream.Stream;
public final class MethodChainsSearchUtil {
private final static int COMMON_PART_MIN_LENGTH = 3;
private MethodChainsSearchUtil() {
}
public static boolean isSimilar(@NotNull String target,
@NotNull String candidate) {
return EditDistance.levenshtein(target, sanitizedToLowerCase(candidate), true) >= COMMON_PART_MIN_LENGTH;
}
@NotNull
public static String sanitizedToLowerCase(@NotNull String name) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (Character.isLetter(ch)) {
result.append(Character.toLowerCase(ch));
}
}
return result.toString();
}
@Nullable
public static PsiMethod getMethodWithMinNotPrimitiveParameters(@NotNull PsiMethod[] methods,
@NotNull PsiClass target) {
return Stream.of(methods)
.filter(m -> {
for (PsiParameter parameter : m.getParameterList().getParameters()) {
PsiType t = parameter.getType();
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(t);
if (aClass != null && aClass == target) {
return false;
}
}
return true;
})
.sorted(Comparator.comparing(MethodChainsSearchUtil::getNonPrimitiveParameterCount))
.findFirst().orElse(null);
}
private static int getNonPrimitiveParameterCount(PsiMethod method) {
return (int)Stream.of(method.getParameterList().getParameters())
.map(p -> p.getType())
.filter(t -> !TypeConversionUtil.isPrimitiveAndNotNull(t))
.count();
}
public static boolean doesMethodsContainParameters(@NotNull PsiMethod[] psiMethods,
@NotNull Set<PsiType> parameterRawTypes) {
for (PsiMethod m : psiMethods) {
//TODO
//if (!containsParameter(m, parameterRawTypes)) {
// return true;
//}
}
return false;
}
}
@@ -0,0 +1,174 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import com.intellij.compiler.backwardRefs.MethodIncompleteSignature;
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import static com.intellij.util.containers.ContainerUtil.newArrayList;
import static com.intellij.util.containers.ContainerUtil.reverse;
public class MethodsChain {
private final List<PsiMethod[]> myRevertedPath;
private final MethodIncompleteSignature mySignature;
private final int myWeight;
private final PsiClass myQualifierClass;
@Nullable
public static MethodsChain create(@NotNull MethodIncompleteSignature signature,
int weight,
@NotNull ChainCompletionContext context) {
PsiClass qualifier = context.resolveQualifierClass(signature);
if (qualifier == null || (!signature.isStatic() && isInheritorOrSelf(context.getTarget().getPsiType(), qualifier))) {
return null;
}
PsiMethod[] methods = context.resolve(signature);
if (methods.length == 0) return null;
Set<PsiClass> classes = Arrays.stream(methods)
.flatMap(m -> Arrays.stream(m.getParameterList().getParameters()))
.map(p -> PsiUtil.resolveClassInType(p.getType()))
.collect(Collectors.toSet());
PsiClass contextClass = context.getTarget().getTargetClass();
if (classes.contains(contextClass)) {
return null;
}
classes.add(contextClass);
return new MethodsChain(qualifier, Collections.singletonList(methods), signature, weight);
}
public MethodsChain(@NotNull PsiClass qualifierClass,
@NotNull List<PsiMethod[]> revertedPath,
MethodIncompleteSignature signature,
int weight) {
myQualifierClass = qualifierClass;
myRevertedPath = revertedPath;
mySignature = signature;
myWeight = weight;
}
@NotNull
public MethodIncompleteSignature getHeadSignature() {
return mySignature;
}
public int size() {
return myRevertedPath.size();
}
public PsiClass getQualifierClass() {
return myQualifierClass;
}
public Iterator<PsiMethod[]> iterator() {
return myRevertedPath.iterator();
}
@NotNull
public PsiMethod[] getFirst() {
return myRevertedPath.get(0);
}
public List<PsiMethod[]> getPath() {
return reverse(myRevertedPath);
}
public int getChainWeight() {
return myWeight;
}
public MethodsChain continuation(@NotNull MethodIncompleteSignature signature,
int weight,
@NotNull ChainCompletionContext context) {
MethodsChain head = create(signature, weight, context);
if (head == null) return null;
ArrayList<PsiMethod[]> newRevertedPath = newArrayList();
newRevertedPath.addAll(myRevertedPath);
newRevertedPath.add(head.getPath().get(0));
return new MethodsChain(head.getQualifierClass(), newRevertedPath, head.getHeadSignature(), weight);
}
@Override
public String toString() {
return myQualifierClass.getName() + "." + reverse(myRevertedPath).stream().map(methods -> methods[0].getName() + "()").collect(Collectors.joining("."));
}
@SuppressWarnings("ConstantConditions")
public static CompareResult compare(@NotNull MethodsChain left, @NotNull MethodsChain right) {
if (left.size() == 0) {
return CompareResult.RIGHT_CONTAINS_LEFT;
}
if (right.size() == 0) {
return CompareResult.LEFT_CONTAINS_RIGHT;
}
Iterator<PsiMethod[]> leftIterator = left.myRevertedPath.iterator();
Iterator<PsiMethod[]> rightIterator = right.myRevertedPath.iterator();
while (leftIterator.hasNext() && rightIterator.hasNext()) {
PsiMethod[] thisNext = leftIterator.next();
PsiMethod[] thatNext = rightIterator.next();
if (!lookSimilar(thisNext, thatNext)) {
return CompareResult.NOT_EQUAL;
}
}
if (leftIterator.hasNext() && !rightIterator.hasNext()) {
return CompareResult.LEFT_CONTAINS_RIGHT;
}
if (!leftIterator.hasNext() && rightIterator.hasNext()) {
return CompareResult.RIGHT_CONTAINS_LEFT;
}
return CompareResult.EQUAL;
}
public enum CompareResult {
LEFT_CONTAINS_RIGHT,
RIGHT_CONTAINS_LEFT,
EQUAL,
NOT_EQUAL
}
private static boolean lookSimilar(PsiMethod[] methods1, PsiMethod[] methods2) {
PsiMethod repr1 = methods1[0];
PsiMethod repr2 = methods2[0];
if (repr1.hasModifierProperty(PsiModifier.STATIC) || repr2.hasModifierProperty(PsiModifier.STATIC)) return false;
if (!repr1.getName().equals(repr2.getName()) ||
repr1.getParameterList().getParametersCount() != repr2.getParameterList().getParametersCount()) {
return false;
}
Set<PsiMethod> methodSet1 = ContainerUtil.newHashSet(methods1);
Set<PsiMethod> methodSet2 = ContainerUtil.newHashSet(methods2);
if (ContainerUtil.intersects(methodSet1, methodSet2)) return true;
Set<PsiMethod> deepestSupers1 = methodSet1.stream().flatMap(m -> Arrays.stream(m.findDeepestSuperMethods())).collect(Collectors.toSet());
return methodSet2.stream().flatMap(m -> Arrays.stream(m.findDeepestSuperMethods())).anyMatch(deepestSupers1::contains);
}
private static boolean isInheritorOrSelf(@NotNull PsiType type, @NotNull PsiClass superCandidate) {
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type);
return aClass != null && InheritanceUtil.isInheritorOrSelf(aClass, superCandidate, true);
}
}
@@ -0,0 +1,244 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.completion.JavaChainLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.VariableLookupItem;
import com.intellij.compiler.chainsSearch.completion.lookup.ChainCompletionNewVariableLookupElement;
import com.intellij.compiler.chainsSearch.completion.lookup.WeightableChainLookupElement;
import com.intellij.compiler.chainsSearch.completion.lookup.sub.GetterLookupSubLookupElement;
import com.intellij.compiler.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.compiler.chainsSearch.completion.lookup.sub.VariableSubLookupElement;
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
import com.intellij.psi.*;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.stream.Collectors;
import static com.intellij.compiler.chainsSearch.completion.lookup.ChainCompletionLookupElementUtil.createLookupElement;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
public class MethodsChainLookupRangingHelper {
@Nullable
public static LookupElement chainToWeightableLookupElement(MethodsChain chain,
ChainCompletionContext context) {
int chainSize = chain.size();
assert chainSize != 0;
int lastMethodWeight = chain.getChainWeight();
int unreachableParametersCount = 0;
int notMatchedStringVars = 0;
int matchedParametersInContext = 0;
Boolean isFirstMethodStatic = null;
Boolean hasCallingVariableInContext = null;
LookupElement chainLookupElement = null;
PsiClass newVariableClass = null;
NullableNotNullManager nullableNotNullManager = NullableNotNullManager.getInstance(context.getProject());
for (PsiMethod[] psiMethods : chain.getPath()) {
PsiMethod method =
MethodChainsSearchUtil.getMethodWithMinNotPrimitiveParameters(psiMethods, context.getTarget().getTargetClass());
if (method == null) {
return null;
}
if (isFirstMethodStatic == null) {
isFirstMethodStatic = psiMethods[0].hasModifierProperty(PsiModifier.STATIC);
}
PsiClass qualifierClass;
boolean isHead = chainLookupElement == null;
if (isHead) {
qualifierClass = chain.getQualifierClass();
}
else {
qualifierClass = null;
}
MethodProcResult procResult = processMethod(method, qualifierClass, isHead, lastMethodWeight, context, nullableNotNullManager);
if (procResult == null) {
return null;
}
if (hasCallingVariableInContext == null) {
hasCallingVariableInContext = procResult.hasCallingVariableInContext();
}
if (isHead && procResult.isIntroduceNewVariable()) {
newVariableClass = qualifierClass;
}
matchedParametersInContext += procResult.getMatchedParametersInContext();
unreachableParametersCount += procResult.getUnreachableParametersCount();
notMatchedStringVars += procResult.getNotMatchedStringVars();
chainLookupElement =
isHead ? procResult.getLookupElement() : new JavaChainLookupElement(chainLookupElement, procResult.getLookupElement());
}
if (newVariableClass != null) {
chainLookupElement = ChainCompletionNewVariableLookupElement.create(newVariableClass, chainLookupElement);
}
ChainRelevance relevance =
new ChainRelevance(chainSize, lastMethodWeight, unreachableParametersCount, notMatchedStringVars, hasCallingVariableInContext,
isFirstMethodStatic, matchedParametersInContext);
return new WeightableChainLookupElement(chainLookupElement, relevance);
}
@Nullable
private static MethodProcResult processMethod(@NotNull PsiMethod method,
@Nullable PsiClass qualifierClass,
boolean isHeadMethod,
int weight,
ChainCompletionContext context,
NullableNotNullManager nullableNotNullManager) {
int unreachableParametersCount = 0;
int notMatchedStringVars = 0;
int matchedParametersInContext = 0;
boolean hasCallingVariableInContext = false;
boolean introduceNewVariable = false;
PsiParameterList parameterList = method.getParameterList();
TIntObjectHashMap<SubLookupElement> parametersMap = new TIntObjectHashMap<>(parameterList.getParametersCount());
PsiParameter[] parameters = parameterList.getParameters();
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
PsiType type = parameter.getType();
if (type.equalsToText(JAVA_LANG_STRING)) {
PsiElement relevantStringElement = context.findRelevantStringInContext(parameter.getName());
if (relevantStringElement == null) {
notMatchedStringVars++;
}
else {
parametersMap.put(i, createSubLookup(relevantStringElement));
}
}
else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) {
Collection<PsiElement> contextVariables = context.getQualifiers(type).collect(Collectors.toList());
PsiElement contextVariable = ContainerUtil.getFirstItem(contextVariables, null);
if (contextVariable != null) {
if (contextVariables.size() == 1) parametersMap.put(i, createSubLookup(contextVariable));
matchedParametersInContext++;
continue;
}
if (!nullableNotNullManager.isNullable(parameter, true)) {
unreachableParametersCount++;
}
}
}
LookupElement lookupElement;
if (isHeadMethod) {
if (method.hasModifierProperty(PsiModifier.STATIC)) {
hasCallingVariableInContext = true;
lookupElement = createLookupElement(method, parametersMap);
}
else if (method.isConstructor()) {
return null;
}
else {
Object e = context.getQualifiers(qualifierClass).findFirst().orElse(null);
if (e != null) {
LookupElement firstChainElement;
if (e instanceof PsiVariable) {
firstChainElement = new VariableLookupItem((PsiVariable)e);
}
else if (e instanceof PsiMethod) {
firstChainElement = createLookupElement((PsiMethod)e, null);
}
else if (e instanceof LookupElement) {
firstChainElement = (LookupElement)e;
}
else {
throw new AssertionError();
}
hasCallingVariableInContext = true;
lookupElement = new JavaChainLookupElement(firstChainElement, createLookupElement(method, parametersMap));
}
else {
lookupElement = createLookupElement(method, parametersMap);
if (!context.hasQualifier(qualifierClass)) {
introduceNewVariable = true;
}
}
}
}
else {
lookupElement = createLookupElement(method, parametersMap);
}
return new MethodProcResult(lookupElement,
unreachableParametersCount,
notMatchedStringVars,
hasCallingVariableInContext,
introduceNewVariable,
matchedParametersInContext);
}
@NotNull
private static SubLookupElement createSubLookup(PsiElement relevantStringElement) {
return relevantStringElement instanceof PsiMethod
? new GetterLookupSubLookupElement((PsiMethod)relevantStringElement)
: new VariableSubLookupElement((PsiVariable)relevantStringElement);
}
private static class MethodProcResult {
private final LookupElement myMethodLookup;
private final int myUnreachableParametersCount;
private final int myNotMatchedStringVars;
private final boolean myHasCallingVariableInContext;
private final boolean myIntroduceNewVariable;
private final int myMatchedParametersInContext;
private MethodProcResult(LookupElement methodLookup,
int unreachableParametersCount,
int notMatchedStringVars,
boolean hasCallingVariableInContext,
boolean introduceNewVariable,
int matchedParametersInContext) {
myMethodLookup = methodLookup;
myUnreachableParametersCount = unreachableParametersCount;
myNotMatchedStringVars = notMatchedStringVars;
myHasCallingVariableInContext = hasCallingVariableInContext;
myIntroduceNewVariable = introduceNewVariable;
myMatchedParametersInContext = matchedParametersInContext;
}
private boolean isIntroduceNewVariable() {
return myIntroduceNewVariable;
}
private boolean hasCallingVariableInContext() {
return myHasCallingVariableInContext;
}
private LookupElement getLookupElement() {
return myMethodLookup;
}
private int getUnreachableParametersCount() {
return myUnreachableParametersCount;
}
private int getNotMatchedStringVars() {
return myNotMatchedStringVars;
}
public int getMatchedParametersInContext() {
return myMatchedParametersInContext;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,36 +13,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch;
package com.intellij.compiler.chainsSearch;
import org.jetbrains.annotations.NotNull;
/**
* @author Dmitry Batkovich
*/
public class WeightAware<V> implements Comparable<WeightAware<V>> {
public class OccurrencesAware<V> implements Comparable<OccurrencesAware<V>> {
private final V myUnderlying;
private final int myWeight;
private final int myOccurrences;
public WeightAware(final V underlying, final int weight) {
public OccurrencesAware(final V underlying, final int occurrences) {
myUnderlying = underlying;
myWeight = weight;
myOccurrences = occurrences;
}
public V getUnderlying() {
return myUnderlying;
}
public int getWeight() {
return myWeight;
public int getOccurrences() {
return myOccurrences;
}
@Override
public int compareTo(@NotNull final WeightAware<V> that) {
final int sub = -getWeight() + that.getWeight();
public int compareTo(@NotNull final OccurrencesAware<V> that) {
final int sub = -getOccurrences() + that.getOccurrences();
if (sub != 0) {
return sub;
}
return myUnderlying.hashCode() - that.myUnderlying.hashCode();
}
@Override
public String toString() {
return getOccurrences() + " for " + myUnderlying;
}
}
@@ -0,0 +1,98 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch;
import com.intellij.compiler.backwardRefs.MethodIncompleteSignature;
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
import com.intellij.openapi.util.Pair;
import java.util.*;
public class SearchInitializer {
private final static int CHAIN_SEARCH_MAGIC_RATIO = 10;
private final LinkedHashMap<MethodIncompleteSignature, Pair<MethodsChain, Integer>> myChains;
private final ChainCompletionContext myContext;
public SearchInitializer(SortedSet<OccurrencesAware<MethodIncompleteSignature>> indexValues,
ChainCompletionContext context) {
myContext = context;
int size = indexValues.size();
myChains = new LinkedHashMap<>(size);
add(indexValues);
}
private void add(Collection<OccurrencesAware<MethodIncompleteSignature>> indexValues) {
int bestOccurrences = -1;
for (OccurrencesAware<MethodIncompleteSignature> indexValue : indexValues) {
if (add(indexValue)) {
int occurrences = indexValue.getOccurrences();
if (bestOccurrences == -1) {
bestOccurrences = occurrences;
}
else if (bestOccurrences > occurrences * CHAIN_SEARCH_MAGIC_RATIO) {
return;
}
}
}
}
private boolean add(OccurrencesAware<MethodIncompleteSignature> indexValue) {
MethodIncompleteSignature methodInvocation = indexValue.getUnderlying();
int occurrences = indexValue.getOccurrences();
MethodsChain methodsChain = MethodsChain.create(indexValue.getUnderlying(), occurrences, myContext);
if (methodsChain != null) {
myChains.put(methodInvocation, Pair.create(methodsChain, occurrences));
return true;
}
return false;
}
public InitResult init(Set<String> excludedEdgeNames) {
int size = myChains.size();
List<OccurrencesAware<MethodIncompleteSignature>> initedVertexes = new ArrayList<>(size);
LinkedHashMap<MethodIncompleteSignature, MethodsChain> initedChains =
new LinkedHashMap<>(size);
for (Map.Entry<MethodIncompleteSignature, Pair<MethodsChain, Integer>> entry : myChains.entrySet()) {
MethodIncompleteSignature signature = entry.getKey();
if (!excludedEdgeNames.contains(signature.getName())) {
initedVertexes.add(new OccurrencesAware<>(entry.getKey(), entry.getValue().getSecond()));
MethodsChain methodsChain = entry.getValue().getFirst();
initedChains.put(signature, methodsChain);
}
}
return new InitResult(initedVertexes, initedChains);
}
public static class InitResult {
private final List<OccurrencesAware<MethodIncompleteSignature>> myVertexes;
private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains;
private InitResult(List<OccurrencesAware<MethodIncompleteSignature>> vertexes,
LinkedHashMap<MethodIncompleteSignature, MethodsChain> chains) {
myVertexes = vertexes;
myChains = chains;
}
public List<OccurrencesAware<MethodIncompleteSignature>> getVertices() {
return myVertexes;
}
public LinkedHashMap<MethodIncompleteSignature, MethodsChain> getChains() {
return myChains;
}
}
}
@@ -0,0 +1,168 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.compiler.CompilerReferenceService;
import com.intellij.compiler.backwardRefs.CompilerReferenceServiceEx;
import com.intellij.compiler.backwardRefs.ReferenceIndexUnavailableException;
import com.intellij.compiler.chainsSearch.ChainSearchMagicConstants;
import com.intellij.compiler.chainsSearch.ChainsSearcher;
import com.intellij.compiler.chainsSearch.MethodsChain;
import com.intellij.compiler.chainsSearch.MethodsChainLookupRangingHelper;
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.chainsSearch.context.TargetType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static com.intellij.patterns.PsiJavaPatterns.or;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
/**
* @author Dmitry Batkovich
*/
public class MethodsChainsCompletionContributor extends CompletionContributor {
public static final String REGISTRY_KEY = "compiler.ref.chain.search";
private static final Logger LOG = Logger.getInstance(MethodsChainsCompletionContributor.class);
private static final boolean IS_UNIT_TEST_MODE = ApplicationManager.getApplication().isUnitTestMode();
public static final CompletionType COMPLETION_TYPE = IS_UNIT_TEST_MODE ? CompletionType.BASIC : CompletionType.SMART;
@SuppressWarnings("unchecked")
public MethodsChainsCompletionContributor() {
ElementPattern<PsiElement> pattern = or(patternForMethodCallParameter(), patternForVariableAssignment());
extend(COMPLETION_TYPE, pattern, new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet result) {
try {
if (!Registry.is(REGISTRY_KEY)) return;
ChainCompletionContext completionContext = extractContext(parameters);
if (completionContext == null) return;
List<LookupElement> elementsFoundByMethodsChainsSearch = searchForLookups(completionContext);
if (!IS_UNIT_TEST_MODE) {
result.runRemainingContributors(parameters, completionResult -> {
LookupElement lookupElement = completionResult.getLookupElement();
PsiElement lookupElementPsi = lookupElement.getPsiElement();
if (lookupElementPsi != null) {
for (LookupElement element : elementsFoundByMethodsChainsSearch) {
if (lookupElementPsi.isEquivalentTo(element.getPsiElement())) {
elementsFoundByMethodsChainsSearch.remove(element);
break;
}
}
}
result.passResult(completionResult);
});
} else {
result.stopHere();
}
result.addAllElements(elementsFoundByMethodsChainsSearch);
}
catch (ReferenceIndexUnavailableException ignored) {
//index was closed due to compilation
}
}
});
}
private static List<LookupElement> searchForLookups(ChainCompletionContext context) {
CompilerReferenceServiceEx methodsUsageIndexReader = (CompilerReferenceServiceEx)CompilerReferenceService.getInstance(context.getProject());
TargetType target = context.getTarget();
List<MethodsChain> searchResult =
ChainsSearcher.search(ChainSearchMagicConstants.MAX_CHAIN_SIZE,
target,
ChainSearchMagicConstants.MAX_SEARCH_RESULT_SIZE,
context,
methodsUsageIndexReader);
int maxWeight = searchResult.stream().mapToInt(MethodsChain::getChainWeight).max().orElse(0);
return searchResult
.stream()
.filter(ch -> ch.getChainWeight() * ChainSearchMagicConstants.FILTER_RATIO >= maxWeight)
.map(ch -> MethodsChainLookupRangingHelper.chainToWeightableLookupElement(ch, context))
.collect(Collectors.toList());
}
@Nullable
private static ChainCompletionContext extractContext(CompletionParameters parameters) {
PsiElement parent = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiAssignmentExpression.class, PsiLocalVariable.class, PsiMethodCallExpression.class);
LOG.assertTrue(parent != null, "A completion position should match to a pattern");
if (parent instanceof PsiAssignmentExpression) {
return extractContextFromAssignment((PsiAssignmentExpression)parent);
}
if (parent instanceof PsiLocalVariable) {
return extractContextFromVariable((PsiLocalVariable)parent);
}
PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod();
if (method == null) return null;
PsiExpression expression = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiExpression.class);
PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiExpressionList.class);
if (expressionList == null) return null;
int exprPosition = Arrays.asList(expressionList.getExpressions()).indexOf(expression);
PsiParameter[] methodParameters = method.getParameterList().getParameters();
if (exprPosition < methodParameters.length) {
PsiParameter methodParameter = methodParameters[exprPosition];
return ChainCompletionContext.createContext(methodParameter.getType(), PsiTreeUtil.getParentOfType(expression, PsiDeclarationStatement.class));
}
return null;
}
@Nullable
private static ChainCompletionContext extractContextFromVariable(PsiLocalVariable localVariable) {
PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(localVariable, PsiDeclarationStatement.class);
return ChainCompletionContext.createContext(localVariable.getType(), declaration);
}
@Nullable
private static ChainCompletionContext extractContextFromAssignment(PsiAssignmentExpression assignmentExpression) {
if (!(assignmentExpression instanceof PsiReferenceExpression)) return null;
PsiElement resolved = ((PsiReferenceExpression)assignmentExpression).resolve();
return resolved instanceof PsiVariable
? ChainCompletionContext.createContext(((PsiVariable)resolved).getType(), assignmentExpression)
: null;
}
@NotNull
private static ElementPattern<PsiElement> patternForVariableAssignment() {
final ElementPattern<PsiElement> patternForParent = or(psiElement().withText(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED)
.afterSiblingSkipping(psiElement(PsiWhiteSpace.class),
psiElement(PsiJavaToken.class).withText("=")));
return psiElement().withParent(patternForParent).withSuperParent(2, or(psiElement(PsiAssignmentExpression.class),
psiElement(PsiLocalVariable.class)
.inside(PsiDeclarationStatement.class))).inside(PsiMethod.class);
}
@NotNull
private static ElementPattern<PsiElement> patternForMethodCallParameter() {
return psiElement().withSuperParent(3, PsiMethodCallExpressionImpl.class);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion;
package com.intellij.compiler.chainsSearch.completion;
import com.intellij.codeInsight.completion.CompletionLocation;
import com.intellij.codeInsight.completion.CompletionWeigher;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.WeightableChainLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.ChainRelevance;
import com.intellij.compiler.chainsSearch.ChainRelevance;
import com.intellij.compiler.chainsSearch.completion.lookup.WeightableChainLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import org.jetbrains.annotations.NotNull;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup;
package com.intellij.compiler.chainsSearch.completion.lookup;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.compiler.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.PsiKeyword;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup;
package com.intellij.compiler.chainsSearch.completion.lookup;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.JavaMethodCallElement;
import com.intellij.codeInsight.completion.StaticallyImportable;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.compiler.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.PsiClass;
@@ -27,7 +27,6 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiMethod;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TObjectProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -81,12 +80,9 @@ public class ChainCompletionMethodCallLookupElement extends JavaMethodCallElemen
assert file instanceof PsiJavaFile;
final PsiJavaFile javaFile = (PsiJavaFile)file;
if (myReplaceElements != null) {
myReplaceElements.forEachValue(new TObjectProcedure<SubLookupElement>() {
@Override
public boolean execute(final SubLookupElement subLookupElement) {
subLookupElement.doImport(javaFile);
return true;
}
myReplaceElements.forEachValue(subLookupElement -> {
subLookupElement.doImport(javaFile);
return true;
});
}
context.commitDocument();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup;
package com.intellij.compiler.chainsSearch.completion.lookup;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
@@ -36,7 +36,7 @@ import java.util.Collection;
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class ChainCompletionNewVariableLookupElement extends LookupElementDecorator<LookupElement> {
private final static Logger log = Logger.getInstance(ChainCompletionNewVariableLookupElement.class);
private final static Logger LOG = Logger.getInstance(ChainCompletionNewVariableLookupElement.class);
private final PsiClass myPsiClass;
private final String myNewVarName;
@@ -62,13 +62,20 @@ public class ChainCompletionNewVariableLookupElement extends LookupElementDecora
((PsiJavaFile)file).importClass(myPsiClass);
final PsiElement caretElement = file.findElementAt(context.getEditor().getCaretModel().getOffset());
if (caretElement == null) {
log.error("element on caret position MUST BE not null");
LOG.error("element on caret position MUST BE not null");
return;
}
final PsiStatement statement = (PsiStatement) caretElement.getPrevSibling();
PsiElement prevSibling = caretElement.getPrevSibling();
final PsiStatement statement;
if (prevSibling instanceof PsiStatement) {
statement = (PsiStatement)prevSibling;
} else {
statement = PsiTreeUtil.getParentOfType(prevSibling, PsiStatement.class);
}
final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(statement, PsiCodeBlock.class);
if (codeBlock == null) {
log.error("code block MUST BE not null");
LOG.error("code block MUST BE not null");
return;
}
final Project project = context.getProject();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup;
package com.intellij.compiler.chainsSearch.completion.lookup;
import com.intellij.compiler.classFilesIndex.chainsSearch.ChainRelevance;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.compiler.chainsSearch.ChainRelevance;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.ui.JBColor;
import org.jetbrains.annotations.NotNull;
/**
@@ -34,4 +36,10 @@ public final class WeightableChainLookupElement extends LookupElementDecorator<L
public ChainRelevance getChainRelevance() {
return myChainRelevance;
}
@Override
public void renderElement(LookupElementPresentation presentation) {
presentation.setItemTextForeground(JBColor.GREEN);
super.renderElement(presentation);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub;
package com.intellij.compiler.chainsSearch.completion.lookup.sub;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.Nullable;
/**
@@ -25,8 +26,8 @@ public class GetterLookupSubLookupElement implements SubLookupElement {
private final String myVariableName;
private final String myMethodName;
public GetterLookupSubLookupElement(final String methodName) {
this(null, methodName);
public GetterLookupSubLookupElement(final PsiMethod method) {
this(null, method.getName());
}
public GetterLookupSubLookupElement(@Nullable final String variableName, final String methodName) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub;
package com.intellij.compiler.chainsSearch.completion.lookup.sub;
import com.intellij.psi.PsiJavaFile;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub;
package com.intellij.compiler.chainsSearch.completion.lookup.sub;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiVariable;
@@ -0,0 +1,250 @@
/*
* Copyright 2000-2017 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.compiler.chainsSearch.context;
import com.intellij.compiler.backwardRefs.MethodIncompleteSignature;
import com.intellij.compiler.chainsSearch.ChainCompletionStringUtil;
import com.intellij.compiler.chainsSearch.MethodChainsSearchUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.scope.BaseScopeProcessor;
import com.intellij.psi.scope.ElementClassHint;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.FactoryMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ChainCompletionContext {
@NotNull
private final TargetType myTarget;
@NotNull
private final List<PsiNamedElement> myContextElements;
@NotNull
private final List<PsiNamedElement> myContextStrings;
@NotNull
private final PsiElement myContext;
@NotNull
private final GlobalSearchScope myResolveScope;
@NotNull
private final Project myProject;
@NotNull
private final PsiManager myPsiManager;
@NotNull
private final FactoryMap<MethodIncompleteSignature, PsiClass> myQualifierClassResolver;
@NotNull
private final FactoryMap<MethodIncompleteSignature, PsiMethod[]> myResolver;
public ChainCompletionContext(@NotNull TargetType target,
@NotNull List<PsiNamedElement> contextElements,
@NotNull List<PsiNamedElement> contextStrings,
@NotNull PsiElement context) {
myTarget = target;
myContextElements = contextElements;
myContextStrings = contextStrings;
myContext = context;
myResolveScope = context.getResolveScope();
myProject = context.getProject();
myPsiManager = PsiManager.getInstance(myProject);
myQualifierClassResolver = new FactoryMap<MethodIncompleteSignature, PsiClass>() {
@Nullable
@Override
protected PsiClass create(MethodIncompleteSignature sign) {
return sign.resolveQualifier(myProject, myResolveScope);
}
};
myResolver = new FactoryMap<MethodIncompleteSignature, PsiMethod[]>() {
@NotNull
@Override
protected PsiMethod[] create(MethodIncompleteSignature sign) {
return sign.resolve(myProject, myResolveScope);
}
};
}
@NotNull
public TargetType getTarget() {
return myTarget;
}
public boolean contains(@Nullable PsiType type) {
if (type == null) return false;
Set<PsiType> types = getContextTypes();
if (types.contains(type)) return true;
for (PsiType contextType : types) {
if (type.isAssignableFrom(contextType)) {
return true;
}
}
return false;
}
public PsiFile getContextFile() {
return myContext.getContainingFile();
}
@NotNull
public Set<PsiType> getContextTypes() {
return myContextElements.stream().map(ChainCompletionContext::getType).collect(Collectors.toSet());
}
@NotNull
public GlobalSearchScope getResolveScope() {
return myResolveScope;
}
@NotNull
public Project getProject() {
return myProject;
}
@NotNull
public PsiManager getPsiManager() {
return myPsiManager;
}
@Nullable
public PsiElement findRelevantStringInContext(String stringParameterName) {
String sanitizedTarget = MethodChainsSearchUtil.sanitizedToLowerCase(stringParameterName);
return myContextStrings.stream().filter(e -> {
String name = e.getName();
return name != null && MethodChainsSearchUtil.isSimilar(sanitizedTarget, name);
}).findFirst().orElse(null);
}
public boolean hasQualifier(@Nullable PsiClass targetClass) {
return getQualifiers(targetClass).findAny().isPresent();
}
public Stream<PsiNamedElement> getQualifiers(@Nullable PsiClass targetClass) {
if (targetClass == null) return Stream.empty();
return getQualifiers(JavaPsiFacade.getInstance(myProject).getElementFactory().createType(targetClass));
}
public Stream<PsiNamedElement> getQualifiers(@NotNull PsiType targetType) {
return myContextElements.stream().filter(e -> {
PsiType elementType = getType(e);
return elementType != null && targetType.isAssignableFrom(elementType);
});
}
@Nullable
public PsiClass resolveQualifierClass(MethodIncompleteSignature sign) {
return myQualifierClassResolver.get(sign);
}
@NotNull
public PsiMethod[] resolve(MethodIncompleteSignature sign) {
return myResolver.get(sign);
}
@Nullable
public static ChainCompletionContext createContext(@Nullable PsiType targetType,
@Nullable PsiElement containingElement) {
if (containingElement == null) return null;
TargetType target = TargetType.create(targetType);
if (target == null) return null;
ContextProcessor processor = new ContextProcessor(null, containingElement.getProject(), containingElement);
PsiScopesUtil.treeWalkUp(processor, containingElement, containingElement.getContainingFile());
List<PsiNamedElement> contextElements = processor.getContextElements();
List<PsiNamedElement> contextStrings = processor.getContextStrings();
return new ChainCompletionContext(target, contextElements, contextStrings, containingElement);
}
private static class ContextProcessor extends BaseScopeProcessor implements ElementClassHint {
private final List<PsiNamedElement> myContextElements = new SmartList<>();
private final List<PsiNamedElement> myContextStrings = new SmartList<>();
private final PsiVariable myCompletionVariable;
private final PsiResolveHelper myResolveHelper;
private final PsiElement myPlace;
private ContextProcessor(@Nullable PsiVariable variable,
@NotNull Project project,
@NotNull PsiElement place) {
myCompletionVariable = variable;
myResolveHelper = PsiResolveHelper.SERVICE.getInstance(project);
myPlace = place;
}
@Override
public boolean shouldProcess(DeclarationKind kind) {
return kind == DeclarationKind.ENUM_CONST ||
kind == DeclarationKind.FIELD ||
kind == DeclarationKind.METHOD ||
kind == DeclarationKind.VARIABLE;
}
@Override
public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
if ((!(element instanceof PsiMethod) || PropertyUtil.isSimplePropertyAccessor((PsiMethod)element)) &&
(!(element instanceof PsiMember) || myResolveHelper.isAccessible((PsiMember)element, myPlace, null))) {
PsiType type = getType(element);
if (type == null) {
return false;
}
if (ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) {
if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
myContextStrings.add((PsiNamedElement)element);
}
return false;
}
myContextElements.add((PsiNamedElement)element);
}
return true;
}
@Override
public <T> T getHint(@NotNull Key<T> hintKey) {
if (hintKey == ElementClassHint.KEY) {
//noinspection unchecked
return (T)this;
}
return super.getHint(hintKey);
}
@NotNull
public List<PsiNamedElement> getContextElements() {
myContextElements.remove(myCompletionVariable);
return myContextElements;
}
@NotNull
public List<PsiNamedElement> getContextStrings() {
return myContextStrings;
}
}
@Nullable
private static PsiType getType(PsiElement element) {
if (element instanceof PsiVariable) {
return ((PsiVariable)element).getType();
}
if (element instanceof PsiMethod) {
return ((PsiMethod)element).getReturnType();
}
throw new AssertionError(element);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -13,12 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.classFilesIndex.chainsSearch.context;
package com.intellij.compiler.chainsSearch.context;
import com.intellij.psi.PsiArrayType;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nullable;
/**
@@ -30,9 +28,9 @@ public class TargetType {
private final boolean myArray;
private final PsiType myPsiType;
public TargetType(final String classQName,
final boolean isArray,
final PsiType targetType) {
public TargetType(String classQName,
boolean isArray,
PsiType targetType) {
myClassQName = classQName;
myArray = isArray;
myPsiType = targetType;
@@ -50,8 +48,27 @@ public class TargetType {
return myPsiType;
}
public PsiClass getTargetClass() {
return PsiUtil.resolveClassInType(myPsiType);
}
public boolean isAssignableFrom(PsiClass psiClass) {
return myPsiType.isAssignableFrom(JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory().createType(psiClass));
}
@Nullable
public static TargetType create(final PsiArrayType arrayType) {
public static TargetType create(PsiType type) {
if (type instanceof PsiArrayType) {
return create((PsiArrayType)type);
}
else if (type instanceof PsiClassType) {
return create((PsiClassType)type);
}
return null;
}
@Nullable
private static TargetType create(PsiArrayType arrayType) {
PsiType currentComponentType = arrayType.getComponentType();
while (currentComponentType instanceof PsiArrayType) {
currentComponentType = ((PsiArrayType)currentComponentType).getComponentType();
@@ -59,18 +76,18 @@ public class TargetType {
if (!(currentComponentType instanceof PsiClassType)) {
return null;
}
final String targetQName = arrayType.getCanonicalText();
String targetQName = arrayType.getCanonicalText();
return new TargetType(targetQName, true, arrayType);
}
@Nullable
public static TargetType create(final PsiClassType classType) {
final PsiClassType.ClassResolveResult resolvedGenerics = classType.resolveGenerics();
final PsiClass resolvedClass = resolvedGenerics.getElement();
private static TargetType create(PsiClassType classType) {
PsiClassType.ClassResolveResult resolvedGenerics = classType.resolveGenerics();
PsiClass resolvedClass = resolvedGenerics.getElement();
if (resolvedClass == null) {
return null;
}
final String classQName = resolvedClass.getQualifiedName();
String classQName = resolvedClass.getQualifiedName();
if (classQName == null) {
return null;
}
@@ -1,38 +0,0 @@
/*
* 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.compiler.classFilesIndex.api.index;
import com.intellij.openapi.project.Project;
import org.jetbrains.jps.classFilesIndex.indexer.api.ClassFileIndexerFactory;
/**
* @author Dmitry Batkovich
*/
public abstract class ClassFilesIndexConfigure<K, V> {
public abstract String getIndexCanonicalName();
public abstract int getIndexVersion();
public abstract Class<? extends ClassFileIndexerFactory> getIndexerBuilderClass();
public abstract ClassFilesIndexReaderBase<K, V> createIndexReader(final Project project);
public void prepareToIndexing(final Project project) {
ClassFilesIndexReaderBase.checkIndexAndRecreateIfNeed(project, getIndexVersion(), getIndexCanonicalName());
}
}
@@ -1,76 +0,0 @@
/*
* 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.compiler.classFilesIndex.api.index;
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexConfigure;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.registry.RegistryValue;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
/**
* @author Dmitry Batkovich
*/
@SuppressWarnings("unchecked")
public enum ClassFilesIndexFeature {
METHOD_CHAINS_COMPLETION("completion.enable.relevant.method.chain.suggestions", MethodsUsageIndexConfigure.INSTANCE);
@NotNull
private final String myKey;
@NotNull
private final Collection<? extends ClassFilesIndexConfigure> myRequiredIndicesConfigures;
ClassFilesIndexFeature(@NotNull final String key,
@NotNull final Collection<? extends ClassFilesIndexConfigure> requiredIndicesConfigures) {
myKey = key;
myRequiredIndicesConfigures = requiredIndicesConfigures;
}
ClassFilesIndexFeature(@NotNull final String key, @NotNull final ClassFilesIndexConfigure requiredConfigure) {
this(key, Collections.<ClassFilesIndexConfigure>singleton(requiredConfigure));
}
public RegistryValue getRegistryValue() {
return Registry.get(myKey);
}
@NotNull
public String getKey() {
return myKey;
}
/**
* is feature enabled by registry key
*/
public boolean isEnabled() {
return Registry.is(myKey);
}
public void enable() {
getRegistryValue().setValue(true);
}
public void disable() {
getRegistryValue().setValue(false);
}
@NotNull
public Collection<? extends ClassFilesIndexConfigure> getRequiredIndicesConfigures() {
return myRequiredIndicesConfigures;
}
}
@@ -1,178 +0,0 @@
/*
* 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.compiler.classFilesIndex.api.index;
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexConfigure;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileTask;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.openapi.util.registry.RegistryValueListener;
import com.intellij.util.Processor;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* @author Dmitry Batkovich
*/
public class ClassFilesIndexFeaturesHolder extends AbstractProjectComponent {
private final Map<ClassFilesIndexConfigure, ClassFilesIndexReaderBase> myEnabledIndexReaders =
new HashMap<>();
private final Map<ClassFilesIndexFeature, FeatureState> myEnabledFeatures = new HashMap<>();
public static ClassFilesIndexFeaturesHolder getInstance(final Project project) {
return project.getComponent(ClassFilesIndexFeaturesHolder.class);
}
protected ClassFilesIndexFeaturesHolder(final Project project) {
super(project);
}
@Override
public final void projectOpened() {
for (final ClassFilesIndexFeature feature : ClassFilesIndexFeature.values()) {
final RegistryValue registryValue = feature.getRegistryValue();
registryValue.addListener(new RegistryValueListener.Adapter() {
@Override
public void afterValueChanged(final RegistryValue rawValue) {
if (!rawValue.asBoolean() && myEnabledFeatures.containsKey(feature)) {
disposeFeature(feature);
}
}
}, myProject);
}
final CompilerManager compilerManager = CompilerManager.getInstance(myProject);
compilerManager.addBeforeTask(new CompileTask() {
@Override
public boolean execute(final CompileContext context) {
close();
return true;
}
});
}
public synchronized boolean enableFeatureIfNeed(final ClassFilesIndexFeature feature) {
if (!feature.isEnabled()) {
return false;
}
FeatureState state = myEnabledFeatures.get(feature);
if (state == null) {
state = initializeFeature(feature);
}
return state == FeatureState.AVAILABLE;
}
public synchronized void visitConfigures(final ConfigureVisitor visitor) {
for (final ClassFilesIndexConfigure configure : myEnabledIndexReaders.keySet()) {
visitor.visit(configure, true);
}
for (final ClassFilesIndexFeature feature : ClassFilesIndexFeature.values()) {
if (feature.isEnabled() && !myEnabledFeatures.containsKey(feature)) {
for (final ClassFilesIndexConfigure configure : feature.getRequiredIndicesConfigures()) {
if (!myEnabledIndexReaders.containsKey(configure)) {
visitor.visit(configure, false);
}
}
}
}
}
private synchronized void disposeFeature(final ClassFilesIndexFeature featureToRemove) {
for (final ClassFilesIndexConfigure requiredConfigure : featureToRemove.getRequiredIndicesConfigures()) {
boolean needClose = true;
for (final ClassFilesIndexFeature enabledFeature : myEnabledFeatures.keySet()) {
if (!enabledFeature.equals(featureToRemove) && enabledFeature.getRequiredIndicesConfigures().contains(requiredConfigure)) {
needClose = false;
break;
}
}
if (needClose) {
final ClassFilesIndexReaderBase readerToClose = myEnabledIndexReaders.remove(requiredConfigure);
readerToClose.close();
}
}
myEnabledFeatures.remove(featureToRemove);
}
private synchronized FeatureState initializeFeature(final ClassFilesIndexFeature feature) {
if (myEnabledFeatures.containsKey(feature)) {
throw new IllegalStateException(String.format("feature %s already contains", feature.getKey()));
}
final Map<ClassFilesIndexConfigure, ClassFilesIndexReaderBase> newIndices =
new HashMap<>();
FeatureState newFeatureState = FeatureState.AVAILABLE;
for (final ClassFilesIndexConfigure requiredConfigure : feature.getRequiredIndicesConfigures()) {
boolean isIndexAlreadyLoaded = false;
for (final ClassFilesIndexFeature enabledFeature : myEnabledFeatures.keySet()) {
if (enabledFeature.getRequiredIndicesConfigures().contains(requiredConfigure)) {
isIndexAlreadyLoaded = true;
break;
}
}
if (!isIndexAlreadyLoaded) {
final ClassFilesIndexReaderBase reader = requiredConfigure.createIndexReader(myProject);
newIndices.put(requiredConfigure, reader);
if (reader.isEmpty()) {
newFeatureState = FeatureState.NOT_AVAILABLE;
}
}
}
myEnabledIndexReaders.putAll(newIndices);
myEnabledFeatures.put(feature, newFeatureState);
return newFeatureState;
}
private synchronized void close() {
for (final ClassFilesIndexReaderBase reader : myEnabledIndexReaders.values()) {
reader.close();
}
myEnabledIndexReaders.clear();
myEnabledFeatures.clear();
}
@Override
public void projectClosed() {
close();
}
/**
* try to find index with corresponding class only in currently enabled indexes
*/
@Nullable
@SuppressWarnings("unchecked")
public <T extends ClassFilesIndexReaderBase> T getAvailableIndexReader(final Class<T> tClass) {
final String indexReaderClassName = tClass.getCanonicalName();
for (final ClassFilesIndexReaderBase reader : myEnabledIndexReaders.values()) {
if (reader.getClass().getCanonicalName().equals(indexReaderClassName)) {
return (T)reader;
}
}
throw new RuntimeException(String.format("index reader for class %s not found", indexReaderClassName));
}
public Project getProject() {
return myProject;
}
private enum FeatureState {
AVAILABLE,
NOT_AVAILABLE
}
}
@@ -1,165 +0,0 @@
/*
* 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.compiler.classFilesIndex.api.index;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
import org.jetbrains.jps.classFilesIndex.indexer.api.IndexState;
import org.jetbrains.jps.classFilesIndex.indexer.api.storage.ClassFilesIndexStorageBase;
import org.jetbrains.jps.incremental.storage.BuildDataManager;
import java.io.File;
import java.io.IOException;
/**
* @author Dmitry Batkovich
*/
public abstract class ClassFilesIndexReaderBase<K, V> {
public static final String VERSION_FILE_NAME = "version";
private final static Logger LOG = Logger.getInstance(ClassFilesIndexReaderBase.class);
@Nullable
protected final ClassFilesIndexStorageReader<K, V> myIndex;
@Nullable
protected final Mappings myMappings;
public static boolean checkIndexAndRecreateIfNeed(final Project project, final int currentVersion, final String canonicalIndexName) {
final File projectBuildSystemDirectory = BuildManager.getInstance().getProjectSystemDirectory(project);
assert projectBuildSystemDirectory != null;
final File versionFile = new File(ClassFilesIndexStorageBase.getIndexDir(canonicalIndexName, projectBuildSystemDirectory), VERSION_FILE_NAME);
final File indexDir = ClassFilesIndexStorageBase.getIndexDir(canonicalIndexName, projectBuildSystemDirectory);
if (versionFile.exists() &&
!versionDiffers(projectBuildSystemDirectory, canonicalIndexName, currentVersion) &&
IndexState.load(indexDir) == IndexState.EXIST) {
return true;
}
else {
recreateIndex(canonicalIndexName, currentVersion, projectBuildSystemDirectory, indexDir);
return false;
}
}
@SuppressWarnings("ConstantConditions")
protected ClassFilesIndexReaderBase(final KeyDescriptor<K> keyDescriptor,
final DataExternalizer<V> valueExternalizer,
final String canonicalIndexName,
final int indexVersion,
final Project project) {
if (checkIndexAndRecreateIfNeed(project, indexVersion, canonicalIndexName)) {
ClassFilesIndexStorageReader<K, V> index = null;
IOException exception = null;
final File projectBuildSystemDirectory = BuildManager.getInstance().getProjectSystemDirectory(project);
final File indexDir = ClassFilesIndexStorageBase.getIndexDir(canonicalIndexName, projectBuildSystemDirectory);
try {
index = new ClassFilesIndexStorageReader<>(indexDir, keyDescriptor, valueExternalizer);
}
catch (final IOException e) {
exception = e;
PersistentHashMap.deleteFilesStartingWith(ClassFilesIndexStorageBase.getIndexFile(indexDir));
}
if (exception != null) {
recreateIndex(canonicalIndexName, indexVersion, projectBuildSystemDirectory, indexDir);
myIndex = null;
myMappings = null;
}
else {
myIndex = index;
try {
myMappings = new Mappings(BuildDataManager.getMappingsRoot(projectBuildSystemDirectory),false);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
}
else {
myIndex = null;
myMappings = null;
}
}
private static void recreateIndex(final String canonicalIndexName,
final int indexVersion,
final File projectBuildSystemDirectory,
final File indexDir) {
if (indexDir.exists()) {
FileUtil.delete(indexDir);
}
try {
FileUtil.writeToFile(new File(ClassFilesIndexStorageBase.getIndexDir(canonicalIndexName, projectBuildSystemDirectory), VERSION_FILE_NAME),
String.valueOf(indexVersion));
}
catch (final IOException e) {
throw new RuntimeException(e);
}
IndexState.NOT_EXIST.save(indexDir);
}
public boolean isEmpty() {
return myIndex == null;
}
public final void close() {
if (myIndex != null) {
try {
myIndex.close();
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
if (myMappings != null) {
myMappings.close();
}
}
public final void delete() {
try {
if (myIndex != null) {
myIndex.delete();
}
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
private static File getVersionFile(final File projectBuildSystemDirectory, final String canonicalIndexName) {
return new File(ClassFilesIndexStorageBase.getIndexDir(canonicalIndexName, projectBuildSystemDirectory), VERSION_FILE_NAME);
}
private static boolean versionDiffers(final File projectBuildSystemDirectory, final String canonicalIndexName, final int currentVersion) {
final File versionFile = getVersionFile(projectBuildSystemDirectory, canonicalIndexName);
if (!versionFile.exists()) {
return true;
}
try {
return Integer.parseInt(FileUtil.loadFile(versionFile)) != currentVersion;
}
catch (final IOException e) {
LOG.error("error while reading version file " + versionFile.getAbsolutePath());
return true;
}
}
}
@@ -1,39 +0,0 @@
/*
* Copyright 2000-2014 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.compiler.classFilesIndex.api.index;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.jps.classFilesIndex.indexer.api.storage.ClassFilesIndexStorageBase;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
/**
* @author Dmitry Batkovich
*/
public class ClassFilesIndexStorageReader<K, V> extends ClassFilesIndexStorageBase<K, V> {
public ClassFilesIndexStorageReader(final File indexDir,
final KeyDescriptor<K> keyDescriptor,
final DataExternalizer<V> valueExternalizer) throws IOException {
super(indexDir, keyDescriptor, valueExternalizer);
}
public Collection<V> getData(final K key) {
return myCache.get(key).getValues();
}
}
@@ -1,56 +0,0 @@
/*
* 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.compiler.classFilesIndex.api.index;
import com.intellij.compiler.server.BuildProcessParametersProvider;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.classFilesIndex.indexer.api.ClassFilesIndicesBuilder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Dmitry Batkovich
*/
public class ClassFilesIndexerBuilderParametersProvider extends BuildProcessParametersProvider {
private final ClassFilesIndexFeaturesHolder myIndicesHolder;
protected ClassFilesIndexerBuilderParametersProvider(final ClassFilesIndexFeaturesHolder indicesHolder) {
myIndicesHolder = indicesHolder;
}
@NotNull
@Override
public List<String> getVMArguments() {
final List<String> args = new ArrayList<>();
myIndicesHolder.visitConfigures(new ConfigureVisitor() {
@Override
public void visit(ClassFilesIndexConfigure<?, ?> configure, boolean isAvailable) {
final String className = configure.getIndexerBuilderClass().getCanonicalName();
args.add(className);
if (!isAvailable) {
configure.prepareToIndexing(myIndicesHolder.getProject());
}
}
});
return args.size() != 0
? Collections.singletonList("-D" + ClassFilesIndicesBuilder.PROPERTY_NAME + "=" + StringUtil.join(args, ";"))
: Collections.<String>emptyList();
}
}
@@ -1,129 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextRelevantStaticMethod;
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexReader;
import com.intellij.compiler.classFilesIndex.impl.UsageIndexValue;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
public class CachedRelevantStaticMethodSearcher {
private final HashMap<MethodIncompleteSignature, PsiMethod> myCachedResolveResults = new HashMap<>();
private final MethodsUsageIndexReader myIndexReader;
private final ChainCompletionContext myCompletionContext;
public CachedRelevantStaticMethodSearcher(final ChainCompletionContext completionContext) {
myIndexReader = MethodsUsageIndexReader.getInstance(completionContext.getProject());
myCompletionContext = completionContext;
}
@NotNull
public List<ContextRelevantStaticMethod> getRelevantStaticMethods(final String resultQualifiedClassName, final int minOccurrence) {
if (resultQualifiedClassName == null ||
ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(resultQualifiedClassName) ||
myCompletionContext.getTarget().getClassQName().equals(resultQualifiedClassName)) {
return Collections.emptyList();
}
final TreeSet<UsageIndexValue> indexValues = myIndexReader.getMethods(resultQualifiedClassName);
if (!indexValues.isEmpty()) {
int occurrences = 0;
final List<ContextRelevantStaticMethod> relevantMethods = new ArrayList<>();
for (final UsageIndexValue indexValue : extractStaticMethods(indexValues)) {
final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature();
final PsiMethod method;
if (myCachedResolveResults.containsKey(methodInvocation)) {
method = myCachedResolveResults.get(methodInvocation);
}
else {
final PsiMethod[] methods = myCompletionContext.resolveNotDeprecated(methodInvocation);
method = MethodChainsSearchUtil
.getMethodWithMinNotPrimitiveParameters(methods, Collections.singleton(myCompletionContext.getTarget().getClassQName()));
myCachedResolveResults.put(methodInvocation, method);
if (method == null) {
return Collections.emptyList();
}
}
if (method == null) {
return Collections.emptyList();
}
if (method.hasModifierProperty(PsiModifier.PUBLIC)) {
if (isMethodValid(method, myCompletionContext, resultQualifiedClassName)) {
occurrences += indexValue.getOccurrences();
if (myCompletionContext.getResolveScope().contains(method.getContainingFile().getVirtualFile())) {
relevantMethods.add(new ContextRelevantStaticMethod(method, null));
}
if (occurrences >= minOccurrence) {
return relevantMethods;
}
}
}
}
}
return Collections.emptyList();
}
private static List<UsageIndexValue> extractStaticMethods(final TreeSet<UsageIndexValue> indexValues) {
final List<UsageIndexValue> relevantStaticMethods = new SmartList<>();
for (final UsageIndexValue indexValue : indexValues) {
if (indexValue.getMethodIncompleteSignature().isStatic()) {
relevantStaticMethods.add(indexValue);
}
}
return relevantStaticMethods;
}
private static boolean isMethodValid(final @Nullable PsiMethod method,
final ChainCompletionContext completionContext,
final String targetTypeShortName) {
if (method == null) return false;
for (final PsiParameter parameter : method.getParameterList().getParameters()) {
final PsiType type = parameter.getType();
final String shortClassName = typeAsShortString(type);
if (targetTypeShortName.equals(shortClassName)) return false;
if (!ChainCompletionStringUtil.isShortNamePrimitiveOrArrayOfPrimitives(shortClassName) &&
!completionContext.contains(type.getCanonicalText())) {
return false;
}
}
return true;
}
@Nullable
public static String typeAsShortString(final PsiType type) {
if (type instanceof PsiClassType)
return ((PsiClassType) type).getClassName();
else if (type instanceof PsiPrimitiveType)
return type.getCanonicalText();
else if (type instanceof PsiArrayType) {
final String componentTypeAsString = typeAsShortString(((PsiArrayType)type).getComponentType());
if (componentTypeAsString == null) return null;
return String.format("%s[]", componentTypeAsString);
}
return null;
}
}
@@ -1,92 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
/**
* @author Dmitry Batkovich
*/
public final class ChainCompletionStringUtil {
private ChainCompletionStringUtil() {}
/**
* CAUTION: isPrimitiveOrArrayOfPrimitives("java.lang.String") == true,
* isPrimitiveOrArrayOfPrimitives("java.lang.Object") == true
* isPrimitiveOrArrayOfPrimitives("java.lang.Class") == true
*/
public static boolean isPrimitiveOrArrayOfPrimitives(final @Nullable String typeQName) {
if (typeQName == null) {
return false;
}
return PRIMITIVES_NAMES.contains(deleteArraySigns(typeQName));
}
public static boolean isShortNamePrimitiveOrArrayOfPrimitives(final @Nullable String shortName) {
if (shortName == null) {
return false;
}
return PRIMITIVES_SHORT_NAMES.contains(deleteArraySigns(shortName));
}
private static String deleteArraySigns(final @NotNull String typeName) {
String nameWithoutArraySign = typeName;
while (nameWithoutArraySign.endsWith("[]")) {
nameWithoutArraySign = nameWithoutArraySign.substring(0, nameWithoutArraySign.length() - 2);
}
return nameWithoutArraySign;
}
private static final Set<String> PRIMITIVES_NAMES = new HashSet<>();
private static final Set<String> PRIMITIVES_SHORT_NAMES = new HashSet<>();
static {
fillPrimitivesNames(PsiType.BOOLEAN);
fillPrimitivesNames(PsiType.INT);
fillPrimitivesNames(PsiType.LONG);
fillPrimitivesNames(PsiType.DOUBLE);
fillPrimitivesNames(PsiType.FLOAT);
fillPrimitivesNames(PsiType.SHORT);
fillPrimitivesNames(PsiType.CHAR);
fillPrimitivesNames(PsiType.BYTE);
fillPrimitivesNames(PsiType.VOID);
fillNonPrimitiveNames(CommonClassNames.JAVA_LANG_STRING);
fillNonPrimitiveNames(CommonClassNames.JAVA_LANG_OBJECT);
fillNonPrimitiveNames(CommonClassNames.JAVA_LANG_CLASS);
}
private static void fillNonPrimitiveNames(final String typeAsString) {
PRIMITIVES_NAMES.add(typeAsString);
PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(typeAsString));
}
private static void fillPrimitivesNames(final PsiPrimitiveType type) {
PRIMITIVES_NAMES.add(type.getBoxedTypeName());
PRIMITIVES_NAMES.add(type.getCanonicalText());
PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(type.getBoxedTypeName()));
PRIMITIVES_SHORT_NAMES.add(type.getCanonicalText());
}
}
@@ -1,317 +0,0 @@
/*
* Copyright 2000-2014 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.TargetType;
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexReader;
import com.intellij.compiler.classFilesIndex.impl.UsageIndexValue;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
public final class ChainsSearcher {
private ChainsSearcher() {
}
private static final Logger LOG = Logger.getInstance(ChainsSearcher.class);
private static final double NEXT_METHOD_IN_CHAIN_RATIO = 1.5;
@NotNull
public static List<MethodsChain> search(final int pathMaximalLength,
final TargetType targetType,
final Set<String> contextQNames,
final int maxResultSize,
final ChainCompletionContext context,
final MethodsUsageIndexReader methodsUsageIndexReader) {
final SearchInitializer initializer = createInitializer(targetType, context.getExcludedQNames(), methodsUsageIndexReader, context);
if (initializer == null) {
return Collections.emptyList();
}
return search(methodsUsageIndexReader,
initializer,
contextQNames,
pathMaximalLength,
maxResultSize,
targetType.getClassQName(),
context);
}
@Nullable
private static SearchInitializer createInitializer(final TargetType target,
final Set<String> excludedParamsTypesQNames,
final MethodsUsageIndexReader methodsUsageIndexReader,
final ChainCompletionContext context) {
final SortedSet<UsageIndexValue> methods = methodsUsageIndexReader.getMethods(target.getClassQName());
return new SearchInitializer(methods, target.getClassQName(), excludedParamsTypesQNames, context);
}
@NotNull
private static List<MethodsChain> search(final MethodsUsageIndexReader indexReader,
final SearchInitializer initializer,
final Set<String> toSet,
final int pathMaximalLength,
final int maxResultSize,
final String targetQName,
final ChainCompletionContext context) {
final Set<String> allExcludedNames = MethodChainsSearchUtil.joinToHashSet(context.getExcludedQNames(), targetQName);
final SearchInitializer.InitResult initResult = initializer.init(Collections.<String>emptySet());
final Map<MethodIncompleteSignature, MethodsChain> knownDistance = initResult.getChains();
final List<WeightAware<MethodIncompleteSignature>> allInitialVertexes = initResult.getVertexes();
final LinkedList<WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>> q =
new LinkedList<>(ContainerUtil.map(allInitialVertexes,
methodIncompleteSignatureWeightAware -> {
final MethodIncompleteSignature underlying =
methodIncompleteSignatureWeightAware.getUnderlying();
return new WeightAware<>(
Pair.create(
underlying,
new MethodsChain(context
.resolveNotDeprecated(
underlying),
methodIncompleteSignatureWeightAware
.getWeight(),
underlying
.getOwner())),
methodIncompleteSignatureWeightAware
.getWeight()
);
}
));
int maxWeight = 0;
for (final MethodsChain methodsChain : knownDistance.values()) {
if (methodsChain.getChainWeight() > maxWeight) {
maxWeight = methodsChain.getChainWeight();
}
}
final ResultHolder result = new ResultHolder(context.getPsiManager());
while (!q.isEmpty()) {
ProgressManager.checkCanceled();
final WeightAware<Pair<MethodIncompleteSignature, MethodsChain>> currentVertex = q.poll();
final int currentVertexDistance = currentVertex.getWeight();
final Pair<MethodIncompleteSignature, MethodsChain> currentVertexUnderlying = currentVertex.getUnderlying();
final MethodsChain currentVertexMethodsChain = knownDistance.get(currentVertexUnderlying.getFirst());
if (currentVertexDistance != currentVertexMethodsChain.getChainWeight()) {
continue;
}
if (currentVertex.getUnderlying().getFirst().isStatic() || toSet.contains(currentVertex.getUnderlying().getFirst().getOwner())) {
result.add(currentVertex.getUnderlying().getSecond());
continue;
}
final String currentReturnType = currentVertexUnderlying.getFirst().getOwner();
final SortedSet<UsageIndexValue> nextMethods = indexReader.getMethods(currentReturnType);
final MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>> currentSignatures =
new MaxSizeTreeSet<>(maxResultSize);
for (final UsageIndexValue indexValue : nextMethods) {
final MethodIncompleteSignature vertex = indexValue.getMethodIncompleteSignature();
final int occurrences = indexValue.getOccurrences();
if (vertex.isStatic() || !vertex.getOwner().equals(targetQName)) {
final int vertexDistance = Math.min(currentVertexDistance, occurrences);
final MethodsChain knownVertexMethodsChain = knownDistance.get(vertex);
if ((knownVertexMethodsChain == null || knownVertexMethodsChain.getChainWeight() < vertexDistance)) {
if (currentSignatures.isEmpty() || currentSignatures.last().getWeight() < vertexDistance) {
if (currentVertexMethodsChain.size() < pathMaximalLength - 1) {
final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature();
final PsiMethod[] psiMethods = context.resolveNotDeprecated(methodInvocation);
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, allExcludedNames)) {
final MethodsChain newBestMethodsChain =
currentVertexMethodsChain.addEdge(psiMethods, indexValue.getMethodIncompleteSignature().getOwner(), vertexDistance);
currentSignatures
.add(new WeightAware<>(indexValue.getMethodIncompleteSignature(), vertexDistance));
knownDistance.put(vertex, newBestMethodsChain);
}
}
}
}
else {
break;
}
}
}
boolean updated = false;
if (!currentSignatures.isEmpty()) {
boolean isBreak = false;
for (final WeightAware<MethodIncompleteSignature> sign : currentSignatures) {
final PsiMethod[] resolved = context.resolveNotDeprecated(sign.getUnderlying());
if (!isBreak) {
if (sign.getWeight() * NEXT_METHOD_IN_CHAIN_RATIO > currentVertex.getWeight()) {
final boolean stopChain = sign.getUnderlying().isStatic() || toSet.contains(sign.getUnderlying().getOwner());
if (stopChain) {
updated = true;
result.add(currentVertex.getUnderlying().getSecond().addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight()));
continue;
}
else {
updated = true;
final MethodsChain methodsChain =
currentVertexUnderlying.second.addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight());
q.add(new WeightAware<>(
Pair.create(sign.getUnderlying(), methodsChain), sign.getWeight()));
continue;
}
}
}
final MethodsChain methodsChain =
currentVertexUnderlying.second.addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight());
final ParametersMatcher.MatchResult parametersMatchResult = ParametersMatcher.matchParameters(methodsChain, context);
if (parametersMatchResult.noUnmatchedAndHasMatched() && parametersMatchResult.hasTarget()) {
updated = true;
q.addFirst(new WeightAware<>(
Pair.create(sign.getUnderlying(), methodsChain), sign.getWeight()));
}
isBreak = true;
}
}
if (!updated &&
(currentVertex.getUnderlying().getFirst().isStatic() ||
!targetQName.equals(currentVertex.getUnderlying().getFirst().getOwner()))) {
result.add(currentVertex.getUnderlying().getSecond());
}
if (result.size() > maxResultSize) {
return result.getResult();
}
}
return result.getResult();
}
private static MethodsChain createChainFromFirstElement(final MethodsChain chain, final PsiClass newQualifierClass) {
final String qualifiedClassName = newQualifierClass.getQualifiedName();
if (qualifiedClassName == null) {
throw new IllegalArgumentException();
}
return new MethodsChain(chain.getFirst(), chain.getChainWeight(), qualifiedClassName);
}
private static class ResultHolder {
private final List<MethodsChain> myResult;
private final PsiManager myContext;
private ResultHolder(final PsiManager psiManager) {
myContext = psiManager;
myResult = new ArrayList<>();
}
public void add(final MethodsChain newChain) {
if (myResult.isEmpty()) {
myResult.add(newChain);
return;
}
boolean doAdd = true;
final Stack<Integer> indexesToRemove = new Stack<>();
for (int i = 0; i < myResult.size(); i++) {
final MethodsChain chain = myResult.get(i);
//
final MethodsChain.CompareResult r = MethodsChain.compare(chain, newChain, myContext);
switch (r) {
case LEFT_CONTAINS_RIGHT:
indexesToRemove.add(i);
break;
case RIGHT_CONTAINS_LEFT:
case EQUAL:
doAdd = false;
break;
case NOT_EQUAL:
break;
}
}
while (!indexesToRemove.empty()) {
myResult.remove((int)indexesToRemove.pop());
}
if (doAdd) {
myResult.add(newChain);
}
}
public List<MethodsChain> getRawResult() {
return myResult;
}
public List<MethodsChain> getResult() {
return findSimilar(reduceChainsSize(myResult, PsiManager.getInstance(myContext.getProject())), myContext);
}
public int size() {
return myResult.size();
}
private static List<MethodsChain> reduceChainsSize(final List<MethodsChain> chains, final PsiManager psiManager) {
return ContainerUtil.map(chains, chain -> {
final Iterator<PsiMethod[]> chainIterator = chain.iterator();
if (!chainIterator.hasNext()) {
LOG.error("empty chain");
return chain;
}
final PsiMethod[] first = chainIterator.next();
while (chainIterator.hasNext()) {
final PsiMethod psiMethod = chainIterator.next()[0];
if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
continue;
}
final PsiClass current = psiMethod.getContainingClass();
if (current == null) {
LOG.error("containing class must be not null");
return chain;
}
final PsiMethod[] currentMethods = current.findMethodsByName(first[0].getName(), true);
if (currentMethods.length != 0) {
for (final PsiMethod f : first) {
final PsiMethod[] fSupers = f.findDeepestSuperMethods();
final PsiMethod fSuper = fSupers.length == 0 ? first[0] : fSupers[0];
for (final PsiMethod currentMethod : currentMethods) {
if (psiManager.areElementsEquivalent(currentMethod, fSuper)) {
return createChainFromFirstElement(chain, currentMethod.getContainingClass());
}
for (final PsiMethod method : currentMethod.findDeepestSuperMethods()) {
if (psiManager.areElementsEquivalent(method, fSuper)) {
return createChainFromFirstElement(chain, method.getContainingClass());
}
}
}
}
}
}
return chain;
});
}
private static List<MethodsChain> findSimilar(final List<MethodsChain> chains, final PsiManager psiManager) {
final ResultHolder resultHolder = new ResultHolder(psiManager);
for (final MethodsChain chain : chains) {
resultHolder.add(chain);
}
return resultHolder.getRawResult();
}
}
}
@@ -1,222 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
public class MaxSizeTreeSet<E> implements NavigableSet<E> {
@NotNull
private final NavigableSet<E> myUnderlying;
private final int myMaxSize;
public MaxSizeTreeSet(final int maxSize) {
myMaxSize = maxSize;
if (myMaxSize < 1) {
throw new IllegalArgumentException();
}
myUnderlying = new TreeSet<>();
}
public E lower(final E e) {
return myUnderlying.lower(e);
}
public E floor(final E e) {
return myUnderlying.floor(e);
}
public E ceiling(final E e) {
return myUnderlying.ceiling(e);
}
public E higher(final E e) {
return myUnderlying.higher(e);
}
@Override
public E pollFirst() {
return myUnderlying.pollFirst();
}
@Override
public E pollLast() {
return myUnderlying.pollLast();
}
@NotNull
@Override
public Iterator<E> iterator() {
return myUnderlying.iterator();
}
@NotNull
@Override
public NavigableSet<E> descendingSet() {
return myUnderlying.descendingSet();
}
@NotNull
@Override
public Iterator<E> descendingIterator() {
return myUnderlying.descendingIterator();
}
@NotNull
public NavigableSet<E> subSet(final E fromElement, final boolean fromInclusive, final E toElement, final boolean toInclusive) {
return myUnderlying.subSet(fromElement, fromInclusive, toElement, toInclusive);
}
@NotNull
public NavigableSet<E> headSet(final E toElement, final boolean inclusive) {
return myUnderlying.headSet(toElement, inclusive);
}
@NotNull
public NavigableSet<E> tailSet(final E fromElement, final boolean inclusive) {
return myUnderlying.tailSet(fromElement, inclusive);
}
@NotNull
public SortedSet<E> subSet(final E fromElement, final E toElement) {
return myUnderlying.subSet(fromElement, toElement);
}
@NotNull
public SortedSet<E> headSet(final E toElement) {
return myUnderlying.headSet(toElement);
}
@NotNull
public SortedSet<E> tailSet(final E fromElement) {
return myUnderlying.tailSet(fromElement);
}
@Nullable
@Override
public Comparator<? super E> comparator() {
return myUnderlying.comparator();
}
@Override
public E first() {
return myUnderlying.first();
}
@Override
public E last() {
return myUnderlying.last();
}
@Override
public int size() {
return myUnderlying.size();
}
@Override
public boolean isEmpty() {
return myUnderlying.isEmpty();
}
@Override
public boolean contains(final Object o) {
return myUnderlying.contains(o);
}
@NotNull
@Override
public Object[] toArray() {
return myUnderlying.toArray();
}
@NotNull
@Override
public <T> T[] toArray(final T[] a) {
return myUnderlying.toArray(a);
}
public boolean add(final E e) {
if (myUnderlying.size() == myMaxSize) {
//noinspection ConstantConditions
final Comparator<? super E> comparator = comparator();
if ((comparator == null ? ((Comparable)e).compareTo(last()) : comparator.compare(e, last())) < 0) {
final boolean isAdded = myUnderlying.add(e);
if (isAdded) {
pollLast();
return true;
}
}
return false;
}
return myUnderlying.add(e);
}
@Override
public boolean remove(final Object o) {
return myUnderlying.remove(o);
}
@Override
public boolean containsAll(final Collection<?> c) {
return myUnderlying.containsAll(c);
}
public boolean addAll(final Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(final Collection<?> c) {
return myUnderlying.retainAll(c);
}
@Override
public boolean removeAll(final Collection<?> c) {
return myUnderlying.removeAll(c);
}
@Override
public void clear() {
myUnderlying.clear();
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof MaxSizeTreeSet)) return false;
final MaxSizeTreeSet that = (MaxSizeTreeSet)o;
if (!myUnderlying.equals(that.myUnderlying)) return false;
return true;
}
@Override
public int hashCode() {
return myUnderlying.hashCode();
}
@Override
public String toString() {
return myUnderlying.toString();
}
}
@@ -1,92 +0,0 @@
/*
* Copyright 2000-2014 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @author Dmitry Batkovich
*/
public final class MethodChainsSearchUtil {
private MethodChainsSearchUtil() {
}
@Nullable
public static PsiMethod getMethodWithMinNotPrimitiveParameters(final @NotNull PsiMethod[] methods,
final Set<String> excludedParamsQNames) {
PsiMethod minMethod = null;
int minParametersCount = Integer.MAX_VALUE;
for (final PsiMethod method : methods) {
final PsiParameterList parameterList = method.getParameterList();
boolean doContinue = false;
int parametersCount = parameterList.getParametersCount();
for (final PsiParameter p : parameterList.getParameters()) {
if (!(p.getType() instanceof PsiPrimitiveType)) {
if (excludedParamsQNames.contains(p.getType().getCanonicalText())) {
doContinue = true;
break;
}
parametersCount++;
}
}
if (doContinue) {
continue;
}
if (parametersCount < minParametersCount) {
if (parametersCount == 0) {
return method;
}
minParametersCount = parametersCount;
minMethod = method;
}
}
return minMethod;
}
public static boolean checkParametersForTypesQNames(final PsiMethod[] psiMethods, final Set<String> excludedTypesQNames) {
if (psiMethods.length == 0) {
return true;
}
for (final PsiMethod method : psiMethods) {
boolean hasTargetInParams = false;
for (final PsiParameter param : method.getParameterList().getParameters()) {
final String paramType = param.getType().getCanonicalText();
if (excludedTypesQNames.contains(paramType)) {
hasTargetInParams = true;
break;
}
}
if (!hasTargetInParams) {
return true;
}
}
return false;
}
public static <T> HashSet<T> joinToHashSet(final Collection<T> collection, final T... items) {
final HashSet<T> result = new HashSet<>();
result.addAll(collection);
Collections.addAll(result, items);
return result;
}
}
@@ -1,177 +0,0 @@
/*
* Copyright 2000-2014 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import static com.intellij.util.containers.ContainerUtil.findAll;
import static com.intellij.util.containers.ContainerUtil.reverse;
/**
* @author Dmitry Batkovich
*/
public class MethodsChain {
private final List<PsiMethod[]> myRevertedPath;
private final int myWeight;
//
// chain qualifier class could be different with method.getContainingClass()
private final String myQualifierClassName;
private final Set<String> myExcludedQNames;
public MethodsChain(final PsiMethod[] methods, final int weight, final String qualifierClassName) {
this(Collections.singletonList(methods), weight, qualifierClassName, chooseParametersQNames(methods));
}
private MethodsChain(final List<PsiMethod[]> revertedPath,
final int weight,
final String qualifierClassName,
final Set<String> excludedQNames) {
myRevertedPath = revertedPath;
myWeight = weight;
myQualifierClassName = qualifierClassName;
myExcludedQNames = excludedQNames;
}
public int size() {
return myRevertedPath.size();
}
public Set<String> getExcludedQNames() {
return myExcludedQNames;
}
public String getQualifierClassName() {
return myQualifierClassName;
}
public Iterator<PsiMethod[]> iterator() {
return myRevertedPath.iterator();
}
@NotNull
public PsiMethod[] getFirst() {
return myRevertedPath.get(0);
}
public List<PsiMethod[]> getPath() {
return reverse(myRevertedPath);
}
public int getChainWeight() {
return myWeight;
}
@SuppressWarnings("unchecked")
public MethodsChain addEdge(final PsiMethod[] psiMethods, final String newQualifierClassName, final int newWeight) {
final List<PsiMethod[]> newRevertedPath = new ArrayList<>(myRevertedPath.size() + 1);
newRevertedPath.addAll(myRevertedPath);
newRevertedPath.add(psiMethods);
return new MethodsChain(newRevertedPath,
newWeight,
newQualifierClassName,
joinSets(myExcludedQNames, chooseParametersQNames(psiMethods)));
}
@Override
public String toString() {
return StringUtil.join(myRevertedPath, "<-");
}
@SuppressWarnings("ConstantConditions")
public static CompareResult compare(final MethodsChain left, final MethodsChain right, final PsiManager psiManager) {
if (left.size() == 0) {
return CompareResult.RIGHT_CONTAINS_LEFT;
}
if (right.size() == 0) {
return CompareResult.LEFT_CONTAINS_RIGHT;
}
final Iterator<PsiMethod[]> leftIterator = left.myRevertedPath.iterator();
final Iterator<PsiMethod[]> rightIterator = right.myRevertedPath.iterator();
while (leftIterator.hasNext() && rightIterator.hasNext()) {
final PsiMethod thisNext = leftIterator.next()[0];
final PsiMethod thatNext = rightIterator.next()[0];
if (thisNext == null || thatNext == null) {
throw new NullPointerException();
}
if (((thisNext.isConstructor() != thatNext.isConstructor())) || !thisNext.getName().equals(thatNext.getName())) {
return CompareResult.NOT_EQUAL;
}
}
if (leftIterator.hasNext() && !rightIterator.hasNext()) {
return CompareResult.LEFT_CONTAINS_RIGHT;
}
if (!leftIterator.hasNext() && rightIterator.hasNext()) {
return CompareResult.RIGHT_CONTAINS_LEFT;
}
return hasBaseMethod(left.getPath().get(0), right.getPath().get(0), psiManager)
? CompareResult.EQUAL
: CompareResult.NOT_EQUAL;
}
public enum CompareResult {
LEFT_CONTAINS_RIGHT,
RIGHT_CONTAINS_LEFT,
EQUAL,
NOT_EQUAL
}
private static boolean hasBaseMethod(final PsiMethod[] left, final PsiMethod[] right, final PsiManager psiManager) {
for (final PsiMethod rightMethod : right) {
final PsiMethod[] rightSupers = rightMethod.findDeepestSuperMethods();
if (rightSupers.length != 0) {
for (final PsiMethod leftMethod : left) {
final PsiMethod[] leftSupers = leftMethod.findDeepestSuperMethods();
if (leftSupers.length != 0) {
if (psiManager.areElementsEquivalent(leftSupers[0], rightSupers[0])) {
return true;
}
}
}
}
}
return false;
}
private static Set<String> joinSets(final Set<String>... sets) {
final Set<String> result = new HashSet<>();
for (final Set<String> set : sets) {
for (final String s : set) {
result.add(s);
}
}
return result;
}
private static Set<String> chooseParametersQNames(final PsiMethod[] methods) {
final Set<String> qNames = new HashSet<>();
for (final PsiParameter methodParameter : methods[0].getParameterList().getParameters()) {
qNames.add(methodParameter.getType().getCanonicalText());
}
return qNames;
}
}
@@ -1,291 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.completion.JavaChainLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextRelevantStaticMethod;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextRelevantVariableGetter;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.ChainCompletionNewVariableLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.WeightableChainLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.GetterLookupSubLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.VariableSubLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.VariableLookupItem;
import com.intellij.psi.*;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.ChainCompletionLookupElementUtil.createLookupElement;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class MethodsChainLookupRangingHelper {
public static List<LookupElement> chainsToWeightableLookupElements(final List<MethodsChain> chains,
final ChainCompletionContext context) {
final CachedRelevantStaticMethodSearcher staticMethodSearcher = new CachedRelevantStaticMethodSearcher(context);
final List<LookupElement> lookupElements = new ArrayList<>(chains.size());
for (final MethodsChain chain : chains) {
final LookupElement lookupElement = chainToWeightableLookupElement(chain, context, staticMethodSearcher);
if (lookupElement != null) {
lookupElements.add(lookupElement);
}
}
return lookupElements;
}
@SuppressWarnings("ConstantConditions")
@Nullable
private static LookupElement chainToWeightableLookupElement(final MethodsChain chain,
final ChainCompletionContext context,
final CachedRelevantStaticMethodSearcher staticMethodSearcher) {
final int chainSize = chain.size();
assert chainSize != 0;
final int lastMethodWeight = chain.getChainWeight();
int unreachableParametersCount = 0;
int notMatchedStringVars = 0;
int matchedParametersInContext = 0;
Boolean isFirstMethodStatic = null;
Boolean hasCallingVariableInContext = null;
LookupElement chainLookupElement = null;
PsiClass newVariableClass = null;
final NullableNotNullManager nullableNotNullManager = NullableNotNullManager.getInstance(context.getProject());
for (final PsiMethod[] psiMethods : chain.getPath()) {
final PsiMethod method =
MethodChainsSearchUtil.getMethodWithMinNotPrimitiveParameters(psiMethods, Collections.singleton(context.getTarget().getClassQName()));
if (method == null) {
return null;
}
if (isFirstMethodStatic == null) {
isFirstMethodStatic = psiMethods[0].hasModifierProperty(PsiModifier.STATIC);
}
final PsiClass qualifierClass;
final boolean isHead = chainLookupElement == null;
if (isHead) {
final String qualifierClassName = chain.getQualifierClassName();
qualifierClass = JavaPsiFacade.getInstance(context.getProject()).
findClass(qualifierClassName, context.getResolveScope());
}
else {
qualifierClass = null;
}
final MethodProcResult procResult = processMethod(method, qualifierClass, isHead, lastMethodWeight, context, staticMethodSearcher,
nullableNotNullManager);
if (procResult == null) {
return null;
}
if (hasCallingVariableInContext == null) {
hasCallingVariableInContext = procResult.hasCallingVariableInContext();
}
if (isHead && procResult.isIntroduceNewVariable()) {
newVariableClass = qualifierClass;
}
matchedParametersInContext += procResult.getMatchedParametersInContext();
unreachableParametersCount += procResult.getUnreachableParametersCount();
notMatchedStringVars += procResult.getNotMatchedStringVars();
chainLookupElement =
isHead ? procResult.getLookupElement() : new JavaChainLookupElement(chainLookupElement, procResult.getLookupElement());
}
if (newVariableClass != null) {
chainLookupElement = ChainCompletionNewVariableLookupElement.create(newVariableClass, chainLookupElement);
}
final ChainRelevance relevance =
new ChainRelevance(chainSize, lastMethodWeight, unreachableParametersCount, notMatchedStringVars, hasCallingVariableInContext,
isFirstMethodStatic, matchedParametersInContext);
return new WeightableChainLookupElement(chainLookupElement, relevance);
}
@Nullable
private static MethodProcResult processMethod(@NotNull final PsiMethod method,
@Nullable final PsiClass qualifierClass,
final boolean isHeadMethod,
final int weight,
final ChainCompletionContext context,
final CachedRelevantStaticMethodSearcher staticMethodSearcher,
final NullableNotNullManager nullableNotNullManager) {
int unreachableParametersCount = 0;
int notMatchedStringVars = 0;
int matchedParametersInContext = 0;
boolean hasCallingVariableInContext = false;
boolean introduceNewVariable = false;
final PsiParameterList parameterList = method.getParameterList();
final TIntObjectHashMap<SubLookupElement> parametersMap = new TIntObjectHashMap<>(parameterList.getParametersCount());
final PsiParameter[] parameters = parameterList.getParameters();
for (int i = 0; i < parameters.length; i++) {
final PsiParameter parameter = parameters[i];
final String typeQName = parameter.getType().getCanonicalText();
if (JAVA_LANG_STRING.equals(typeQName)) {
final PsiVariable relevantStringVar = context.findRelevantStringInContext(parameter.getName());
if (relevantStringVar == null) {
notMatchedStringVars++;
}
else {
parametersMap.put(i, new VariableSubLookupElement(relevantStringVar));
}
}
else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(typeQName)) {
final Collection<PsiVariable> contextVariables = context.getVariables(typeQName);
final PsiVariable contextVariable = ContainerUtil.getFirstItem(contextVariables, null);
if (contextVariable != null) {
if (contextVariables.size() == 1) parametersMap.put(i, new VariableSubLookupElement(contextVariable));
matchedParametersInContext++;
continue;
}
final Collection<ContextRelevantVariableGetter> relevantVariablesGetters = context.getRelevantVariablesGetters(typeQName);
final ContextRelevantVariableGetter contextVariableGetter = ContainerUtil.getFirstItem(relevantVariablesGetters, null);
if (contextVariableGetter != null) {
if (relevantVariablesGetters.size() == 1) parametersMap.put(i, contextVariableGetter.createSubLookupElement());
matchedParametersInContext++;
continue;
}
final Collection<PsiMethod> containingClassMethods = context.getContainingClassMethods(typeQName);
final PsiMethod contextRelevantGetter = ContainerUtil.getFirstItem(containingClassMethods, null);
if (contextRelevantGetter != null) {
if (containingClassMethods.size() == 1) parametersMap.put(i, new GetterLookupSubLookupElement(method.getName()));
matchedParametersInContext++;
continue;
}
final ContextRelevantStaticMethod contextRelevantStaticMethod =
ContainerUtil.getFirstItem(staticMethodSearcher.getRelevantStaticMethods(typeQName, weight), null);
if (contextRelevantStaticMethod != null) {
//
// In most cases it is not really relevant
//
//parametersMap.put(i, contextRelevantStaticMethod.createLookupElement());
matchedParametersInContext++;
continue;
}
if (!nullableNotNullManager.isNullable(parameter, true)) {
unreachableParametersCount++;
}
}
}
final LookupElement lookupElement;
if (isHeadMethod) {
if (method.hasModifierProperty(PsiModifier.STATIC)) {
hasCallingVariableInContext = true;
lookupElement = createLookupElement(method, parametersMap);
}
else if (method.isConstructor()) {
return null;
}
else {
@SuppressWarnings("ConstantConditions")
final String classQName = qualifierClass.getQualifiedName();
if (classQName == null) return null;
final Object e = ContainerUtil.getFirstItem(context.getContextRefElements(classQName), null);
if (e != null) {
final LookupElement firstChainElement;
if (e instanceof PsiVariable) {
firstChainElement = new VariableLookupItem((PsiVariable)e);
}
else if (e instanceof PsiMethod) {
firstChainElement = createLookupElement((PsiMethod)e, null);
}
else if (e instanceof LookupElement) {
firstChainElement = (LookupElement)e;
}
else {
throw new AssertionError();
}
hasCallingVariableInContext = true;
lookupElement = new JavaChainLookupElement(firstChainElement, createLookupElement(method, parametersMap));
}
else {
lookupElement = createLookupElement(method, parametersMap);
if (!context.getContainingClassQNames().contains(classQName)) {
introduceNewVariable = true;
}
}
}
}
else {
lookupElement = createLookupElement(method, parametersMap);
}
return new MethodProcResult(lookupElement,
unreachableParametersCount,
notMatchedStringVars,
hasCallingVariableInContext,
introduceNewVariable,
matchedParametersInContext);
}
private static class MethodProcResult {
private final LookupElement myMethodLookup;
private final int myUnreachableParametersCount;
private final int myNotMatchedStringVars;
private final boolean myHasCallingVariableInContext;
private final boolean myIntroduceNewVariable;
private final int myMatchedParametersInContext;
private MethodProcResult(final LookupElement methodLookup,
final int unreachableParametersCount,
final int notMatchedStringVars,
final boolean hasCallingVariableInContext,
final boolean introduceNewVariable,
final int matchedParametersInContext) {
myMethodLookup = methodLookup;
myUnreachableParametersCount = unreachableParametersCount;
myNotMatchedStringVars = notMatchedStringVars;
myHasCallingVariableInContext = hasCallingVariableInContext;
myIntroduceNewVariable = introduceNewVariable;
myMatchedParametersInContext = matchedParametersInContext;
}
private boolean isIntroduceNewVariable() {
return myIntroduceNewVariable;
}
private boolean hasCallingVariableInContext() {
return myHasCallingVariableInContext;
}
private LookupElement getLookupElement() {
return myMethodLookup;
}
private int getUnreachableParametersCount() {
return myUnreachableParametersCount;
}
private int getNotMatchedStringVars() {
return myNotMatchedStringVars;
}
public int getMatchedParametersInContext() {
return myMatchedParametersInContext;
}
}
}
@@ -1,111 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;
/**
* @author Dmitry Batkovich
*/
public final class ParametersMatcher {
private ParametersMatcher() {}
public static MatchResult matchParameters(final MethodsChain chain, final ChainCompletionContext context) {
MatchResult overallResult = EMPTY;
for (final PsiMethod[] methods : chain.getPath()) {
final NavigableSet<MatchResult> matchResults = new TreeSet<>();
for (final PsiMethod method : methods) {
matchResults.add(matchParameters(method, context, chain.getExcludedQNames()));
}
final MatchResult best = matchResults.first();
overallResult = overallResult.add(best);
}
return overallResult;
}
private static MatchResult matchParameters(final PsiMethod method, final ChainCompletionContext context, final Set<String> additionalExcludedNames) {
int matched = 0;
int unMatched = 0;
boolean hasTarget = false;
for (final PsiParameter parameter : method.getParameterList().getParameters()) {
final PsiType type = parameter.getType();
final String canonicalText = type.getCanonicalText();
if (context.contains(canonicalText) || type instanceof PsiPrimitiveType) {
matched++;
}
else {
unMatched++;
}
if (context.getTarget().getClassQName().equals(canonicalText) || additionalExcludedNames.contains(canonicalText)) {
hasTarget = true;
}
}
return new MatchResult(matched, unMatched, hasTarget);
}
private static final MatchResult EMPTY = new MatchResult(0, 0, false);
public static class MatchResult implements Comparable<MatchResult> {
private final int myMatched;
private final int myUnMatched;
private final boolean myHasTarget;
private MatchResult(final int matched, final int unMatched, final boolean hasTarget) {
myMatched = matched;
myUnMatched = unMatched;
myHasTarget = hasTarget;
}
public int getMatched() {
return myMatched;
}
public int getUnMatched() {
return myUnMatched;
}
public boolean hasTarget() {
return myHasTarget;
}
public MatchResult add(final MatchResult other) {
return new MatchResult(getMatched() + other.getMatched(), getUnMatched() + other.getUnMatched(), other.myHasTarget || myHasTarget);
}
public boolean noUnmatchedAndHasMatched() {
return myUnMatched == 0 && myMatched != 0;
}
@Override
public int compareTo(@NotNull final MatchResult other) {
final int sub = getUnMatched() - other.getUnMatched();
if (sub != 0) {
return sub;
}
return getMatched() - other.getMatched();
}
}
}
@@ -1,107 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.classFilesIndex.impl.UsageIndexValue;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiMethod;
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
import java.util.*;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class SearchInitializer {
private final static int CHAIN_SEARCH_MAGIC_RATIO = 12;
private final LinkedHashMap<MethodIncompleteSignature, Pair<MethodsChain, Integer>> myChains;
private final ChainCompletionContext myContext;
public SearchInitializer(final SortedSet<UsageIndexValue> indexValues,
final String targetQName,
final Set<String> excludedParamsTypesQNames,
final ChainCompletionContext context) {
myContext = context;
final int size = indexValues.size();
myChains = new LinkedHashMap<>(size);
add(indexValues, MethodChainsSearchUtil.joinToHashSet(excludedParamsTypesQNames, targetQName));
}
private void add(final Collection<UsageIndexValue> indexValues,
final Set<String> excludedParamsTypesQNames) {
int bestOccurrences = -1;
for (final UsageIndexValue indexValue : indexValues) {
if (add(indexValue, excludedParamsTypesQNames)) {
final int occurrences = indexValue.getOccurrences();
if (bestOccurrences == -1) {
bestOccurrences = occurrences;
}
else if (bestOccurrences > occurrences * CHAIN_SEARCH_MAGIC_RATIO) {
return;
}
}
}
}
private boolean add(final UsageIndexValue indexValue, final Set<String> excludedParamsTypesQNames) {
final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature();
final PsiMethod[] psiMethods = myContext.resolveNotDeprecated(methodInvocation);
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, excludedParamsTypesQNames)) {
final int occurrences = indexValue.getOccurrences();
final MethodsChain methodsChain = new MethodsChain(psiMethods, occurrences, indexValue.getMethodIncompleteSignature().getOwner());
myChains.put(methodInvocation, Pair.create(methodsChain, occurrences));
return true;
}
return false;
}
public InitResult init(final Set<String> excludedEdgeNames) {
final int size = myChains.size();
final List<WeightAware<MethodIncompleteSignature>> initedVertexes = new ArrayList<>(size);
final LinkedHashMap<MethodIncompleteSignature, MethodsChain> initedChains =
new LinkedHashMap<>(size);
for (final Map.Entry<MethodIncompleteSignature, Pair<MethodsChain, Integer>> entry : myChains.entrySet()) {
final MethodIncompleteSignature signature = entry.getKey();
if (!excludedEdgeNames.contains(signature.getName())) {
initedVertexes.add(new WeightAware<>(entry.getKey(), entry.getValue().getSecond()));
final MethodsChain methodsChain = entry.getValue().getFirst();
initedChains.put(signature, methodsChain);
}
}
return new InitResult(initedVertexes, initedChains);
}
public static class InitResult {
private final List<WeightAware<MethodIncompleteSignature>> myVertexes;
private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains;
private InitResult(final List<WeightAware<MethodIncompleteSignature>> vertexes,
final LinkedHashMap<MethodIncompleteSignature, MethodsChain> chains) {
myVertexes = vertexes;
myChains = chains;
}
public List<WeightAware<MethodIncompleteSignature>> getVertexes() {
return myVertexes;
}
public LinkedHashMap<MethodIncompleteSignature, MethodsChain> getChains() {
return myChains;
}
}
}
@@ -1,48 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.completion;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
import static com.intellij.patterns.StandardPatterns.or;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public final class CompletionContributorPatternUtil {
private CompletionContributorPatternUtil() {}
@SuppressWarnings("unchecked")
public static ElementPattern<PsiElement> patternForVariableAssignment() {
final ElementPattern<PsiElement> patternForParent = or(psiElement().withText(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED)
.afterSiblingSkipping(psiElement(PsiWhiteSpace.class),
psiElement(PsiJavaToken.class).withText("=")));
return psiElement().withParent(patternForParent).withSuperParent(2, or(psiElement(PsiAssignmentExpression.class),
psiElement(PsiLocalVariable.class)
.inside(PsiDeclarationStatement.class)))
.inside(PsiMethod.class);
}
public static ElementPattern<PsiElement> patternForMethodParameter() {
return psiElement().withSuperParent(3, PsiMethodCallExpressionImpl.class);
}
}
@@ -1,213 +0,0 @@
package com.intellij.compiler.classFilesIndex.chainsSearch.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexFeature;
import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexFeaturesHolder;
import com.intellij.compiler.classFilesIndex.chainsSearch.*;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextUtil;
import com.intellij.compiler.classFilesIndex.chainsSearch.context.TargetType;
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexReader;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.compiler.classFilesIndex.chainsSearch.completion.CompletionContributorPatternUtil.*;
import static com.intellij.patterns.PsiJavaPatterns.or;
/**
* @author Dmitry Batkovich
*/
public class MethodsChainsCompletionContributor extends CompletionContributor {
private final static boolean IS_UNIT_TEST_MODE = ApplicationManager.getApplication().isUnitTestMode();
public static final int INVOCATIONS_THRESHOLD = 2;
public static final CompletionType COMPLETION_TYPE = IS_UNIT_TEST_MODE ? CompletionType.BASIC : CompletionType.SMART;
private final static int MAX_SEARCH_RESULT_SIZE = 5;
private final static int MAX_CHAIN_SIZE = 4;
private final static int FILTER_RATIO = 10;
@Override
public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull final CompletionResultSet result) {
if (parameters.getInvocationCount() >= INVOCATIONS_THRESHOLD &&
ClassFilesIndexFeaturesHolder.getInstance(parameters.getPosition().getProject())
.enableFeatureIfNeed(ClassFilesIndexFeature.METHOD_CHAINS_COMPLETION)) {
super.fillCompletionVariants(parameters, result);
}
}
@SuppressWarnings("unchecked")
public MethodsChainsCompletionContributor() {
final ElementPattern<PsiElement> pattern = or(patternForMethodParameter(), patternForVariableAssignment());
extend(COMPLETION_TYPE, pattern, new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(final @NotNull CompletionParameters parameters,
final ProcessingContext context,
final @NotNull CompletionResultSet result) {
final ChainCompletionContext completionContext = extractContext(parameters);
if (completionContext == null) return;
final Set<String> contextTypesKeysSet = completionContext.getContextTypes();
final Set<String> contextRelevantTypes = new HashSet<>(contextTypesKeysSet.size() + 1);
for (final String type : contextTypesKeysSet) {
if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) {
contextRelevantTypes.add(type);
}
}
final TargetType target = completionContext.getTarget();
contextRelevantTypes.remove(target.getClassQName());
final List<LookupElement> elementsFoundByMethodsChainsSearch = searchForLookups(target, contextRelevantTypes, completionContext);
if (!IS_UNIT_TEST_MODE) {
result.runRemainingContributors(parameters, completionResult -> {
final LookupElement lookupElement = completionResult.getLookupElement();
final PsiElement lookupElementPsi = lookupElement.getPsiElement();
if (lookupElementPsi != null) {
for (final LookupElement element : elementsFoundByMethodsChainsSearch) {
if (lookupElementPsi.isEquivalentTo(element.getPsiElement())) {
elementsFoundByMethodsChainsSearch.remove(element);
break;
}
}
}
result.passResult(completionResult);
});
} else {
result.stopHere();
}
result.addAllElements(elementsFoundByMethodsChainsSearch);
}
});
}
private static List<LookupElement> searchForLookups(final TargetType target,
final Set<String> contextRelevantTypes,
final ChainCompletionContext completionContext) {
final Project project = completionContext.getProject();
final MethodsUsageIndexReader methodsUsageIndexReader = MethodsUsageIndexReader.getInstance(project);
final List<MethodsChain> searchResult =
searchChains(target, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, completionContext, methodsUsageIndexReader);
if (searchResult.size() < MAX_SEARCH_RESULT_SIZE) {
if (!target.isArray()) {
final List<MethodsChain> inheritorFilteredSearchResult = new SmartList<>();
final Processor<TargetType> consumer = targetType -> {
for (final MethodsChain chain : searchChains(targetType,
contextRelevantTypes,
MAX_SEARCH_RESULT_SIZE,
MAX_CHAIN_SIZE,
completionContext,
methodsUsageIndexReader)) {
boolean insert = true;
for (final MethodsChain baseChain : searchResult) {
final MethodsChain.CompareResult r = MethodsChain.compare(baseChain, chain, completionContext.getPsiManager());
if (r != MethodsChain.CompareResult.NOT_EQUAL) {
insert = false;
break;
}
}
if (insert) {
inheritorFilteredSearchResult.add(chain);
}
}
searchResult.addAll(inheritorFilteredSearchResult);
return searchResult.size() < MAX_SEARCH_RESULT_SIZE;
};
DirectClassInheritorsSearch.search(((PsiClassType)target.getPsiType()).resolve()).forEach(psiClass -> {
final String inheritorQName = psiClass.getQualifiedName();
if (inheritorQName == null) {
return true;
}
return consumer.process(new TargetType(inheritorQName, false, new PsiImmediateClassType(psiClass, PsiSubstitutor.EMPTY)));
});
}
}
final List<MethodsChain> chains = searchResult.size() > MAX_CHAIN_SIZE ? chooseHead(searchResult) : searchResult;
return MethodsChainLookupRangingHelper
.chainsToWeightableLookupElements(filterTailAndGetSumLastMethodOccurrence(chains), completionContext);
}
private static List<MethodsChain> chooseHead(final List<MethodsChain> elements) {
Collections.sort(elements, (o1, o2) -> o2.getChainWeight() - o1.getChainWeight());
return elements.subList(0, MAX_CHAIN_SIZE);
}
@SuppressWarnings("unchecked")
@Nullable
private static ChainCompletionContext extractContext(final CompletionParameters parameters) {
final PsiElement parent = PsiTreeUtil
.getParentOfType(parameters.getPosition(), PsiAssignmentExpression.class, PsiLocalVariable.class, PsiMethodCallExpression.class);
if (parent == null) {
return null;
}
if (parent instanceof PsiAssignmentExpression) {
return tryExtractContextFromAssignment((PsiAssignmentExpression)parent);
}
if (parent instanceof PsiLocalVariable) {
final PsiLocalVariable localVariable = (PsiLocalVariable)parent;
return ContextUtil.createContext(localVariable.getType(), localVariable.getName(),
PsiTreeUtil.getParentOfType(parent, PsiDeclarationStatement.class));
}
final PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod();
if (method == null) return null;
final PsiExpression expression = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiExpression.class);
final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiExpressionList.class);
if (expressionList == null) return null;
final int exprPosition = Arrays.asList(expressionList.getExpressions()).indexOf(expression);
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
if (exprPosition < methodParameters.length) {
final PsiParameter methodParameter = methodParameters[exprPosition];
return ContextUtil
.createContext(methodParameter.getType(), null, PsiTreeUtil.getParentOfType(expression, PsiDeclarationStatement.class));
}
return null;
}
@Nullable
private static ChainCompletionContext tryExtractContextFromAssignment(final PsiAssignmentExpression assignmentExpression) {
final PsiType type = assignmentExpression.getLExpression().getType();
final PsiIdentifier identifier = PsiTreeUtil.getChildOfType(assignmentExpression.getLExpression(), PsiIdentifier.class);
if (identifier == null) return null;
final String identifierText = identifier.getText();
return ContextUtil.createContext(type, identifierText, assignmentExpression);
}
private static List<MethodsChain> filterTailAndGetSumLastMethodOccurrence(final List<MethodsChain> chains) {
int maxWeight = 0;
for (final MethodsChain chain : chains) {
final int chainWeight = chain.getChainWeight();
if (chainWeight > maxWeight) {
maxWeight = chainWeight;
}
}
final List<MethodsChain> filteredResult = new ArrayList<>();
for (final MethodsChain chain : chains) {
final int chainWeight = chain.getChainWeight();
if (chainWeight * FILTER_RATIO >= maxWeight) {
filteredResult.add(chain);
}
}
return filteredResult;
}
private static List<MethodsChain> searchChains(final TargetType target,
final Set<String> contextVarsQNames,
final int maxResultSize,
final int maxChainSize,
final ChainCompletionContext context,
final MethodsUsageIndexReader methodsUsageIndexReader) {
return ChainsSearcher.search(maxChainSize, target, contextVarsQNames, maxResultSize, context, methodsUsageIndexReader);
}
}
@@ -1,66 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.completion.lookup.sub;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.ChainCompletionLookupElementUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TObjectProcedure;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Batkovich
*/
public class StaticMethodSubLookupElement implements SubLookupElement {
private final PsiMethod myMethod;
private final TIntObjectHashMap<SubLookupElement> myReplaceElements;
public StaticMethodSubLookupElement(final PsiMethod method, @Nullable final TIntObjectHashMap<SubLookupElement> replaceElements) {
assert method.hasModifierProperty(PsiModifier.STATIC);
myReplaceElements = replaceElements;
myMethod = method;
}
@Override
public void doImport(final PsiJavaFile javaFile) {
final PsiClass containingClass = myMethod.getContainingClass();
if (containingClass != null) {
if (javaFile.findImportReferenceTo(containingClass) == null) {
javaFile.importClass(containingClass);
}
}
if (myReplaceElements != null) {
myReplaceElements.forEachValue(new TObjectProcedure<SubLookupElement>() {
@Override
public boolean execute(final SubLookupElement subLookupElement) {
subLookupElement.doImport(javaFile);
return false;
}
});
}
}
@Override
public String getInsertString() {
//noinspection ConstantConditions
return String.format("%s.%s(%s)", myMethod.getContainingClass().getName(), myMethod.getName(),
ChainCompletionLookupElementUtil.fillMethodParameters(myMethod, myReplaceElements));
}
}
@@ -1,162 +0,0 @@
/*
* Copyright 2000-2014 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.compiler.classFilesIndex.chainsSearch.context;
import com.intellij.compiler.classFilesIndex.chainsSearch.CachedRelevantStaticMethodSearcher;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
public class ChainCompletionContext {
private final TargetType myTarget;
private final Set<String> myContainingClassQNames;
private final MultiMap<String, PsiVariable> myContextVars;
private final MultiMap<String, PsiMethod> myContainingClassGetters;
private final MultiMap<String, ContextRelevantVariableGetter> myContextVarsGetters;
private final Map<String, PsiVariable> myStringVars;
private final Set<String> myExcludedQNames;
private final GlobalSearchScope myResolveScope;
private final Project myProject;
private final PsiManager myPsiManager;
private final MethodIncompleteSignatureResolver myNotDeprecatedMethodsResolver;
private final NotNullLazyValue<Set<String>> contextTypesQNames = new NotNullLazyValue<Set<String>>() {
@SuppressWarnings("unchecked")
@NotNull
@Override
protected Set<String> compute() {
return unionToHashSet(myContainingClassQNames,
myContextVars.keySet(),
myContainingClassGetters.keySet(),
myContextVarsGetters.keySet());
}
};
public Set<String> getExcludedQNames() {
return myExcludedQNames;
}
ChainCompletionContext(final TargetType target,
final Set<String> containingClassQNames,
final MultiMap<String, PsiVariable> contextVars,
final MultiMap<String, PsiMethod> containingClassGetters,
final MultiMap<String, ContextRelevantVariableGetter> contextVarsGetters,
final Map<String, PsiVariable> stringVars,
final Set<String> excludedQNames,
final Project project,
final GlobalSearchScope resolveScope) {
myTarget = target;
myContainingClassQNames = containingClassQNames;
myContextVars = contextVars;
myContainingClassGetters = containingClassGetters;
myContextVarsGetters = contextVarsGetters;
myStringVars = stringVars;
myExcludedQNames = excludedQNames;
myResolveScope = resolveScope;
myProject = project;
myPsiManager = PsiManager.getInstance(project);
myNotDeprecatedMethodsResolver = new MethodIncompleteSignatureResolver(JavaPsiFacade.getInstance(project), resolveScope);
}
public TargetType getTarget() {
return myTarget;
}
@Nullable
public PsiVariable findRelevantStringInContext(@Nullable final String stringParamName) {
if (stringParamName == null) {
return null;
}
for (final Map.Entry<String, PsiVariable> e : myStringVars.entrySet()) {
if (ChainCompletionContextStringUtil.isSimilar(e.getKey(), stringParamName)) {
return e.getValue();
}
}
return null;
}
public Set<String> getContainingClassQNames() {
return myContainingClassQNames;
}
public Collection<PsiVariable> getVariables(final String typeQName) {
return myContextVars.get(typeQName);
}
public Collection<PsiMethod> getContainingClassMethods(final String typeQName) {
return myContainingClassGetters.get(typeQName);
}
public Collection<ContextRelevantVariableGetter> getRelevantVariablesGetters(final String typeQName) {
return myContextVarsGetters.get(typeQName);
}
public Collection<?> getContextRefElements(final String typeQName) {
final Collection<PsiVariable> variables = getVariables(typeQName);
final Collection<PsiMethod> containingClassMethods = getContainingClassMethods(typeQName);
final Collection<UserDataHolder> refElements = new ArrayList<>(variables.size() + containingClassMethods.size());
refElements.addAll(variables);
refElements.addAll(containingClassMethods);
for (final ContextRelevantVariableGetter contextRelevantVariableGetter : getRelevantVariablesGetters(typeQName)) {
refElements.add(contextRelevantVariableGetter.createLookupElement());
}
return refElements;
}
public boolean contains(@Nullable final String typeQualifierName) {
return typeQualifierName != null && contextTypesQNames.getValue().contains(typeQualifierName);
}
public Set<String> getContextTypes() {
return contextTypesQNames.getValue();
}
public GlobalSearchScope getResolveScope() {
return myResolveScope;
}
public Project getProject() {
return myProject;
}
public PsiManager getPsiManager() {
return myPsiManager;
}
@NotNull
public PsiMethod[] resolveNotDeprecated(final MethodIncompleteSignature methodIncompleteSignature) {
return myNotDeprecatedMethodsResolver.get(methodIncompleteSignature);
}
private static <T> HashSet<T> unionToHashSet(final Collection<T>... collections) {
final HashSet<T> res = new HashSet<>();
for (final Collection<T> set : collections) {
res.addAll(set);
}
return res;
}
}
@@ -1,51 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.context;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
/**
* @author Dmitry Batkovich
*/
class ChainCompletionContextStringUtil {
private ChainCompletionContextStringUtil(){}
private final static int COMMON_PART_MIN_LENGTH = 3;
public static boolean isSimilar(@NotNull final String varName,
@NotNull final String parameterName) {
final String sanitizedParamName = sanitizedToLowerCase(parameterName);
if (StringUtil.commonPrefix(varName, sanitizedParamName).length() >= COMMON_PART_MIN_LENGTH) {
return true;
}
final String suffix = StringUtil.commonSuffix(varName, sanitizedParamName);
return suffix.length() >= COMMON_PART_MIN_LENGTH;
}
@NotNull
public static String sanitizedToLowerCase(@NotNull final String name) {
final StringBuilder result = new StringBuilder();
for (int i = 0; i < name.length(); i++) {
final char ch = name.charAt(i);
if (Character.isLetter(ch)) {
result.append(Character.toLowerCase(ch));
}
}
return result.toString();
}
}
@@ -1,60 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.context;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.StaticMethodSubLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.VariableSubLookupElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiVariable;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TIntObjectProcedure;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Batkovich
*/
public class ContextRelevantStaticMethod {
private final PsiMethod psiMethod;
@Nullable
private final TIntObjectHashMap<SubLookupElement> parameters;
public ContextRelevantStaticMethod(final PsiMethod psiMethod, @Nullable final TIntObjectHashMap<PsiVariable> parameters) {
this.psiMethod = psiMethod;
if (parameters == null) {
this.parameters = null;
} else {
this.parameters = new TIntObjectHashMap<>(parameters.size());
parameters.forEachEntry(new TIntObjectProcedure<PsiVariable>() {
@SuppressWarnings("ConstantConditions")
@Override
public boolean execute(final int pos, final PsiVariable var) {
ContextRelevantStaticMethod.this.parameters.put(pos, new VariableSubLookupElement(var));
return true;
}
});
}
}
private SubLookupElement cachedLookupElement;
public SubLookupElement createLookupElement() {
if (cachedLookupElement == null) {
cachedLookupElement = new StaticMethodSubLookupElement(psiMethod, parameters);
}
return cachedLookupElement;
}
}
@@ -1,46 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.context;
import com.intellij.codeInsight.completion.JavaChainLookupElement;
import com.intellij.codeInsight.completion.JavaMethodCallElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.GetterLookupSubLookupElement;
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.VariableLookupItem;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiVariable;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class ContextRelevantVariableGetter {
private final PsiVariable myVariable;
private final PsiMethod myMethod;
public ContextRelevantVariableGetter(final PsiVariable variable, final PsiMethod method) {
myVariable = variable;
myMethod = method;
}
public SubLookupElement createSubLookupElement() {
return new GetterLookupSubLookupElement(myVariable.getName(), myMethod.getName());
}
public LookupElement createLookupElement() {
return new JavaChainLookupElement(new VariableLookupItem(myVariable), new JavaMethodCallElement(myMethod));
}
}
@@ -1,257 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.context;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
public final class ContextUtil {
@Nullable
public static ChainCompletionContext createContext(final @Nullable PsiType variableType,
final @Nullable String variableName,
final @Nullable PsiElement containingElement) {
if (variableType == null || containingElement == null) {
return null;
}
final TargetType target;
if (variableType instanceof PsiClassType) {
target = TargetType.create((PsiClassType)variableType);
}
else if (variableType instanceof PsiArrayType) {
target = TargetType.create((PsiArrayType)variableType);
}
else {
return null;
}
if (target == null) {
return null;
}
final PsiMethod method = PsiTreeUtil.getParentOfType(containingElement, PsiMethod.class);
if (method == null) {
return null;
}
final PsiClass aClass = method.getContainingClass();
if (aClass == null) {
return null;
}
final Set<String> containingClassQNames = resolveSupersNamesRecursively(aClass);
final List<PsiVariable> contextVars = new SmartList<>();
for (final PsiField field : aClass.getFields()) {
final PsiClass containingClass = field.getContainingClass();
if (containingClass != null) {
if ((field.hasModifierProperty(PsiModifier.PUBLIC) ||
field.hasModifierProperty(PsiModifier.PROTECTED) ||
((field.hasModifierProperty(PsiModifier.PRIVATE) || field.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) &&
aClass.isEquivalentTo(containingClass))) && !field.getName().equals(variableName)) {
contextVars.add(field);
}
}
}
Collections.addAll(contextVars, method.getParameterList().getParameters());
final PsiCodeBlock methodBody = method.getBody();
assert methodBody != null;
boolean processMethodTail = false;
final List<PsiElement> afterElements = new ArrayList<>();
for (final PsiElement element : methodBody.getChildren()) {
if (element.isEquivalentTo(containingElement)) {
if (variableType instanceof PsiClassType) {
processMethodTail = true;
continue;
}
else {
break;
}
}
if (element instanceof PsiDeclarationStatement) {
if (processMethodTail) {
afterElements.add(element);
}
else {
for (final PsiElement declaredElement : ((PsiDeclarationStatement)element).getDeclaredElements()) {
if (declaredElement instanceof PsiLocalVariable &&
(variableName == null || !variableName.equals(((PsiLocalVariable)declaredElement).getName()))) {
contextVars.add((PsiVariable)declaredElement);
}
}
}
}
}
final Set<String> excludedQNames = processMethodTail
? generateExcludedQNames(afterElements, ((PsiClassType)variableType).resolve(), variableName,
contextVars)
: Collections.<String>emptySet();
final List<PsiMethod> contextMethods = new ArrayList<>();
for (final PsiMethod psiMethod : aClass.getMethods()) {
if ((psiMethod.hasModifierProperty(PsiModifier.PROTECTED) || psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) &&
psiMethod.getParameterList().getParametersCount() == 0) {
contextMethods.add(psiMethod);
}
}
return create(target, contextVars, contextMethods, containingClassQNames, containingElement.getProject(),
containingElement.getResolveScope(), excludedQNames);
}
private static Set<String> generateExcludedQNames(final List<PsiElement> tailElements,
final @Nullable PsiClass psiClass,
final @Nullable String varName,
final List<PsiVariable> contextVars) {
if (psiClass == null) {
return Collections.emptySet();
}
final String classQName = psiClass.getQualifiedName();
if (classQName == null) {
return Collections.emptySet();
}
final Set<String> excludedQNames = new HashSet<>();
if (!tailElements.isEmpty()) {
final Set<String> contextVarTypes = new HashSet<>();
final Map<String, PsiVariable> contextVarNamesToVar = new HashMap<>();
for (final PsiVariable var : contextVars) {
contextVarTypes.add(var.getType().getCanonicalText());
contextVarNamesToVar.put(var.getName(), var);
}
for (final PsiElement element : tailElements) {
final Collection<PsiMethodCallExpression> methodCallExpressions =
PsiTreeUtil.findChildrenOfType(element, PsiMethodCallExpression.class);
for (final PsiMethodCallExpression methodCallExpression : methodCallExpressions) {
final PsiExpressionList args = methodCallExpression.getArgumentList();
final PsiMethod resolvedMethod = methodCallExpression.resolveMethod();
if (resolvedMethod != null) {
final PsiType returnType = resolvedMethod.getReturnType();
if (returnType != null) {
final String returnTypeAsString = returnType.getCanonicalText();
for (final PsiExpression expression : args.getExpressions()) {
final String qVarName = expression.getText();
if (qVarName != null) {
if (contextVarNamesToVar.containsKey(qVarName) || qVarName.equals(varName)) {
excludedQNames.add(returnTypeAsString);
}
}
}
if (!contextVarTypes.contains(returnTypeAsString)) {
excludedQNames.add(returnTypeAsString);
}
}
}
}
}
}
return excludedQNames;
}
@Nullable
private static ChainCompletionContext create(final TargetType target,
final List<PsiVariable> contextVars,
final List<PsiMethod> contextMethods,
final Set<String> containingClassQNames,
final Project project,
final GlobalSearchScope resolveScope,
final Set<String> excludedQNames) {
final MultiMap<String, PsiVariable> classQNameToVariable = new MultiMap<>();
final MultiMap<String, PsiMethod> containingClassGetters = new MultiMap<>();
final MultiMap<String, ContextRelevantVariableGetter> contextVarsGetters = new MultiMap<>();
final Map<String, PsiVariable> stringVars = new HashMap<>();
for (final PsiMethod method : contextMethods) {
final PsiType returnType = method.getReturnType();
if (returnType != null) {
final String returnTypeQName = returnType.getCanonicalText();
containingClassGetters.putValue(returnTypeQName, method);
}
}
for (final PsiVariable var : contextVars) {
final PsiType type = var.getType();
final Set<String> classQNames = new HashSet<>();
if (type instanceof PsiClassType) {
if (JAVA_LANG_STRING_SHORT_NAME.equals(((PsiClassType)type).getClassName())) {
final String varName = var.getName();
if (varName != null) {
stringVars.put(ChainCompletionContextStringUtil.sanitizedToLowerCase(varName), var);
continue;
}
}
final PsiClass aClass = ((PsiClassType)type).resolve();
if (aClass != null) {
final String classQName = type.getCanonicalText();
if (!target.getClassQName().equals(classQName)) {
classQNames.add(classQName);
classQNames.addAll(resolveSupersNamesRecursively(aClass));
for (final PsiMethod method : aClass.getAllMethods()) {
if (method.getParameterList().getParametersCount() == 0 && method.getName().startsWith("get")) {
final PsiType returnType = method.getReturnType();
if (returnType != null) {
final String getterReturnTypeQName = returnType.getCanonicalText();
contextVarsGetters.putValue(getterReturnTypeQName, new ContextRelevantVariableGetter(var, method));
}
}
}
}
}
}
else {
final String classQName = type.getCanonicalText();
classQNames.add(classQName);
}
for (final String qName : classQNames) {
classQNameToVariable.putValue(qName, var);
}
}
return new ChainCompletionContext(target, containingClassQNames, classQNameToVariable, containingClassGetters,
contextVarsGetters, stringVars, excludedQNames, project, resolveScope);
}
@NotNull
private static Set<String> resolveSupersNamesRecursively(@Nullable final PsiClass psiClass) {
final Set<String> result = new HashSet<>();
if (psiClass != null) {
for (final PsiClass superClass : psiClass.getSupers()) {
final String qualifiedName = superClass.getQualifiedName();
if (!CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) {
if (qualifiedName != null) {
result.add(qualifiedName);
}
result.addAll(resolveSupersNamesRecursively(superClass));
}
}
}
return result;
}
private final static String JAVA_LANG_STRING_SHORT_NAME = StringUtil.getShortName(CommonClassNames.JAVA_LANG_STRING);
}
@@ -1,89 +0,0 @@
/*
* 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.compiler.classFilesIndex.chainsSearch.context;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.FactoryMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
import org.jetbrains.jps.classFilesIndex.AsmUtil;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
final class MethodIncompleteSignatureResolver {
private final Map<MethodIncompleteSignature, PsiMethod[]> myResolvedCache;
public MethodIncompleteSignatureResolver(final JavaPsiFacade javaPsiFacade, final GlobalSearchScope scope) {
myResolvedCache = new FactoryMap<MethodIncompleteSignature, PsiMethod[]>() {
@Nullable
@Override
protected PsiMethod[] create(final MethodIncompleteSignature signature) {
return resolveNotDeprecated(signature, javaPsiFacade, scope);
}
};
}
@NotNull
public PsiMethod[] get(final MethodIncompleteSignature signature) {
return myResolvedCache.get(signature);
}
private static PsiMethod[] resolveNotDeprecated(final MethodIncompleteSignature signature,
final JavaPsiFacade javaPsiFacade,
final GlobalSearchScope scope) {
if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(signature.getName())) {
return PsiMethod.EMPTY_ARRAY;
}
final PsiClass aClass = javaPsiFacade.findClass(AsmUtil.getQualifiedClassName(signature.getOwner()), scope);
if (aClass == null) {
return PsiMethod.EMPTY_ARRAY;
}
final PsiMethod[] methods = aClass.findMethodsByName(signature.getName(), true);
final List<PsiMethod> filtered = new ArrayList<>(methods.length);
for (final PsiMethod method : methods) {
if (method.hasModifierProperty(PsiModifier.STATIC) == signature.isStatic()) {
final PsiType returnType = method.getReturnType();
if (returnType != null) {
if (returnType instanceof PsiClassType) {
final PsiClass resolved = ((PsiClassType)returnType).resolve();
if (resolved == null) {
continue;
}
final String qualifiedName = resolved.getQualifiedName();
if (qualifiedName == null) {
continue;
}
if (qualifiedName.equals(signature.getReturnType())) {
filtered.add(method);
}
}
else if (returnType.equalsToText(signature.getReturnType())) {
filtered.add(method);
}
}
}
}
if (filtered.size() > 1) {
Collections.sort(filtered, (o1, o2) -> o1.getParameterList().getParametersCount() - o2.getParameterList().getParametersCount());
}
return filtered.toArray(new PsiMethod[filtered.size()]);
}
}
@@ -1,102 +0,0 @@
/*
* 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.compiler.classFilesIndex.impl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.java.dependencyView.Mappings;
import org.jetbrains.jps.classFilesIndex.AsmUtil;
import org.jetbrains.jps.classFilesIndex.indexer.impl.EnumeratedMethodIncompleteSignature;
import java.util.Comparator;
/**
* @author Dmitry Batkovich
*/
public class MethodIncompleteSignature {
public static final String CONSTRUCTOR_METHOD_NAME = "<init>";
@NotNull
private final String myOwner;
@NotNull
private final String myReturnType;
@NotNull
private final String myName;
private final boolean myStatic;
private MethodIncompleteSignature(@NotNull final String owner, @NotNull final String returnType, @NotNull final String name, final boolean aStatic) {
myOwner = owner;
myReturnType = returnType;
myName = name;
myStatic = aStatic;
}
public static MethodIncompleteSignature denumerated(final EnumeratedMethodIncompleteSignature sign, final String returnType, final Mappings mappings) {
return new MethodIncompleteSignature(AsmUtil.getQualifiedClassName(mappings.valueOf(sign.getOwner())), returnType, mappings.valueOf(sign.getName()), sign.isStatic());
}
@NotNull
public String getOwner() {
return myOwner;
}
@NotNull
public String getName() {
return myName;
}
@NotNull
public String getReturnType() {
return myReturnType;
}
public boolean isStatic() {
return myStatic;
}
@Override
public String toString() {
return "MethodIncompleteSignature{" +
"myOwner='" + myOwner + '\'' +
", myReturnType='" + myReturnType + '\'' +
", myName='" + myName + '\'' +
", myStatic=" + myStatic +
'}';
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || !(o instanceof MethodIncompleteSignature)) return false;
final MethodIncompleteSignature that = (MethodIncompleteSignature)o;
if (myStatic != that.myStatic) return false;
if (!myName.equals(that.myName)) return false;
if (!myOwner.equals(that.myOwner)) return false;
if (!myReturnType.equals(that.myReturnType)) return false;
return true;
}
@Override
public int hashCode() {
int result = myOwner.hashCode();
result = 31 * result + myReturnType.hashCode();
result = 31 * result + myName.hashCode();
result = 31 * result + (myStatic ? 1 : 0);
return result;
}
}
@@ -1,54 +0,0 @@
/*
* 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.compiler.classFilesIndex.impl;
import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexConfigure;
import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexReaderBase;
import com.intellij.openapi.project.Project;
import com.intellij.util.io.PersistentHashMapValueStorage;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.jps.classFilesIndex.indexer.api.ClassFileIndexerFactory;
import org.jetbrains.jps.classFilesIndex.indexer.impl.EnumeratedMethodIncompleteSignature;
import org.jetbrains.jps.classFilesIndex.indexer.impl.MethodsUsageIndexerFactory;
import org.jetbrains.jps.classFilesIndex.indexer.impl.MethodsUsageIndexer;
/**
* @author Dmitry Batkovich
*/
public class MethodsUsageIndexConfigure extends ClassFilesIndexConfigure<Integer, TObjectIntHashMap<EnumeratedMethodIncompleteSignature>> {
public static final MethodsUsageIndexConfigure INSTANCE = new MethodsUsageIndexConfigure();
@Override
public String getIndexCanonicalName() {
return MethodsUsageIndexer.METHODS_USAGE_INDEX_CANONICAL_NAME;
}
@Override
public int getIndexVersion() {
return 1 + (PersistentHashMapValueStorage.COMPRESSION_ENABLED ? 0xFF : 0);
}
@Override
public Class<? extends ClassFileIndexerFactory> getIndexerBuilderClass() {
return MethodsUsageIndexerFactory.class;
}
@Override
public ClassFilesIndexReaderBase<Integer, TObjectIntHashMap<EnumeratedMethodIncompleteSignature>> createIndexReader(final Project project) {
return new MethodsUsageIndexReader(project, getIndexCanonicalName(), getIndexVersion());
}
}
@@ -1,84 +0,0 @@
/*
* 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.compiler.classFilesIndex.impl;
import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexFeaturesHolder;
import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexReaderBase;
import com.intellij.openapi.project.Project;
import com.intellij.util.io.EnumeratorIntegerDescriptor;
import com.intellij.util.io.EnumeratorStringDescriptor;
import gnu.trove.TObjectIntHashMap;
import gnu.trove.TObjectIntProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.classFilesIndex.TObjectIntHashMapExternalizer;
import org.jetbrains.jps.classFilesIndex.indexer.impl.EnumeratedMethodIncompleteSignature;
import java.util.Collection;
import java.util.TreeSet;
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class MethodsUsageIndexReader extends ClassFilesIndexReaderBase<Integer, TObjectIntHashMap<EnumeratedMethodIncompleteSignature>> {
public static MethodsUsageIndexReader getInstance(final Project project) {
final MethodsUsageIndexReader instance =
ClassFilesIndexFeaturesHolder.getInstance(project).getAvailableIndexReader(MethodsUsageIndexReader.class);
if (instance == null) {
throw new RuntimeException("couldn't get instance");
}
return instance;
}
public MethodsUsageIndexReader(final Project project, final String canonicalIndexName, final int version) {
//noinspection ConstantConditions
super(EnumeratorIntegerDescriptor.INSTANCE,
new TObjectIntHashMapExternalizer<>(EnumeratedMethodIncompleteSignature.createDataExternalizer()),
canonicalIndexName, version, project);
}
@NotNull
public TreeSet<UsageIndexValue> getMethods(final String key) {
assert myIndex != null;
assert myMappings != null;
final Collection<TObjectIntHashMap<EnumeratedMethodIncompleteSignature>> unReducedValues = myIndex.getData(myMappings.getName(key.replace('.', '/')));
final TObjectIntHashMap<MethodIncompleteSignature> rawValues = new TObjectIntHashMap<>();
for (final TObjectIntHashMap<EnumeratedMethodIncompleteSignature> unReducedValue : unReducedValues) {
unReducedValue.forEachEntry(new TObjectIntProcedure<EnumeratedMethodIncompleteSignature>() {
@Override
public boolean execute(final EnumeratedMethodIncompleteSignature sign, final int occurrences) {
final MethodIncompleteSignature denumerated = MethodIncompleteSignature.denumerated(sign, key, myMappings);
if (!rawValues.adjustValue(denumerated, occurrences)) {
rawValues.put(denumerated, occurrences);
}
return true;
}
});
}
final TreeSet<UsageIndexValue> values = new TreeSet<>();
rawValues.forEachEntry(new TObjectIntProcedure<MethodIncompleteSignature>() {
@Override
public boolean execute(final MethodIncompleteSignature sign, final int occurrences) {
values.add(new UsageIndexValue(sign, occurrences));
return true;
}
});
return values;
}
}
@@ -1,83 +0,0 @@
/*
* 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.compiler.classFilesIndex.impl;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
/**
* @author Dmitry Batkovich
*/
public class UsageIndexValue implements Comparable<UsageIndexValue> {
private final int myOccurrences;
private final MethodIncompleteSignature myMethodIncompleteSignature;
public UsageIndexValue(final MethodIncompleteSignature signature, final int occurrences) {
myOccurrences = occurrences;
myMethodIncompleteSignature = signature;
}
public int getOccurrences() {
return myOccurrences;
}
public MethodIncompleteSignature getMethodIncompleteSignature() {
return myMethodIncompleteSignature;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final UsageIndexValue that = (UsageIndexValue)o;
return myOccurrences == that.myOccurrences && myMethodIncompleteSignature.equals(that.myMethodIncompleteSignature);
}
@Override
public int hashCode() {
int result = myOccurrences;
result = 31 * result + myMethodIncompleteSignature.hashCode();
return result;
}
@Override
public int compareTo(@NotNull final UsageIndexValue that) {
int sub = -myOccurrences + that.myOccurrences;
if (sub != 0) return sub;
sub = myMethodIncompleteSignature.getOwner().compareTo(that.myMethodIncompleteSignature.getOwner());
if (sub != 0) {
return sub;
}
sub = myMethodIncompleteSignature.getName().compareTo(that.myMethodIncompleteSignature.getName());
if (sub != 0) {
return sub;
}
sub = myMethodIncompleteSignature.getReturnType().compareTo(that.myMethodIncompleteSignature.getReturnType());
if (sub != 0) {
return sub;
}
if (myMethodIncompleteSignature.isStatic() && !that.myMethodIncompleteSignature.isStatic()) {
return 1;
}
if (that.myMethodIncompleteSignature.isStatic() && !myMethodIncompleteSignature.isStatic()) {
return -1;
}
return 0;
}
}
@@ -374,6 +374,13 @@ public class JavaDebugProcess extends XDebugProcess {
final MemoryViewDebugProcessData data = new MemoryViewDebugProcessData(classesFilteredView);
process.putUserData(MemoryViewDebugProcessData.KEY, data);
session.addSessionListener(new XDebugSessionListener() {
@Override
public void sessionStopped() {
session.removeSessionListener(this);
data.getTrackedStacks().clear();
}
}, memoryViewContent);
ui.addContent(memoryViewContent, 0, PlaceInGrid.right, true);
ui.addListener(new ContentManagerAdapter() {
@@ -25,6 +25,7 @@ import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.requests.ClassPrepareRequestor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
@@ -203,18 +204,26 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
return new JavaSourcePosition(sourcePosition, location.declaringType(), method, lambdaOrdinal);
}
private static class JavaSourcePosition extends RemappedSourcePosition {
public static class JavaSourcePosition extends RemappedSourcePosition {
private final String myExpectedClassName;
private final String myExpectedMethodName;
private final int myLambdaOrdinal;
public JavaSourcePosition(SourcePosition delegate, ReferenceType declaringType, Method method, int lambdaOrdinal) {
public JavaSourcePosition(@NotNull SourcePosition delegate, ReferenceType declaringType, Method method, int lambdaOrdinal) {
super(delegate);
myExpectedClassName = declaringType != null ? declaringType.name() : null;
myExpectedMethodName = method != null ? method.name() : null;
myLambdaOrdinal = lambdaOrdinal;
}
public JavaSourcePosition(@NotNull SourcePosition delegate, int lambdaOrdinal) {
super(delegate);
assert lambdaOrdinal > -1;
myExpectedClassName = null;
myExpectedMethodName = "lambda$"; // fake lambda name
myLambdaOrdinal = lambdaOrdinal;
}
private PsiElement remapElement(PsiElement element) {
String name = JVMNameUtil.getClassVMName(getEnclosingClass(element));
if (name != null && !name.equals(myExpectedClassName)) {
@@ -244,37 +253,34 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
@Override
public SourcePosition mapDelegate(final SourcePosition original) {
return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
@Override
public SourcePosition compute() {
PsiFile file = original.getFile();
int line = original.getLine();
if (DebuggerUtilsEx.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) {
List<PsiLambdaExpression> lambdas = DebuggerUtilsEx.collectLambdas(original, true);
return ReadAction.compute(() -> {
PsiFile file = original.getFile();
int line = original.getLine();
if (DebuggerUtilsEx.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) {
List<PsiLambdaExpression> lambdas = DebuggerUtilsEx.collectLambdas(original, true);
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
if (document == null || line >= document.getLineCount()) {
return original;
}
if (myLambdaOrdinal < lambdas.size()) {
PsiElement firstElem = DebuggerUtilsEx.getFirstElementOnTheLine(lambdas.get(myLambdaOrdinal), document, line);
if (firstElem != null) {
return SourcePosition.createFromElement(firstElem);
}
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
if (document == null || line >= document.getLineCount()) {
return original;
}
if (myLambdaOrdinal < lambdas.size()) {
PsiElement firstElem = DebuggerUtilsEx.getFirstElementOnTheLine(lambdas.get(myLambdaOrdinal), document, line);
if (firstElem != null) {
return SourcePosition.createFromElement(firstElem);
}
}
else {
// There may be more than one class/method code on the line, so we need to find out the correct place
for (PsiElement elem : getLineElements(file, line)) {
PsiElement remappedElement = remapElement(elem);
if (remappedElement != null) {
if (remappedElement.getTextOffset() <= original.getOffset()) break;
return SourcePosition.createFromElement(remappedElement);
}
}
}
return original;
}
else {
// There may be more than one class/method code on the line, so we need to find out the correct place
for (PsiElement elem : getLineElements(file, line)) {
PsiElement remappedElement = remapElement(elem);
if (remappedElement != null) {
if (remappedElement.getTextOffset() <= original.getOffset()) break;
return SourcePosition.createFromElement(remappedElement);
}
}
}
return original;
});
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -28,7 +28,7 @@ abstract class RemappedSourcePosition extends SourcePosition {
private SourcePosition myDelegate;
private boolean myMapped = false;
public RemappedSourcePosition(SourcePosition delegate) {
public RemappedSourcePosition(@NotNull SourcePosition delegate) {
myDelegate = delegate;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -22,10 +22,7 @@ import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaCodeFragment;
import com.intellij.psi.JavaRecursiveElementVisitor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLocalVariable;
import com.intellij.psi.*;
import com.intellij.psi.search.DelegatingGlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.StringBuilderSpinAllocator;
@@ -104,21 +101,19 @@ public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory {
if (session != null) {
XValueMarkers<?, ?> markers = ((XDebugSessionImpl)session).getValueMarkers();
Map<?, ValueMarkup> markupMap = markers != null ? markers.getAllMarkers() : null;
//final Map<ObjectReference, ValueMarkup> markupMap = ValueDescriptorImpl.getMarkupMap(process);
if (!ContainerUtil.isEmpty(markupMap)) {
final Pair<String, Map<String, ObjectReference>> markupVariables = createMarkupVariablesText(markupMap);
int offset = markupVariables.getFirst().length() - 1;
final TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, markupVariables.getFirst(), "", myDelegate.getFileType());
final JavaCodeFragment codeFragment = myDelegate.createCodeFragment(textWithImports, context, project);
codeFragment.accept(new JavaRecursiveElementVisitor() {
public void visitLocalVariable(PsiLocalVariable variable) {
final String name = variable.getName();
variable.putUserData(LABEL_VARIABLE_VALUE_KEY, markupVariables.getSecond().get(name));
}
});
final PsiElement newContext = codeFragment.findElementAt(offset);
if (newContext != null) {
context = newContext;
Pair<String, Map<String, ObjectReference>> markupVariables = createMarkupVariablesText(markupMap);
String text = markupVariables.getFirst();
if (!StringUtil.isEmpty(text)) {
PsiCodeBlock codeFragment =
JavaPsiFacade.getInstance(project).getElementFactory().createCodeBlockFromText("{" + text + "}", context);
codeFragment.accept(new JavaRecursiveElementVisitor() {
public void visitLocalVariable(PsiLocalVariable variable) {
final String name = variable.getName();
variable.putUserData(LABEL_VARIABLE_VALUE_KEY, markupVariables.getSecond().get(name));
}
});
context = codeFragment;
}
}
}
@@ -149,7 +144,6 @@ public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory {
//it.remove();
}
}
buffer.append(" ");
return Pair.create(buffer.toString(), reverseMap);
}
finally {
@@ -761,6 +761,20 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
return null;
}
@Nullable
public static SourcePosition toSourcePosition(@Nullable XSourcePosition position, Project project) {
if (position != null) {
if (position instanceof JavaXSourcePosition) {
return ((JavaXSourcePosition)position).mySourcePosition;
}
PsiFile psiFile = PsiManager.getInstance(project).findFile(position.getFile());
if (psiFile != null) {
return SourcePosition.createFromLine(psiFile, position.getLine());
}
}
return null;
}
private static class JavaXSourcePosition implements XSourcePosition, ExecutionPointHighlighter.HighlighterProvider {
private final SourcePosition mySourcePosition;
@NotNull private final VirtualFile myFile;
@@ -85,6 +85,12 @@ public class MemoryViewDebugProcessData {
myType2Reference2Stack.clear();
}
@Override
public void clear() {
release();
myPinnedType2Reference2Stack.clear();
}
@Nullable
private static List<StackFrameItem> extract(@NotNull Map<ReferenceType, Map<ObjectReference, List<StackFrameItem>>> map,
@NotNull ObjectReference ref) {
@@ -37,4 +37,6 @@ public interface TrackedStacksContainer {
void unpinStacks(@NotNull ReferenceType referenceType);
void release();
void clear();
}
@@ -30,7 +30,6 @@ import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType;
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
@@ -55,7 +54,7 @@ import java.util.List;
public class ConstructorInstancesTracker implements TrackerForNewInstances, Disposable, BackgroundTracker {
private static final int TRACKED_INSTANCES_LIMIT = 2000;
private final ReferenceType myReference;
private final String myClassName;
private final Project myProject;
private final MyConstructorBreakpoints myBreakpoint;
@@ -71,10 +70,10 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
public ConstructorInstancesTracker(@NotNull ReferenceType ref,
@NotNull XDebugSession debugSession,
@NotNull InstancesTracker instancesTracker) {
myReference = ref;
myProject = debugSession.getProject();
myIsBackgroundTrackingEnabled = instancesTracker.isBackgroundTrackingEnabled();
myClassName = ref.name();
final DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject)
.getDebugProcess(debugSession.getDebugProcess().getProcessHandler());
@@ -107,15 +106,7 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
new LineBreakpointState<>());
myBreakpoint = new MyConstructorBreakpoints(myProject, bpn);
myBreakpoint.createRequestForPreparedClass(debugProcess, myReference);
Disposer.register(myBreakpoint, () -> debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
@Override
protected void action() throws Exception {
disable();
debugProcess.getRequestsManager().deleteRequest(myBreakpoint);
myBreakpoint.delete();
}
}));
myBreakpoint.createRequestForPreparedClass(debugProcess, ref);
}
public void obsolete() {
@@ -169,7 +160,9 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
@Override
public void dispose() {
Disposer.dispose(myBreakpoint);
myBreakpoint.delete();
myTrackedObjects.clear();
myNewObjects = null;
}
@Override
@@ -197,7 +190,7 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
}
}
private final class MyConstructorBreakpoints extends LineBreakpoint<JavaLineBreakpointProperties> implements Disposable {
private final class MyConstructorBreakpoints extends LineBreakpoint<JavaLineBreakpointProperties> {
private final List<BreakpointRequest> myRequests = new ArrayList<>();
private volatile boolean myIsEnabled = false;
private volatile boolean myIsDeleted = false;
@@ -225,34 +218,19 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
}
void delete() {
// unable disable all requests here because VMDisconnectedException can be thrown
myRequests.clear();
myIsDeleted = true;
}
@Override
public void dispose() {
}
@Override
public boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event)
throws EventProcessingException {
try {
SuspendContextImpl suspendContext = action.getSuspendContext();
if (suspendContext != null) {
final MemoryViewDebugProcessData data = suspendContext.getDebugProcess().getUserData(MemoryViewDebugProcessData.KEY);
ObjectReference thisRef = getThisObject(suspendContext, event);
if (myReference.equals(thisRef.referenceType()) && data != null) {
thisRef.disableCollection();
myTrackedObjects.add(thisRef);
data.getTrackedStacks().addStack(thisRef, StackFrameItem.createFrames(suspendContext, false));
}
}
if (myIsDeleted) {
event.request().disable();
}
catch (EvaluateException e) {
return false;
}
if (myTrackedObjects.size() >= TRACKED_INSTANCES_LIMIT) {
disable();
else {
handleEvent(action, event);
}
return false;
@@ -271,5 +249,26 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
myIsEnabled = false;
}
}
private void handleEvent(@NotNull SuspendContextCommandImpl action, @NotNull LocatableEvent event) {
try {
SuspendContextImpl suspendContext = action.getSuspendContext();
if (suspendContext != null) {
final MemoryViewDebugProcessData data = suspendContext.getDebugProcess().getUserData(MemoryViewDebugProcessData.KEY);
ObjectReference thisRef = getThisObject(suspendContext, event);
if (thisRef.referenceType().name().equals(myClassName) && data != null) {
thisRef.disableCollection();
myTrackedObjects.add(thisRef);
data.getTrackedStacks().addStack(thisRef, StackFrameItem.createFrames(suspendContext, false));
}
}
}
catch (EvaluateException ignored) {
}
if (myTrackedObjects.size() >= TRACKED_INSTANCES_LIMIT) {
disable();
}
}
}
}
@@ -66,6 +66,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static com.intellij.debugger.memory.ui.ClassesTable.DiffViewTableModel.CLASSNAME_COLUMN_INDEX;
import static com.intellij.debugger.memory.ui.ClassesTable.DiffViewTableModel.DIFF_COLUMN_INDEX;
@@ -88,8 +89,10 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
private final Map<ReferenceType, ConstructorInstancesTracker> myConstructorTrackedClasses = new ConcurrentHashMap<>();
private final MyDebuggerSessionListener myDebugSessionListener;
@Nullable
private volatile SuspendContextImpl myLastSuspendContext;
// tick on each session paused event
private final AtomicInteger myTime = new AtomicInteger(0);
private final AtomicInteger myLastUpdatingTime = new AtomicInteger(Integer.MIN_VALUE);
/**
* Indicates that the debug session had been stopped at least once.
@@ -309,7 +312,6 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
tracker.disable();
}
Disposer.register(this, tracker);
myConstructorTrackedClasses.put(ref, tracker);
}
}
@@ -348,7 +350,6 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
@Override
public void dispose() {
myLastSuspendContext = null;
myConstructorTrackedClasses.clear();
}
@@ -359,12 +360,11 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
myIsActive = active;
final SuspendContext suspendContext = process.getDebuggerContext().getSuspendContext();
process.getManagerThread().schedule(new DebuggerCommandImpl() {
@Override
protected void action() throws Exception {
if (active) {
doActivate(suspendContext);
doActivate();
}
else {
doPause();
@@ -373,12 +373,11 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
});
}
private void doActivate(@Nullable SuspendContext suspendContext) {
private void doActivate() {
myDebugSessionListener.setActive(true);
myConstructorTrackedClasses.values().forEach(x -> x.setBackgroundMode(false));
final SuspendContextImpl lastContext = myLastSuspendContext;
if (lastContext == null || !lastContext.equals(suspendContext)) {
if (isNeedUpdateView()) {
updateClassesAndCounts();
}
}
@@ -389,6 +388,14 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
myConstructorTrackedClasses.values().forEach(x -> x.setBackgroundMode(true));
}
private boolean isNeedUpdateView() {
return myLastUpdatingTime.get() != myTime.get();
}
private void viewUpdated() {
myLastUpdatingTime.set(myTime.get());
}
private final class MyUpdateClassesCommand extends LowestPriorityCommand {
MyUpdateClassesCommand(@Nullable SuspendContextImpl suspendContext) {
@@ -397,7 +404,6 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
@Override
public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception {
myLastSuspendContext = suspendContext;
handleTrackers();
final List<ReferenceType> classes = suspendContext.getDebugProcess().getVirtualMachineProxy().allClasses();
@@ -414,6 +420,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
}
ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(false));
viewUpdated();
}
private void handleTrackers() {
@@ -564,6 +571,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
@Override
public void sessionStopped() {
myConstructorTrackedClasses.values().forEach(Disposer::dispose);
myConstructorTrackedClasses.clear();
mySingleAlarm.cancelAllRequests();
ApplicationManager.getApplication().invokeLater(() -> {
myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_STOPPED);
@@ -577,6 +586,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable
ApplicationManager.getApplication().invokeLater(() -> myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_SUSPENDED));
updateClassesAndCounts();
}
myTime.incrementAndGet();
}
}
}
@@ -241,7 +241,7 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable {
}
private void updateCountsInternal(@NotNull Map<ReferenceType, Long> class2Count) {
final ReferenceType selectedClass = myModel.getSelectedClassBeforeHided();
final ReferenceType selectedClass = myModel.getSelectedClassBeforeHide();
int newSelectedIndex = -1;
final boolean isInitialized = !myItems.isEmpty();
myItems = Collections.unmodifiableList(new ArrayList<>(class2Count.keySet()));
@@ -296,12 +296,11 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable {
}
public void clean() {
if (!myItems.isEmpty()) {
clearSelection();
myItems = Collections.emptyList();
myCounts.clear();
fireTableDataChanged();
}
clearSelection();
myItems = Collections.emptyList();
myCounts.clear();
myModel.mySelectedClassWhenHidden = null;
fireTableDataChanged();
}
@Override
@@ -325,7 +324,7 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable {
final static int DIFF_COLUMN_INDEX = 2;
// Workaround: save selection after content of classes table has been hided
private ReferenceType mySelectedClassWhenHided = null;
private ReferenceType mySelectedClassWhenHidden = null;
private boolean myIsWithContent = false;
DiffViewTableModel() {
@@ -351,13 +350,13 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable {
});
}
ReferenceType getSelectedClassBeforeHided() {
return mySelectedClassWhenHided;
ReferenceType getSelectedClassBeforeHide() {
return mySelectedClassWhenHidden;
}
void hide() {
if (myIsWithContent) {
mySelectedClassWhenHided = getSelectedClass();
mySelectedClassWhenHidden = getSelectedClass();
myIsWithContent = false;
clearSelection();
fireTableDataChanged();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -23,6 +23,7 @@ import com.intellij.debugger.engine.JVMNameUtil;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.engine.requests.RequestManagerImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -235,14 +236,9 @@ public abstract class BreakpointWithHighlighter<P extends JavaBreakpointProperti
@Override
public void reload() {
ApplicationManager.getApplication().assertReadAccessAllowed();
XSourcePosition position = myXBreakpoint.getSourcePosition();
PsiFile psiFile = getPsiFile();
if (position != null && psiFile != null) {
mySourcePosition = SourcePosition.createFromLine(psiFile, position.getLine());
reload(psiFile);
}
else {
mySourcePosition = null;
mySourcePosition = DebuggerUtilsEx.toSourcePosition(myXBreakpoint.getSourcePosition(), myProject);
if (mySourcePosition != null) {
reload(mySourcePosition.getFile());
}
}

Some files were not shown because too many files have changed in this diff Show More