mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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
|
||||
Generated
+18
@@ -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
@@ -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$ { ThreadLocal<$FieldType$> $FieldName$ = $Init$; }" recursive="false" caseInsensitive="false" type="JAVA">
|
||||
<constraint name="Class" script="""" within="" contains="" />
|
||||
<constraint name="FieldType" script="""" 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$ { @StateProperty private $FieldType$ $FieldName$ }" 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$ { @StateProperty @Modifier("packageLocal") $FieldType$ $FieldName$ }" 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$ { @StateProperty protected $FieldType$ $FieldName$ }" 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$)) { $s$ = $s$.substring($e$.length()); }" recursive="false" caseInsensitive="true" type="JAVA" reformatAccordingToStyle="true" shortenFQN="true" replacement="$s$ = com.intellij.openapi.util.text.StringUtil.trimStart($s$, $e$); ">
|
||||
<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=""var = volatile = E" should be "volatile = var = E"" 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=""import com.intellij.psi.PsiField import com.intellij.psi.PsiModifier import com.intellij.psi.PsiReferenceExpression import com.intellij.psi.PsiVariable field instanceof PsiReferenceExpression && ((PsiReferenceExpression)field).resolve() instanceof PsiField && ((PsiField)((PsiReferenceExpression)field).resolve()).hasModifierProperty(PsiModifier.VOLATILE) && var instanceof PsiReferenceExpression && ((PsiReferenceExpression)var).resolve() instanceof PsiVariable && !((PsiVariable)((PsiReferenceExpression)var).resolve()).hasModifierProperty(PsiModifier.VOLATILE)"" 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" />
|
||||
|
||||
+3834
-76
File diff suppressed because it is too large
Load Diff
Generated
+4
-3
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
+172
@@ -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" "$@"
|
||||
Vendored
+84
@@ -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
|
||||
+2
-11
@@ -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'
|
||||
@@ -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']
|
||||
}
|
||||
@@ -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'
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
@@ -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"])
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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=""-Ddeploy=@{deploy}""/>
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
+13
-10
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+78
-17
@@ -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;
|
||||
}
|
||||
}
|
||||
+44
@@ -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;
|
||||
}
|
||||
+167
-31
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+119
-105
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-9
@@ -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);
|
||||
|
||||
+32
-4
@@ -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);
|
||||
}
|
||||
|
||||
+90
@@ -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 + ")"
|
||||
}
|
||||
}
|
||||
+4
-8
@@ -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;
|
||||
}
|
||||
}
|
||||
+56
@@ -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");
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
+41
@@ -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);
|
||||
}
|
||||
}
|
||||
+244
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-13
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+168
@@ -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);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -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;
|
||||
|
||||
+3
-3
@@ -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;
|
||||
+6
-10
@@ -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();
|
||||
+13
-6
@@ -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();
|
||||
+11
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -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) {
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+2
-2
@@ -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;
|
||||
+250
@@ -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);
|
||||
}
|
||||
}
|
||||
+32
-15
@@ -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;
|
||||
}
|
||||
-38
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
-76
@@ -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;
|
||||
}
|
||||
}
|
||||
-178
@@ -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
|
||||
}
|
||||
}
|
||||
-165
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -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();
|
||||
}
|
||||
}
|
||||
-56
@@ -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();
|
||||
}
|
||||
}
|
||||
-129
@@ -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;
|
||||
}
|
||||
}
|
||||
-92
@@ -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());
|
||||
}
|
||||
}
|
||||
-317
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
-222
@@ -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();
|
||||
}
|
||||
}
|
||||
-92
@@ -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;
|
||||
}
|
||||
}
|
||||
-177
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
-291
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-111
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
-107
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
-48
@@ -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);
|
||||
}
|
||||
}
|
||||
-213
@@ -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);
|
||||
}
|
||||
}
|
||||
-66
@@ -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));
|
||||
}
|
||||
}
|
||||
-162
@@ -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;
|
||||
}
|
||||
}
|
||||
-51
@@ -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();
|
||||
}
|
||||
}
|
||||
-60
@@ -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;
|
||||
}
|
||||
}
|
||||
-46
@@ -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));
|
||||
}
|
||||
}
|
||||
-257
@@ -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);
|
||||
}
|
||||
-89
@@ -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()]);
|
||||
}
|
||||
}
|
||||
-102
@@ -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;
|
||||
}
|
||||
}
|
||||
-54
@@ -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());
|
||||
}
|
||||
}
|
||||
-84
@@ -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;
|
||||
}
|
||||
}
|
||||
-83
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+14
-20
@@ -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;
|
||||
|
||||
+6
@@ -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) {
|
||||
|
||||
+2
@@ -37,4 +37,6 @@ public interface TrackedStacksContainer {
|
||||
void unpinStacks(@NotNull ReferenceType referenceType);
|
||||
|
||||
void release();
|
||||
|
||||
void clear();
|
||||
}
|
||||
|
||||
+34
-35
@@ -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();
|
||||
|
||||
+5
-9
@@ -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
Reference in New Issue
Block a user