From f29cb2a4821e5d42c667cdce00fccad9a3f2581e Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 17 Feb 2017 17:08:36 +0100 Subject: [PATCH] UAST initial commit (copy of code from https://github.com/JetBrains/uast) --- .idea/modules.xml | 3 + uast/build.gradle | 95 +++ uast/gradle.properties | 1 + uast/gradlew | 164 +++++ uast/gradlew.bat | 90 +++ uast/settings.gradle | 1 + .../src/org/jetbrains/uast/UastContext.kt | 130 ++++ .../org/jetbrains/uast/UastLanguagePlugin.kt | 123 ++++ .../src/org/jetbrains/uast/UastUtils.kt | 148 ++++ .../jetbrains/uast/baseElements/UComment.kt | 29 + .../jetbrains/uast/baseElements/UElement.kt | 108 +++ .../uast/baseElements/UExpression.kt | 98 +++ .../uast/baseElements/UIdentifier.kt | 33 + .../uast/baseElements/UResolvable.kt | 30 + .../uast/baseElements/UastErrorType.kt | 31 + .../controlStructures/UDoWhileExpression.kt | 66 ++ .../controlStructures/UForEachExpression.kt | 69 ++ .../uast/controlStructures/UForExpression.kt | 78 +++ .../uast/controlStructures/UIfExpression.kt | 101 +++ .../uast/controlStructures/ULoopExpression.kt | 30 + .../controlStructures/USwitchExpression.kt | 122 ++++ .../uast/controlStructures/UTryExpression.kt | 145 ++++ .../controlStructures/UWhileExpression.kt | 60 ++ .../uast/declarations/UAnnotation.kt | 69 ++ .../org/jetbrains/uast/declarations/UClass.kt | 94 +++ .../uast/declarations/UClassInitializer.kt | 55 ++ .../uast/declarations/UDeclaration.kt | 60 ++ .../org/jetbrains/uast/declarations/UFile.kt | 94 +++ .../uast/declarations/UImportStatement.kt | 47 ++ .../jetbrains/uast/declarations/UMethod.kt | 104 +++ .../jetbrains/uast/declarations/UVariable.kt | 141 ++++ .../evaluation/AbstractEvaluationState.kt | 51 ++ .../evaluation/AbstractEvaluatorExtension.kt | 112 +++ .../evaluation/DelegatingEvaluationState.kt | 32 + .../uast/evaluation/EmptyEvaluationState.kt | 27 + .../evaluation/MapBasedEvaluationContext.kt | 79 +++ .../uast/evaluation/MergingEvaluationState.kt | 28 + .../uast/evaluation/TreeBasedEvaluator.kt | 652 ++++++++++++++++++ .../uast/evaluation/UEvaluationContext.kt | 63 ++ .../uast/evaluation/UEvaluationInfo.kt | 35 + .../uast/evaluation/UEvaluationState.kt | 38 + .../jetbrains/uast/evaluation/UEvaluator.kt | 50 ++ .../uast/evaluation/UEvaluatorExtension.kt | 70 ++ .../expressions/UArrayAccessExpression.kt | 52 ++ .../uast/expressions/UBinaryExpression.kt | 65 ++ .../expressions/UBinaryExpressionWithType.kt | 63 ++ .../uast/expressions/UBlockExpression.kt | 49 ++ .../uast/expressions/UBreakExpression.kt | 41 ++ .../uast/expressions/UCallExpression.kt | 116 ++++ .../UCallableReferenceExpression.kt | 67 ++ .../expressions/UClassLiteralExpression.kt | 53 ++ .../uast/expressions/UContinueExpression.kt | 41 ++ .../expressions/UDeclarationsExpression.kt | 46 ++ .../uast/expressions/UExpressionList.kt | 52 ++ .../uast/expressions/UInstanceExpression.kt | 22 + .../uast/expressions/UJumpExpression.kt | 26 + .../uast/expressions/ULabeledExpression.kt | 52 ++ .../uast/expressions/ULambdaExpression.kt | 58 ++ .../uast/expressions/ULiteralExpression.kt | 74 ++ .../uast/expressions/UNamedExpression.kt | 38 + .../expressions/UObjectLiteralExpression.kt | 65 ++ .../expressions/UParenthesizedExpression.kt | 47 ++ .../uast/expressions/UPolyadicExpression.kt | 53 ++ .../UQualifiedReferenceExpression.kt | 56 ++ .../uast/expressions/UReferenceExpression.kt | 31 + .../uast/expressions/UReturnExpression.kt | 46 ++ .../USimpleNameReferenceExpression.kt | 44 ++ .../uast/expressions/USuperExpression.kt | 40 ++ .../uast/expressions/UThisExpression.kt | 40 ++ .../uast/expressions/UThrowExpression.kt | 46 ++ .../expressions/UTypeReferenceExpression.kt | 48 ++ .../uast/expressions/UUnaryExpression.kt | 92 +++ .../uast/expressions/uastLiteralUtils.kt | 98 +++ .../uast/internal/implementationUtils.kt | 31 + .../uast/internal/internalUastUtils.kt | 45 ++ .../kinds/UastBinaryExpressionWithTypeKind.kt | 37 + .../uast/kinds/UastBinaryOperator.kt | 133 ++++ .../org/jetbrains/uast/kinds/UastCallKind.kt | 47 ++ .../org/jetbrains/uast/kinds/UastClassKind.kt | 43 ++ .../org/jetbrains/uast/kinds/UastOperator.kt | 28 + .../uast/kinds/UastPostfixOperator.kt | 34 + .../uast/kinds/UastPrefixOperator.kt | 46 ++ .../UastQualifiedExpressionAccessType.kt | 31 + .../uast/kinds/UastSpecialExpressionKind.kt | 25 + .../jetbrains/uast/kinds/UastVisibility.kt | 40 ++ .../uast/psi/UElementWithLocation.kt | 21 + .../uast/psi/UastPsiParameterNotResolved.kt | 26 + .../src/org/jetbrains/uast/qualifiedUtils.kt | 199 ++++++ .../src/org/jetbrains/uast/util/callUtils.kt | 43 ++ .../jetbrains/uast/values/UCallResultValue.kt | 31 + .../org/jetbrains/uast/values/UConstant.kt | 426 ++++++++++++ .../org/jetbrains/uast/values/UDependency.kt | 19 + .../jetbrains/uast/values/UDependentValue.kt | 137 ++++ .../jetbrains/uast/values/UNothingValue.kt | 79 +++ .../src/org/jetbrains/uast/values/UOperand.kt | 68 ++ .../org/jetbrains/uast/values/UPhiValue.kt | 40 ++ .../uast/values/UUndeterminedValue.kt | 23 + .../src/org/jetbrains/uast/values/UValue.kt | 46 ++ .../org/jetbrains/uast/values/UValueBase.kt | 100 +++ .../jetbrains/uast/values/UVariableValue.kt | 104 +++ .../uast/visitor/DelegatingUastVisitor.kt | 174 +++++ .../uast/visitor/UastTypedVisitor.kt | 84 +++ .../org/jetbrains/uast/visitor/UastVisitor.kt | 134 ++++ uast/uast-common/uast-common.iml | 14 + .../uast/java/JavaAbstractUElement.kt | 53 ++ .../uast/java/JavaUastLanguagePlugin.kt | 334 +++++++++ .../JavaUDoWhileExpression.kt | 35 + .../JavaUForEachExpression.kt | 37 + .../controlStructures/JavaUForExpression.kt | 35 + .../controlStructures/JavaUIfExpression.kt | 40 ++ .../JavaUSwitchExpression.kt | 116 ++++ .../JavaUTernaryIfExpression.kt | 39 ++ .../controlStructures/JavaUTryExpression.kt | 65 ++ .../controlStructures/JavaUWhileExpression.kt | 33 + .../uast/java/declarations/JavaUAnnotation.kt | 61 ++ .../uast/java/declarations/JavaUClass.kt | 88 +++ .../declarations/JavaUClassInitializer.kt | 40 ++ .../uast/java/declarations/JavaUFile.kt | 51 ++ .../java/declarations/JavaUImportStatement.kt | 30 + .../uast/java/declarations/JavaUMethod.kt | 68 ++ .../uast/java/declarations/JavaUVariable.kt | 128 ++++ .../uast/java/expressions/JavaDumbUElement.kt | 29 + .../expressions/JavaUArrayAccessExpression.kt | 28 + .../java/expressions/JavaUAssertExpression.kt | 67 ++ .../expressions/JavaUAssignmentExpression.kt | 35 + .../java/expressions/JavaUBinaryExpression.kt | 35 + .../java/expressions/JavaUBlockExpression.kt | 27 + .../java/expressions/JavaUBreakExpression.kt | 29 + .../JavaUCallableReferenceExpression.kt | 40 ++ .../JavaUClassLiteralExpression.kt | 31 + .../expressions/JavaUCodeBlockExpression.kt | 27 + .../JavaUCompositeQualifiedExpression.kt | 39 ++ .../expressions/JavaUContinueExpression.kt | 29 + .../JavaUDeclarationsExpression.kt | 39 ++ .../java/expressions/JavaUExpressionList.kt | 32 + .../JavaUInstanceCheckExpression.kt | 37 + .../expressions/JavaULabeledExpression.kt | 36 + .../java/expressions/JavaULambdaExpression.kt | 41 ++ .../expressions/JavaULiteralExpression.kt | 28 + .../java/expressions/JavaUNamedExpression.kt | 38 + .../JavaUObjectLiteralExpression.kt | 49 ++ .../JavaUParenthesizedExpression.kt | 28 + .../expressions/JavaUPolyadicExpression.kt | 31 + .../expressions/JavaUPostfixExpression.kt | 41 ++ .../java/expressions/JavaUPrefixExpression.kt | 45 ++ .../JavaUQualifiedReferenceExpression.kt | 41 ++ .../java/expressions/JavaUReturnExpression.kt | 28 + .../JavaUSimpleNameReferenceExpression.kt | 59 ++ .../java/expressions/JavaUSuperExpression.kt | 34 + .../JavaUSynchronizedExpression.kt | 41 ++ .../java/expressions/JavaUThisExpression.kt | 34 + .../java/expressions/JavaUThrowExpression.kt | 28 + .../expressions/JavaUTypeCastExpression.kt | 38 + .../java/expressions/UnknownJavaExpression.kt | 31 + .../java/expressions/javaUCallExpressions.kt | 225 ++++++ .../java/internal/JavaUElementWithComments.kt | 28 + .../java/internal/javaInternalUastUtils.kt | 85 +++ .../java/kinds/JavaSpecialExpressionKinds.kt | 26 + .../uast/java/kinds/JavaUastCallKinds.kt | 23 + uast/uast-java/uast-java.iml | 15 + .../uast/test/common/RenderLogTestBase.kt | 36 + .../uast/test/common/ResolveTestBase.kt | 36 + .../uast/test/common/TypesTestBase.kt | 71 ++ .../uast/test/common/ValuesTestBase.kt | 78 +++ .../uast/test/env/AbstractCoreEnvironment.kt | 30 + .../env/AbstractTestWithCoreEnvironment.kt | 107 +++ .../uast/test/env/AbstractUastTest.kt | 61 ++ .../uast/test/env/TestCoreEnvironment.java | 203 ++++++ uast/uast-tests/uast-tests.iml | 19 + uast/updateDependencies.gradle | 20 + 170 files changed, 11096 insertions(+) create mode 100644 uast/build.gradle create mode 100644 uast/gradle.properties create mode 100755 uast/gradlew create mode 100644 uast/gradlew.bat create mode 100644 uast/settings.gradle create mode 100644 uast/uast-common/src/org/jetbrains/uast/UastContext.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/UastUtils.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/baseElements/UComment.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/baseElements/UElement.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/baseElements/UExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/baseElements/UIdentifier.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/baseElements/UResolvable.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/baseElements/UastErrorType.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/UDoWhileExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/UForEachExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/UForExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/UIfExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/ULoopExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/USwitchExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/UTryExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/controlStructures/UWhileExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UAnnotation.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UClass.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UClassInitializer.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UFile.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UImportStatement.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UMethod.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/declarations/UVariable.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluationState.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluatorExtension.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/DelegatingEvaluationState.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/EmptyEvaluationState.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/MapBasedEvaluationContext.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/MergingEvaluationState.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/TreeBasedEvaluator.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationContext.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationInfo.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationState.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluator.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluatorExtension.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UArrayAccessExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpressionWithType.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UBlockExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UBreakExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UCallExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UCallableReferenceExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UClassLiteralExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UContinueExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UDeclarationsExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UExpressionList.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UInstanceExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UJumpExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/ULabeledExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/ULambdaExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/ULiteralExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UNamedExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UObjectLiteralExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UParenthesizedExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UPolyadicExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UQualifiedReferenceExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UReferenceExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UReturnExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/USimpleNameReferenceExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/USuperExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UThrowExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UTypeReferenceExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/UUnaryExpression.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/expressions/uastLiteralUtils.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/internal/implementationUtils.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/internal/internalUastUtils.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryExpressionWithTypeKind.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryOperator.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastCallKind.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastClassKind.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastOperator.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastPostfixOperator.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastPrefixOperator.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastQualifiedExpressionAccessType.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastSpecialExpressionKind.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/kinds/UastVisibility.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/psi/UElementWithLocation.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/psi/UastPsiParameterNotResolved.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/qualifiedUtils.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/util/callUtils.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UCallResultValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UConstant.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UDependency.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UDependentValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UNothingValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UOperand.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UPhiValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UUndeterminedValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UValueBase.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/values/UVariableValue.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/visitor/DelegatingUastVisitor.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/visitor/UastTypedVisitor.kt create mode 100644 uast/uast-common/src/org/jetbrains/uast/visitor/UastVisitor.kt create mode 100644 uast/uast-common/uast-common.iml create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUDoWhileExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForEachExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUIfExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTernaryIfExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTryExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUWhileExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUAnnotation.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClassInitializer.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFile.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUImportStatement.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUMethod.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaDumbUElement.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUArrayAccessExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssertExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssignmentExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBinaryExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBlockExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBreakExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCallableReferenceExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUClassLiteralExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCodeBlockExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCompositeQualifiedExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUContinueExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUDeclarationsExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUExpressionList.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceCheckExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULabeledExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULambdaExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULiteralExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUNamedExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUParenthesizedExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPolyadicExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPostfixExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPrefixExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUQualifiedReferenceExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUReturnExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSimpleNameReferenceExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSuperExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSynchronizedExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThisExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThrowExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUTypeCastExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/UnknownJavaExpression.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/internal/JavaUElementWithComments.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaSpecialExpressionKinds.kt create mode 100644 uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaUastCallKinds.kt create mode 100644 uast/uast-java/uast-java.iml create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/common/RenderLogTestBase.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/common/ResolveTestBase.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/common/TypesTestBase.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/common/ValuesTestBase.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractCoreEnvironment.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractTestWithCoreEnvironment.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractUastTest.kt create mode 100644 uast/uast-tests/src/org/jetbrains/uast/test/env/TestCoreEnvironment.java create mode 100644 uast/uast-tests/uast-tests.iml create mode 100644 uast/updateDependencies.gradle diff --git a/.idea/modules.xml b/.idea/modules.xml index 543263c1b657..3455ca934d71 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -270,6 +270,9 @@ + + + diff --git a/uast/build.gradle b/uast/build.gradle new file mode 100644 index 000000000000..8ae03b7a9302 --- /dev/null +++ b/uast/build.gradle @@ -0,0 +1,95 @@ +buildscript { + ext.kotlin_version = '1.0.5' + ext.intellij_core_version = '171.3019.7' + repositories { + jcenter() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' + classpath 'de.undercouch:gradle-download-task:3.1.2' + } +} + +String getUastVersion() { + return System.getenv("ARTIFACT_VERSION") ?: "1.0" +} + +apply from: 'updateDependencies.gradle' + +allprojects { + group = 'org.jetbrains.uast' + version = getUastVersion() + + apply plugin: 'java' + apply plugin: 'kotlin' + apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'com.jfrog.bintray' + apply plugin: "maven-publish" + + configurations { + provided + } + + sourceSets { + main { + compileClasspath += configurations.provided + + java.srcDirs = ['src'] + kotlin.srcDirs = ['src'] + } + + test { + java.srcDirs = ['test'] + kotlin.srcDirs = ['test'] + } + } + + compileJava { + sourceCompatibility = 1.6 + targetCompatibility = 1.6 + } + + repositories { + jcenter() + } + + task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource + } + + bintray { + user = System.getenv("BINTRAY_USER") ?: "" + key = System.getenv("BINTRAY_API_KEY") ?: "" + + publications = ['UastPublication'] + + pkg { + repo = 'uast' + name = 'uast' + userOrg = 'kotlin' + licenses = ['Apache-2.0'] + vcsUrl = SCM_URL + + version { + name = getUastVersion() + released = new Date() + } + } + } + + publishing { + publications { + UastPublication(MavenPublication) { + from components.java + groupId 'org.jetbrains.uast' + artifactId project.name + version getUastVersion() + + artifact sourcesJar + } + } + } +} \ No newline at end of file diff --git a/uast/gradle.properties b/uast/gradle.properties new file mode 100644 index 000000000000..2c33935b50ce --- /dev/null +++ b/uast/gradle.properties @@ -0,0 +1 @@ +SCM_URL=https://github.com/JetBrains/uast \ No newline at end of file diff --git a/uast/gradlew b/uast/gradlew new file mode 100755 index 000000000000..91a7e269e19d --- /dev/null +++ b/uast/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# 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 +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# 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\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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" ] ; 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"` + + # 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 + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/uast/gradlew.bat b/uast/gradlew.bat new file mode 100644 index 000000000000..8a0b282aa688 --- /dev/null +++ b/uast/gradlew.bat @@ -0,0 +1,90 @@ +@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 + +@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= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@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 Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_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=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +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 diff --git a/uast/settings.gradle b/uast/settings.gradle new file mode 100644 index 000000000000..7ddee0eacbf6 --- /dev/null +++ b/uast/settings.gradle @@ -0,0 +1 @@ +include ':uast-common', ':uast-java', ':uast-tests' diff --git a/uast/uast-common/src/org/jetbrains/uast/UastContext.kt b/uast/uast-common/src/org/jetbrains/uast/UastContext.kt new file mode 100644 index 000000000000..80111f822e22 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/UastContext.kt @@ -0,0 +1,130 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.lang.Language +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.project.Project +import com.intellij.psi.* + +/** + * Manages the UAST to PSI conversion. + */ +class UastContext(val project: Project) : UastLanguagePlugin { + private companion object { + private val CONTEXT_LANGUAGE = object : Language("UastContextLanguage") {} + } + + override val language: Language + get() = CONTEXT_LANGUAGE + + override val priority: Int + get() = 0 + + val languagePlugins: Collection + get() = UastLanguagePlugin.getInstances() + + fun findPlugin(element: PsiElement): UastLanguagePlugin? { + val language = element.language + return languagePlugins.firstOrNull { it.language == language } + } + + override fun isFileSupported(fileName: String) = languagePlugins.any { it.isFileSupported(fileName) } + + fun getMethod(method: PsiMethod): UMethod = convertWithParent(method)!! + + fun getVariable(variable: PsiVariable): UVariable = convertWithParent(variable)!! + + fun getClass(clazz: PsiClass): UClass = convertWithParent(clazz)!! + + override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class?): UElement? { + return findPlugin(element)?.convertElement(element, parent, requiredType) + } + + override fun convertElementWithParent(element: PsiElement, requiredType: Class?): UElement? { + return findPlugin(element)?.convertElementWithParent(element, requiredType) + } + + override fun getMethodCallExpression( + element: PsiElement, + containingClassFqName: String?, + methodName: String + ): UastLanguagePlugin.ResolvedMethod? { + return findPlugin(element)?.getMethodCallExpression(element, containingClassFqName, methodName) + } + + override fun getConstructorCallExpression( + element: PsiElement, + fqName: String + ): UastLanguagePlugin.ResolvedConstructor? { + return findPlugin(element)?.getConstructorCallExpression(element, fqName) + } + + override fun isExpressionValueUsed(element: UExpression): Boolean { + val language = element.getLanguage() + return (languagePlugins.firstOrNull { it.language == language })?.isExpressionValueUsed(element) ?: false + } + + private tailrec fun UElement.getLanguage(): Language { + psi?.language?.let { return it } + val containingElement = this.uastParent ?: throw IllegalStateException("At least UFile should have a language") + return containingElement.getLanguage() + } +} + +/** + * Converts the element along with its parents to UAST. + */ +fun PsiElement?.toUElement() = + this?.let { ServiceManager.getService(project, UastContext::class.java).convertElementWithParent(this, null) } + +/** + * Converts the element to an UAST element of the given type. Returns null if the PSI element type does not correspond + * to the given UAST element type. + */ +fun PsiElement?.toUElement(cls: Class): T? = + this?.let { ServiceManager.getService(project, UastContext::class.java).convertElementWithParent(this, cls) as T? } + +inline fun PsiElement?.toUElementOfType(): T? = + this?.let { ServiceManager.getService(project, UastContext::class.java).convertElementWithParent(this, T::class.java) as T? } + +/** + * Finds an UAST element of a given type at the given [offset] in the specified file. Returns null if there is no UAST + * element of the given type at the given offset. + */ +fun PsiFile.findUElementAt(offset: Int, cls: Class): T? { + val element = findElementAt(offset) ?: return null + val uElement = element.toUElement() ?: return null + @Suppress("UNCHECKED_CAST") + return uElement.withContainingElements.firstOrNull { cls.isInstance(it) } as T? +} + +/** + * Finds an UAST element of the given type among the parents of the given PSI element. + */ +@JvmOverloads +fun PsiElement?.getUastParentOfType(cls: Class, strict: Boolean = false): T? { + val uElement = this.toUElement() ?: return null + val sequence = if (strict) + (uElement.uastParent?.withContainingElements ?: emptySequence()) + else + uElement.withContainingElements + + @Suppress("UNCHECKED_CAST") + return sequence.firstOrNull { cls.isInstance(it) } as T? +} + +inline fun PsiElement?.getUastParentOfType(strict: Boolean = false): T? = getUastParentOfType(T::class.java, strict) diff --git a/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt b/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt new file mode 100644 index 000000000000..101a8522f2dc --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt @@ -0,0 +1,123 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.lang.Language +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.extensions.Extensions +import com.intellij.psi.* + +interface UastLanguagePlugin { + companion object { + val extensionPointName: ExtensionPointName = + ExtensionPointName.create("org.jetbrains.uast.uastLanguagePlugin") + + fun getInstances(): Collection { + val rootArea = Extensions.getRootArea() + if (!rootArea.hasExtensionPoint(extensionPointName.name)) return listOf() + return rootArea.getExtensionPoint(extensionPointName).extensions.toList() + } + } + + data class ResolvedMethod(val call: UCallExpression, val method: PsiMethod) + data class ResolvedConstructor(val call: UCallExpression, val constructor: PsiMethod, val clazz: PsiClass) + + val language: Language + + /** + * Checks if the file with the given [fileName] is supported. + * + * @param fileName the source file name. + * @return true, if the file is supported by this converter, false otherwise. + */ + fun isFileSupported(fileName: String): Boolean + + /** + * Returns the converter priority. Might be positive, negative or 0 (Java's is 0). + * UastConverter with the higher priority will be queried earlier. + * + * Priority is useful when a language N wraps its own elements (NElement) to, for example, Java's PsiElements, + * and Java resolves the reference to such wrapped PsiElements, not the original NElement. + * In this case N implementation can handle such wrappers in UastConverter earlier than Java's converter, + * so N language converter will have a higher priority. + */ + val priority: Int + + /** + * Converts a PSI element, the parent of which already has an UAST representation, to UAST. + * + * @param element the element to convert + * @param parent the parent as an UAST element, or null if the element is a file + * @param requiredType the expected type of the result. + * @return the converted element, or null if the element isn't supported or doesn't match the required result type. + */ + fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class? = null): UElement? + + /** + * Converts a PSI element, along with its chain of parents, to UAST. + * + * @param element the element to convert + * @param requiredType the expected type of the result. + * @return the converted element, or null if the element isn't supported or doesn't match the required result type. + */ + fun convertElementWithParent(element: PsiElement, requiredType: Class?): UElement? + + fun getMethodCallExpression( + element: PsiElement, + containingClassFqName: String?, + methodName: String + ): ResolvedMethod? + + fun getConstructorCallExpression( + element: PsiElement, + fqName: String + ) : ResolvedConstructor? + + fun getMethodBody(element: PsiMethod): UExpression? { + if (element is UMethod) return element.uastBody + return (convertElementWithParent(element, null) as? UMethod)?.uastBody + } + + fun getInitializerBody(element: PsiClassInitializer): UExpression { + if (element is UClassInitializer) return element.uastBody + return (convertElementWithParent(element, null) as? UClassInitializer)?.uastBody ?: UastEmptyExpression + } + + fun getInitializerBody(element: PsiVariable): UExpression? { + if (element is UVariable) return element.uastInitializer + return (convertElementWithParent(element, null) as? UVariable)?.uastInitializer + } + + /** + * Returns true if the expression value is used. + * Do not rely on this property too much, its value can be approximate in some cases. + */ + fun isExpressionValueUsed(element: UExpression): Boolean +} + +inline fun UastLanguagePlugin.convertOpt(element: PsiElement?, parent: UElement?): T? { + if (element == null) return null + return convertElement(element, parent) as? T +} + +inline fun UastLanguagePlugin.convert(element: PsiElement, parent: UElement?): T { + return convertElement(element, parent, T::class.java) as T +} + +inline fun UastLanguagePlugin.convertWithParent(element: PsiElement?): T? { + if (element == null) return null + return convertElementWithParent(element, T::class.java) as? T +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt b/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt new file mode 100644 index 000000000000..c0fb99739dab --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt @@ -0,0 +1,148 @@ +/* + * 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. + */ +@file:JvmMultifileClass +@file:JvmName("UastUtils") +package org.jetbrains.uast + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNamedElement +import com.intellij.psi.util.PsiTreeUtil +import java.io.File + +inline fun UElement.getParentOfType(strict: Boolean = true): T? = getParentOfType(T::class.java, strict) + +@JvmOverloads +fun UElement.getParentOfType(parentClass: Class, strict: Boolean = true): T? { + var element = (if (strict) uastParent else this) ?: return null + while (true) { + if (parentClass.isInstance(element)) { + @Suppress("UNCHECKED_CAST") + return element as T + } + element = element.uastParent ?: return null + } +} + +fun UElement.getParentOfType( + parentClass: Class, + strict: Boolean = true, + vararg terminators: Class +): T? { + var element = (if (strict) uastParent else this) ?: return null + while (true) { + if (parentClass.isInstance(element)) { + @Suppress("UNCHECKED_CAST") + return element as T + } + if (terminators.any { it.isInstance(element) }) { + return null + } + element = element.uastParent ?: return null + } +} + +fun UElement.getParentOfType( + strict: Boolean = true, + firstParentClass: Class, + vararg parentClasses: Class +): T? { + var element = (if (strict) uastParent else this) ?: return null + while (true) { + if (firstParentClass.isInstance(element)) { + @Suppress("UNCHECKED_CAST") + return element as T + } + if (parentClasses.any { it.isInstance(element) }) { + @Suppress("UNCHECKED_CAST") + return element as T + } + element = element.uastParent ?: return null + } +} + +fun UElement.getContainingFile() = getParentOfType(UFile::class.java) + +fun UElement.getContainingUClass() = getParentOfType(UClass::class.java) +fun UElement.getContainingUMethod() = getParentOfType(UMethod::class.java) +fun UElement.getContainingUVariable() = getParentOfType(UVariable::class.java) + +fun UElement.getContainingMethod() = getContainingUMethod()?.psi +fun UElement.getContainingClass() = getContainingUClass()?.psi +fun UElement.getContainingVariable() = getContainingUVariable()?.psi + +fun PsiElement?.getContainingClass() = this?.let { PsiTreeUtil.getParentOfType(it, PsiClass::class.java) } + +fun UElement.isChildOf(probablyParent: UElement?, strict: Boolean = false): Boolean { + tailrec fun isChildOf(current: UElement?, probablyParent: UElement): Boolean { + return when (current) { + null -> false + probablyParent -> true + else -> isChildOf(current.uastParent, probablyParent) + } + } + + if (probablyParent == null) return false + return isChildOf(if (strict) this else uastParent, probablyParent) +} + +/** + * Resolves the receiver element if it implements [UResolvable]. + * + * @return the resolved element, or null if the element was not resolved, or if the receiver element is not an [UResolvable]. + */ +fun UElement.tryResolve(): PsiElement? = (this as? UResolvable)?.resolve() + +fun UElement.tryResolveNamed(): PsiNamedElement? = (this as? UResolvable)?.resolve() as? PsiNamedElement + +fun UElement.tryResolveUDeclaration(context: UastContext): UDeclaration? { + return (this as? UResolvable)?.resolve()?.let { context.convertElementWithParent(it, null) as? UDeclaration } +} + +fun UReferenceExpression?.getQualifiedName() = (this?.resolve() as? PsiClass)?.qualifiedName + +/** + * Returns the String expression value, or null if the value can't be calculated or if the calculated value is not a String. + */ +fun UExpression.evaluateString(): String? = evaluate() as? String + +/** + * Get a physical [File] for this file, or null if there is no such file on disk. + */ +fun UFile.getIoFile(): File? = psi.virtualFile?.let { VfsUtilCore.virtualToIoFile(it) } + +tailrec fun UElement.getUastContext(): UastContext { + val psi = this.psi + if (psi != null) { + return ServiceManager.getService(psi.project, UastContext::class.java) ?: error("UastContext not found") + } + + return (uastParent ?: error("PsiElement should exist at least for UFile")).getUastContext() +} + +tailrec fun UElement.getLanguagePlugin(): UastLanguagePlugin { + val psi = this.psi + if (psi != null) { + val uastContext = ServiceManager.getService(psi.project, UastContext::class.java) ?: error("UastContext not found") + return uastContext.findPlugin(psi) ?: error("Language plugin was not found for $this (${this.javaClass.name})") + } + + return (uastParent ?: error("PsiElement should exist at least for UFile")).getLanguagePlugin() +} + +fun Collection.toPsiElements() = mapNotNull { it.psi } diff --git a/uast/uast-common/src/org/jetbrains/uast/baseElements/UComment.kt b/uast/uast-common/src/org/jetbrains/uast/baseElements/UComment.kt new file mode 100644 index 000000000000..67bc9d3608f1 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/baseElements/UComment.kt @@ -0,0 +1,29 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.internal.log + +class UComment(override val psi: PsiElement, override val uastParent: UElement) : UElement { + val text: String + get() = asSourceString() + + override fun asLogString() = log() + + override fun asRenderString(): String = asSourceString() + override fun asSourceString(): String = psi.text +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/baseElements/UElement.kt b/uast/uast-common/src/org/jetbrains/uast/baseElements/UElement.kt new file mode 100644 index 000000000000..75a0f28f5fd0 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/baseElements/UElement.kt @@ -0,0 +1,108 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * The common interface for all Uast elements. + */ +interface UElement { + /** + * Returns the element parent. + */ + val uastParent: UElement? + + /** + * Returns the PSI element underlying this element. Note that some UElements are synthetic and do not have + * an underlying PSI element; this doesn't mean that they are invalid. + */ + val psi: PsiElement? + + /** + * Returns true if this element is valid, false otherwise. + */ + val isPsiValid: Boolean + get() = psi?.isValid ?: true + + /** + * Returns the list of comments for this element. + */ + val comments: List + get() = emptyList() + + /** + * Returns the log string (usually one line containing the class name and some additional information). + * + * Examples: + * UWhileExpression + * UBinaryExpression (>) + * UCallExpression (println) + * USimpleReferenceExpression (i) + * ULiteralExpression (5) + * + * @return the expression tree for this element. + * @see [UIfExpression] for example. + */ + fun asLogString(): String + + /** + * Returns the string in pseudo-code. + * + * Output example (should be something like this): + * while (i > 5) { + * println("Hello, world") + * i-- + * } + * + * @return the rendered text. + * @see [UIfExpression] for example. + */ + fun asRenderString(): String = asLogString() + + /** + * Returns the string as written in the source file. + * Use this String only for logging and diagnostic text messages. + * + * @return the original text. + */ + fun asSourceString(): String = asRenderString() + + /** + * Passes the element to the specified visitor. + * + * @param visitor the visitor to pass the element to. + */ + fun accept(visitor: UastVisitor) { + visitor.visitElement(this) + visitor.afterVisitElement(this) + } + + /** + * Passes the element to the specified typed visitor. + * + * @param visitor the visitor to pass the element to. + */ + fun accept(visitor: UastTypedVisitor, data: D): R = visitor.visitElement(this, data) +} + +/** + * Returns a sequence including this element and its containing elements. + */ +val UElement.withContainingElements: Sequence + get() = generateSequence(this, UElement::uastParent) diff --git a/uast/uast-common/src/org/jetbrains/uast/baseElements/UExpression.kt b/uast/uast-common/src/org/jetbrains/uast/baseElements/UExpression.kt new file mode 100644 index 000000000000..a94693db5fe1 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/baseElements/UExpression.kt @@ -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 org.jetbrains.uast + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents an expression or statement (which is considered as an expression in Uast). + */ +interface UExpression : UElement, UAnnotated { + /** + * Returns the expression value or null if the value can't be calculated. + */ + fun evaluate(): Any? = null + + /** + * Returns expression type, or null if type can not be inferred, or if this expression is a statement. + */ + fun getExpressionType(): PsiType? = null + + override fun accept(visitor: UastVisitor) { + visitor.visitElement(this) + visitor.afterVisitElement(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitExpression(this, data) +} + +/** + * Represents an annotated element. + */ +interface UAnnotated : UElement { + /** + * Returns the list of annotations applied to the current element. + */ + val annotations: List + + /** + * Looks up for annotation element using the annotation qualified name. + * + * @param fqName the qualified name to search + * @return the first annotation element with the specified qualified name, or null if there is no annotation with such name. + */ + fun findAnnotation(fqName: String): UAnnotation? = annotations.firstOrNull { it.qualifiedName == fqName } +} + +/** + * Represents a labeled element. + */ +interface ULabeled : UElement { + /** + * Returns the label name, or null if the label is empty. + */ + val label: String? + + /** + * Returns the label identifier, or null if the label is empty. + */ + val labelIdentifier: UIdentifier? +} + +/** + * In some cases (user typing, syntax error) elements, which are supposed to exist, are missing. + * The obvious example — the lack of the condition expression in [UIfExpression], e.g. `if () return`. + * [UIfExpression.condition] is required to return not-null values, + * and Uast implementation should return something instead of `null` in this case. + * + * Use [UastEmptyExpression] in this case. + */ +object UastEmptyExpression : UExpression { + override val uastParent: UElement? + get() = null + + override val annotations: List + get() = emptyList() + + override val psi: PsiElement? + get() = null + + override fun asLogString() = log() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/baseElements/UIdentifier.kt b/uast/uast-common/src/org/jetbrains/uast/baseElements/UIdentifier.kt new file mode 100644 index 000000000000..fde8d72e4e9b --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/baseElements/UIdentifier.kt @@ -0,0 +1,33 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.internal.log + +class UIdentifier( + override val psi: PsiElement?, + override val uastParent: UElement? +) : UElement { + /** + * Returns the identifier name. + */ + val name: String + get() = psi?.text ?: "" + + override fun asLogString() = log("Identifier ($name)") +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/baseElements/UResolvable.kt b/uast/uast-common/src/org/jetbrains/uast/baseElements/UResolvable.kt new file mode 100644 index 000000000000..ada0da0b7c46 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/baseElements/UResolvable.kt @@ -0,0 +1,30 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiElement + +interface UResolvable { + /** + * Resolve the reference. + * Note that the reference is *always* resolved to an unwrapped [PsiElement], never to a [UElement]. + * + * @return the resolved element, or null if the reference couldn't be resolved. + */ + fun resolve(): PsiElement? +} + +fun UResolvable.resolveToUElement(): UElement? = resolve().toUElement() diff --git a/uast/uast-common/src/org/jetbrains/uast/baseElements/UastErrorType.kt b/uast/uast-common/src/org/jetbrains/uast/baseElements/UastErrorType.kt new file mode 100644 index 000000000000..33782a61e0bf --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/baseElements/UastErrorType.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiType +import com.intellij.psi.PsiTypeVisitor + +object UastErrorType : PsiType(emptyArray()) { + override fun getInternalCanonicalText() = "" + override fun equalsToText(text: String) = false + override fun getCanonicalText() = internalCanonicalText + override fun getPresentableText() = canonicalText + override fun isValid() = false + override fun getResolveScope() = null + override fun getSuperTypes() = emptyArray() + + override fun accept(visitor: PsiTypeVisitor) = visitor.visitType(this) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/UDoWhileExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UDoWhileExpression.kt new file mode 100644 index 000000000000..bc5f8504620b --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UDoWhileExpression.kt @@ -0,0 +1,66 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represent a + * + * `do { + * // body + * } while (expr)` + * + * loop expression. + */ +interface UDoWhileExpression : ULoopExpression { + /** + * Returns the loop post-condition. + */ + val condition: UExpression + + /** + * Returns an identifier for the 'do' keyword. + */ + val doIdentifier: UIdentifier + + /** + * Returns an identifier for the 'while' keyword. + */ + val whileIdentifier: UIdentifier + + override fun accept(visitor: UastVisitor) { + if (visitor.visitDoWhileExpression(this)) return + annotations.acceptList(visitor) + condition.accept(visitor) + body.accept(visitor) + visitor.afterVisitDoWhileExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitDoWhileExpression(this, data) + + override fun asRenderString() = buildString { + append("do ") + append(body.asRenderString()) + appendln("while (${condition.asRenderString()})") + } + + override fun asLogString() = log() +} diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/UForEachExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UForEachExpression.kt new file mode 100644 index 000000000000..880030b077c9 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UForEachExpression.kt @@ -0,0 +1,69 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a + * + * `for (element : collectionOfElements) { + * // body + * }` + * + * loop expression. + */ +interface UForEachExpression : ULoopExpression { + /** + * Returns the loop variable. + */ + val variable: UParameter + + /** + * Returns the iterated value (collection, sequence, iterable etc.) + */ + val iteratedValue: UExpression + + /** + * Returns the identifier for the 'for' ('foreach') keyword. + */ + val forIdentifier: UIdentifier + + override fun accept(visitor: UastVisitor) { + if (visitor.visitForEachExpression(this)) return + annotations.acceptList(visitor) + iteratedValue.accept(visitor) + body.accept(visitor) + visitor.afterVisitForEachExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitForEachExpression(this, data) + + override fun asRenderString() = buildString { + append("for (") + append(variable.name) + append(" : ") + append(iteratedValue.asRenderString()) + append(") ") + append(body.asRenderString()) + } + + override fun asLogString() = log() +} diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/UForExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UForExpression.kt new file mode 100644 index 000000000000..d32c3969dfee --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UForExpression.kt @@ -0,0 +1,78 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a + * + * `for (initDeclarations; loopCondition; update) { + * // body + * }` + * + * loop expression. + */ +interface UForExpression : ULoopExpression { + /** + * Returns the [UExpression] containing variable declarations, or null if the are no variables declared. + */ + val declaration: UExpression? + + /** + * Returns the loop condition, or null if the condition is empty. + */ + val condition: UExpression? + + /** + * Returns the loop update expression(s). + */ + val update: UExpression? + + /** + * Returns the identifier for the 'for' keyword. + */ + val forIdentifier: UIdentifier + + override fun accept(visitor: UastVisitor) { + if (visitor.visitForExpression(this)) return + annotations.acceptList(visitor) + declaration?.accept(visitor) + condition?.accept(visitor) + update?.accept(visitor) + body.accept(visitor) + visitor.afterVisitForExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitForExpression(this, data) + + override fun asRenderString() = buildString { + append("for (") + declaration?.let { append(it.asRenderString()) } + append("; ") + condition?.let { append(it.asRenderString()) } + append("; ") + update?.let { append(it.asRenderString()) } + append(") ") + append(body.asRenderString()) + } + + override fun asLogString() = log() +} diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/UIfExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UIfExpression.kt new file mode 100644 index 000000000000..94a819be78e5 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UIfExpression.kt @@ -0,0 +1,101 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents + * + * `if (condition) { + * // do if true + * } else { + * // do if false + * }` + * + * and + * + * `condition : trueExpression ? falseExpression` + * + * condition expressions. + */ +interface UIfExpression : UExpression { + /** + * Returns the condition expression. + */ + val condition: UExpression + + /** + * Returns the expression which is executed if the condition is true, or null if the expression is empty. + */ + val thenExpression: UExpression? + + /** + * Returns the expression which is executed if the condition is false, or null if the expression is empty. + */ + val elseExpression: UExpression? + + /** + * Returns true if the expression is ternary (condition ? trueExpression : falseExpression). + */ + val isTernary: Boolean + + /** + * Returns an identifier for the 'if' keyword. + */ + val ifIdentifier: UIdentifier + + /** + * Returns an identifier for the 'else' keyword, or null if the conditional expression has not the 'else' part. + */ + val elseIdentifier: UIdentifier? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitIfExpression(this)) return + annotations.acceptList(visitor) + condition.accept(visitor) + thenExpression?.accept(visitor) + elseExpression?.accept(visitor) + visitor.afterVisitIfExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitIfExpression(this, data) + + override fun asLogString() = log() + + override fun asRenderString() = buildString { + if (isTernary) { + append("(" + condition.asRenderString() + ")") + append(" ? ") + append("(" + (thenExpression?.asRenderString() ?: "") + ")") + append(" : ") + append("(" + (elseExpression?.asRenderString() ?: "") + ")") + } else { + append("if (${condition.asRenderString()}) ") + thenExpression?.let { append(it.asRenderString()) } + val elseBranch = elseExpression + if (elseBranch != null && elseBranch !is UastEmptyExpression) { + if (thenExpression !is UBlockExpression) append(" ") + append("else ") + append(elseBranch.asRenderString()) + } + } + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/ULoopExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/ULoopExpression.kt new file mode 100644 index 000000000000..926799aa6be8 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/ULoopExpression.kt @@ -0,0 +1,30 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor + +/** + * Represents a loop expression. + */ +interface ULoopExpression : UExpression { + /** + * Returns the loop body [UExpression]. + */ + val body: UExpression + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitLoopExpression(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/USwitchExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/USwitchExpression.kt new file mode 100644 index 000000000000..4a3da8ea6351 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/USwitchExpression.kt @@ -0,0 +1,122 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a + * + * ` switch (expression) { + * case value1 -> expr1 + * case value2 -> expr2 + * ... + * else -> exprElse + * } + * + * conditional expression. + */ +interface USwitchExpression : UExpression { + /** + Returns the expression on which the `switch` expression is performed. + */ + val expression: UExpression? + + /** + Returns the switch body. + The body should contain [USwitchClauseExpression] expressions. + */ + val body: UExpressionList + + /** + * Returns an identifier for the 'switch' ('case', 'when', ...) keyword. + */ + val switchIdentifier: UIdentifier + + override fun accept(visitor: UastVisitor) { + if (visitor.visitSwitchExpression(this)) return + annotations.acceptList(visitor) + expression?.accept(visitor) + body.accept(visitor) + visitor.afterVisitSwitchExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitSwitchExpression(this, data) + + override fun asLogString() = log() + + override fun asRenderString() = buildString { + val expr = expression?.let { "(" + it.asRenderString() + ") " } ?: "" + appendln("switch $expr") + appendln(body.asRenderString()) + } +} + +/** + * Represents a [USwitchExpression] clause. + * [USwitchClauseExpression] does not contain the clause body, + * and the actual body expression should be the next element in the parent expression list. + */ +interface USwitchClauseExpression : UExpression { + /** + * Returns the list of values for this clause, or null if the are no values for this close + * (for example, for the `else` clause). + */ + val caseValues: List + + override fun accept(visitor: UastVisitor) { + if (visitor.visitSwitchClauseExpression(this)) return + annotations.acceptList(visitor) + caseValues.acceptList(visitor) + visitor.afterVisitSwitchClauseExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitSwitchClauseExpression(this, data) + + override fun asRenderString() = caseValues.joinToString { it.asRenderString() } + " -> " + + override fun asLogString() = "USwitchClauseExpression" +} + +/** + * Represents a [USwitchExpression] clause with the body. + * [USwitchClauseExpressionWithBody], comparing with [USwitchClauseExpression], contains the body expression. + * + * Implementing this interface *is the right way* to support `switch` clauses in your language. + */ +interface USwitchClauseExpressionWithBody : USwitchClauseExpression { + /** + * Returns the body expression for this clause. + */ + val body: UExpressionList + + override fun accept(visitor: UastVisitor) { + if (visitor.visitSwitchClauseExpression(this)) return + annotations.acceptList(visitor) + caseValues.acceptList(visitor) + body.accept(visitor) + visitor.afterVisitSwitchClauseExpression(this) + } + + override fun asRenderString() = caseValues.joinToString { it.asRenderString() } + " -> " + body.asRenderString() + + override fun asLogString() = log() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/UTryExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UTryExpression.kt new file mode 100644 index 000000000000..617ddc34504f --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UTryExpression.kt @@ -0,0 +1,145 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiType +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents + * + * `try { + * // tryClause body + * } catch (e: Type1, Type2 ... TypeN) { + * // catchClause1 body + * } ... { + * finally { + * //finallyBody + * }` + * + * and + * + * `try (resource1, ..., resourceN) { + * // tryClause body + * }` + * + * expressions. + */ +interface UTryExpression : UExpression { + /** + * Returns `true` if the try expression is a try-with-resources expression. + */ + val hasResources: Boolean + + /** + * Returns the list of resource variables declared in this expression, or an empty list if this expression is not a `try-with-resources` expression. + */ + val resourceVariables: List + + /** + * Returns the `try` clause expression. + */ + val tryClause: UExpression + + /** + * Returns the `catch` clauses [UCatchClause] expression list. + */ + val catchClauses: List + + /** + * Returns the `finally` clause expression, or null if the `finally` clause is absent. + */ + val finallyClause: UExpression? + + /** + * Returns an identifier for the 'try' keyword. + */ + val tryIdentifier: UIdentifier + + /** + * Returns an identifier for the 'finally' keyword, or null if the 'try' expression has not a 'finally' clause. + */ + val finallyIdentifier: UIdentifier? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitTryExpression(this)) return + annotations.acceptList(visitor) + resourceVariables.acceptList(visitor) + tryClause.accept(visitor) + catchClauses.acceptList(visitor) + finallyClause?.accept(visitor) + visitor.afterVisitTryExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitTryExpression(this, data) + + override fun asRenderString() = buildString { + append("try ") + if (hasResources) { + append("(") + append(resourceVariables.joinToString("\n") { it.asRenderString() }) + append(")") + } + appendln(tryClause.asRenderString().trim('\n', '\r')) + catchClauses.forEach { appendln(it.asRenderString().trim('\n', '\r')) } + finallyClause?.let { append("finally ").append(it.asRenderString().trim('\n', '\r')) } + } + + override fun asLogString() = log(if (hasResources) "with resources" else "") +} + +/** + * Represents the `catch` clause in [UTryExpression]. + */ +interface UCatchClause : UElement { + /** + * Returns the `catch` clause body expression. + */ + val body: UExpression + + /** + * Returns the exception parameter variables for this `catch` clause. + */ + val parameters: List + + /** + * Returns the exception type references for this `catch` clause. + */ + val typeReferences: List + + /** + * Returns the expression types for this `catch` clause. + */ + val types: List + get() = typeReferences.map { it.type } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitCatchClause(this)) return + body.accept(visitor) + visitor.afterVisitCatchClause(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitCatchClause(this, data) + + override fun asLogString() = log(parameters.joinToString { it.name ?: "" }) + + override fun asRenderString() = "catch (e) " + body.asRenderString() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/controlStructures/UWhileExpression.kt b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UWhileExpression.kt new file mode 100644 index 000000000000..db1e0e59e88e --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/controlStructures/UWhileExpression.kt @@ -0,0 +1,60 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a + * + * `while (condition) { + * // body + * }` + * + * expression. + */ +interface UWhileExpression : ULoopExpression { + /** + * Returns the loop condition. + */ + val condition: UExpression + + /** + * Returns an identifier for the 'while' keyword. + */ + val whileIdentifier: UIdentifier + + override fun accept(visitor: UastVisitor) { + if (visitor.visitWhileExpression(this)) return + annotations.acceptList(visitor) + condition.accept(visitor) + body.accept(visitor) + visitor.afterVisitWhileExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitWhileExpression(this, data) + + override fun asRenderString() = buildString { + append("while (${condition.asRenderString()}) ") + append(body.asRenderString()) + } + + override fun asLogString() = log() +} diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UAnnotation.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UAnnotation.kt new file mode 100644 index 000000000000..48a624c1a62f --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UAnnotation.kt @@ -0,0 +1,69 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiClass +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * An annotation wrapper to be used in [UastVisitor]. + */ +interface UAnnotation : UElement, UResolvable { + /** + * Returns the annotation qualified name. + */ + val qualifiedName: String? + + /** + * Returns the annotation class, or null if the class reference was not resolved. + */ + override fun resolve(): PsiClass? + + /** + * Returns the annotation values. + */ + val attributeValues: List + + fun findAttributeValue(name: String?): UExpression? + + fun findDeclaredAttributeValue(name: String?): UExpression? + + override fun asRenderString() = buildString { + append("@") + append(qualifiedName) + if(attributeValues.isNotEmpty()) { + attributeValues.joinTo( + buffer = this, + prefix = "(", + postfix = ")", + transform = UNamedExpression::asRenderString) + } + } + + override fun asLogString() = log("fqName = $qualifiedName") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitAnnotation(this)) return + attributeValues.acceptList(visitor) + visitor.afterVisitAnnotation(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitAnnotation(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UClass.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UClass.kt new file mode 100644 index 000000000000..fb47f0c178af --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UClass.kt @@ -0,0 +1,94 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiAnonymousClass +import com.intellij.psi.PsiClass +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * A class wrapper to be used in [UastVisitor]. + */ +interface UClass : UDeclaration, PsiClass { + override val psi: PsiClass + + /** + * Returns a [UClass] wrapper of the superclass of this class, or null if this class is [java.lang.Object]. + */ + override fun getSuperClass(): UClass? { + val superClass = psi.superClass ?: return null + return getUastContext().convertWithParent(superClass) + } + + val uastSuperTypes: List + + /** + * Returns [UDeclaration] wrappers for the class declarations. + */ + val uastDeclarations: List + + override fun getFields(): Array = + psi.fields.map { getLanguagePlugin().convert(it, this) }.toTypedArray() + + override fun getInitializers(): Array = + psi.initializers.map { getLanguagePlugin().convert(it, this) }.toTypedArray() + + override fun getMethods(): Array = + psi.methods.map { getLanguagePlugin().convert(it, this) }.toTypedArray() + + override fun getInnerClasses(): Array = + psi.innerClasses.map { getLanguagePlugin().convert(it, this) }.toTypedArray() + + override fun asLogString() = log("name = $name") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitClass(this)) return + annotations.acceptList(visitor) + uastDeclarations.acceptList(visitor) + visitor.afterVisitClass(this) + } + + override fun asRenderString() = buildString { + append(psi.renderModifiers()) + val kind = when { + psi.isAnnotationType -> "annotation" + psi.isInterface -> "interface" + psi.isEnum -> "enum" + else -> "class" + } + append(kind).append(' ').append(psi.name) + val superTypes = uastSuperTypes + if (superTypes.isNotEmpty()) { + append(" : ") + append(superTypes.joinToString { it.asRenderString() }) + } + appendln(" {") + uastDeclarations.forEachIndexed { index, declaration -> + appendln(declaration.asRenderString().withMargin) + } + append("}") + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitClass(this, data) +} + +interface UAnonymousClass : UClass, PsiAnonymousClass { + override val psi: PsiAnonymousClass +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UClassInitializer.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UClassInitializer.kt new file mode 100644 index 000000000000..f50a44b519db --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UClassInitializer.kt @@ -0,0 +1,55 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiClassInitializer + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * A class initializer wrapper to be used in [UastVisitor]. + */ +interface UClassInitializer : UDeclaration, PsiClassInitializer { + override val psi: PsiClassInitializer + + /** + * Returns the body of this class initializer. + */ + val uastBody: UExpression + + @Deprecated("Use uastBody instead.", ReplaceWith("uastBody")) + override fun getBody() = psi.body + + override fun accept(visitor: UastVisitor) { + if (visitor.visitInitializer(this)) return + annotations.acceptList(visitor) + uastBody.accept(visitor) + visitor.afterVisitInitializer(this) + } + + override fun asRenderString() = buildString { + append(modifierList) + appendln(uastBody.asRenderString().withMargin) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitClassInitializer(this, data) + + override fun asLogString() = log("isStatic = $isStatic") +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt new file mode 100644 index 000000000000..2d94b2719440 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt @@ -0,0 +1,60 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiModifierListOwner +import org.jetbrains.uast.visitor.UastTypedVisitor + +/** + * A [PsiElement] declaration wrapper. + */ +interface UDeclaration : UElement, PsiModifierListOwner, UAnnotated { + /** + * Returns the original declaration (which is *always* unwrapped, never a [UDeclaration]). + */ + override val psi: PsiModifierListOwner + + override fun getOriginalElement(): PsiElement? = psi.originalElement + + /** + * Returns the declaration name identifier, or null if the declaration is anonymous. + */ + val uastAnchor: UElement? + + /** + * Returns `true` if this declaration has a [PsiModifier.STATIC] modifier. + */ + val isStatic: Boolean + get() = hasModifierProperty(PsiModifier.STATIC) + + /** + * Returns `true` if this declaration has a [PsiModifier.FINAL] modifier. + */ + val isFinal: Boolean + get() = hasModifierProperty(PsiModifier.FINAL) + + /** + * Returns a declaration visibility. + */ + val visibility: UastVisibility + get() = UastVisibility[this] + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitDeclaration(this, data) +} + +fun UElement.getContainingDeclaration() = withContainingElements.filterIsInstance().firstOrNull() diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UFile.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UFile.kt new file mode 100644 index 000000000000..a9cfb5367c2f --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UFile.kt @@ -0,0 +1,94 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiFile +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a Uast file. + */ +interface UFile : UElement, UAnnotated { + /** + * Returns the original [PsiFile]. + */ + override val psi: PsiFile + + /** + * Returns the Java package name of this file. + * Returns an empty [String] for the default package. + */ + val packageName: String + + /** + * Returns the import statements for this file. + */ + val imports: List + + /** + * Returns the list of top-level classes declared in this file. + */ + val classes: List + + /** + * Returns the plugin for a language used in this file. + */ + val languagePlugin: UastLanguagePlugin + + /** + * Returns all comments in file. + */ + val allCommentsInFile: List + + override fun asLogString() = log("package = $packageName") + + override fun asRenderString() = buildString { + val packageName = this@UFile.packageName + if (packageName.isNotEmpty()) appendln("package $packageName").appendln() + + val imports = this@UFile.imports + if (imports.isNotEmpty()) { + imports.forEach { appendln(it.asRenderString()) } + appendln() + } + + classes.forEachIndexed { index, clazz -> + if (index > 0) appendln() + appendln(clazz.asRenderString()) + } + } + + /** + * [UFile] is a top-level element of the Uast hierarchy, thus the [uastParent] always returns null for it. + */ + override val uastParent: UElement? + get() = null + + override fun accept(visitor: UastVisitor) { + if (visitor.visitFile(this)) return + annotations.acceptList(visitor) + imports.acceptList(visitor) + classes.acceptList(visitor) + visitor.afterVisitFile(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitFile(this, data) +} + diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UImportStatement.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UImportStatement.kt new file mode 100644 index 000000000000..8539e029fa8c --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UImportStatement.kt @@ -0,0 +1,47 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents an import statement. + */ +interface UImportStatement : UResolvable, UElement { + /** + * Returns true if the statement is an import-on-demand (star-import) statement. + */ + val isOnDemand: Boolean + + /** + * Returns the reference to the imported element. + */ + val importReference: UElement? + + override fun asLogString() = log("isOnDemand = $isOnDemand") + + override fun asRenderString() = "import " + (importReference?.asRenderString() ?: "") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitImportStatement(this)) return + visitor.afterVisitImportStatement(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitImportStatement(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UMethod.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UMethod.kt new file mode 100644 index 000000000000..d1cb5125b5ca --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UMethod.kt @@ -0,0 +1,104 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiAnnotationMethod +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * A method visitor to be used in [UastVisitor]. + */ +interface UMethod : UDeclaration, PsiMethod { + override val psi: PsiMethod + + /** + * Returns the body expression (which can be also a [UBlockExpression]). + */ + val uastBody: UExpression? + + /** + * Returns the method parameters. + */ + val uastParameters: List + + /** + * Returns true, if the method overrides a method of a super class. + */ + val isOverride: Boolean + + @Deprecated("Use uastBody instead.", ReplaceWith("uastBody")) + override fun getBody() = psi.body + + override fun accept(visitor: UastVisitor) { + if (visitor.visitMethod(this)) return + annotations.acceptList(visitor) + uastParameters.acceptList(visitor) + uastBody?.accept(visitor) + visitor.afterVisitMethod(this) + } + + override fun asRenderString() = buildString { + if (annotations.isNotEmpty()) { + annotations.joinTo(buffer = this, separator = "\n", postfix = "\n", transform = UAnnotation::asRenderString) + } + + append(psi.renderModifiers()) + append("fun ").append(name) + + uastParameters.joinTo(this, prefix = "(", postfix = ")") { + it.name + ": " + it.type.canonicalText + } + + psi.returnType?.let { append(" : " + it.canonicalText) } + + val body = uastBody + append(when (body) { + is UBlockExpression -> " " + body.asRenderString() + else -> " = " + ((body ?: UastEmptyExpression).asRenderString()) + }) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitMethod(this, data) + + override fun asLogString() = log("name = $name") +} + +interface UAnnotationMethod : UMethod, PsiAnnotationMethod { + override val psi: PsiAnnotationMethod + + /** + * Returns the default value of this annotation method. + */ + val uastDefaultValue: UExpression? + + override fun getDefaultValue() = psi.defaultValue + + override fun accept(visitor: UastVisitor) { + if (visitor.visitMethod(this)) return + annotations.acceptList(visitor) + uastParameters.acceptList(visitor) + uastBody?.accept(visitor) + uastDefaultValue?.accept(visitor) + visitor.afterVisitMethod(this) + } + + override fun asLogString() = log("name = $name") +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UVariable.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UVariable.kt new file mode 100644 index 000000000000..2fb65dc0cc6e --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UVariable.kt @@ -0,0 +1,141 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.* +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * A variable wrapper to be used in [UastVisitor]. + */ +interface UVariable : UDeclaration, PsiVariable { + override val psi: PsiVariable + + /** + * Returns the variable initializer or the parameter default value, or null if the variable has not an initializer. + */ + val uastInitializer: UExpression? + + /** + * Returns variable type reference. + */ + val typeReference: UTypeReferenceExpression? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitVariable(this)) return + visitContents(visitor) + visitor.afterVisitVariable(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitVariable(this, data) + + @Deprecated("Use uastInitializer instead.", ReplaceWith("uastInitializer")) + override fun getInitializer() = psi.initializer + + override fun asLogString() = log("name = $name") + + override fun asRenderString() = buildString { + append(psi.renderModifiers()) + append("var ").append(psi.name).append(": ").append(psi.type.getCanonicalText(false)) + uastInitializer?.let { initializer -> append(" = " + initializer.asRenderString()) } + } +} + +private fun UVariable.visitContents(visitor: UastVisitor) { + annotations.acceptList(visitor) + uastInitializer?.accept(visitor) +} + +interface UParameter : UVariable, PsiParameter { + override val psi: PsiParameter + + override fun asLogString() = log("name = $name") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitParameter(this)) return + visitContents(visitor) + visitor.afterVisitParameter(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitParameter(this, data) +} + +interface UField : UVariable, PsiField { + override val psi: PsiField + + override fun asLogString() = log("name = $name") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitField(this)) return + visitContents(visitor) + visitor.afterVisitField(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitField(this, data) +} + +interface ULocalVariable : UVariable, PsiLocalVariable { + override val psi: PsiLocalVariable + + override fun asLogString() = log("name = $name") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitLocalVariable(this)) return + visitContents(visitor) + visitor.afterVisitLocalVariable(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitLocalVariable(this, data) +} + +interface UEnumConstant : UField, UCallExpression, PsiEnumConstant { + override val psi: PsiEnumConstant + + val initializingClass: UClass? + + override fun asLogString() = log("name = $name") + + override fun accept(visitor: UastVisitor) { + if (visitor.visitEnumConstant(this)) return + annotations.acceptList(visitor) + methodIdentifier?.accept(visitor) + classReference?.accept(visitor) + valueArguments.acceptList(visitor) + initializingClass?.accept(visitor) + visitor.afterVisitEnumConstant(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitEnumConstantExpression(this, data) + + override fun asRenderString() = buildString { + append(name ?: "") + if (valueArguments.isNotEmpty()) { + valueArguments.joinTo(this, prefix = "(", postfix = ")", transform = UExpression::asRenderString) + } + initializingClass?.let { + appendln(" {") + it.uastDeclarations.forEachIndexed { index, declaration -> + appendln(declaration.asRenderString().withMargin) + } + append("}") + } + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluationState.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluationState.kt new file mode 100644 index 000000000000..99aeb3290b9c --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluationState.kt @@ -0,0 +1,51 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UVariable +import org.jetbrains.uast.values.UValue +import org.jetbrains.uast.values.UVariableValue + +abstract class AbstractEvaluationState(override val boundElement: UElement? = null) : UEvaluationState { + override fun assign(variable: UVariable, value: UValue, at: UElement): AbstractEvaluationState { + val variableValue = UVariableValue.create(variable, value) + val prevVariableValue = this[variable] + return if (prevVariableValue == variableValue) this + else DelegatingEvaluationState( + boundElement = at, + variableValue = variableValue, + baseState = this + ) + } + + override fun merge(otherState: UEvaluationState) = + if (this == otherState) this else MergingEvaluationState(this, otherState) + + override fun equals(other: Any?) = + other is UEvaluationState && variables == other.variables && variables.all { this[it] == other[it] } + + override fun hashCode(): Int { + var result = 31 + result = result * 19 + variables.hashCode() + result = result * 19 + variables.map { this[it].hashCode() }.sum() + return result + } + + override fun toString() = variables.joinToString(prefix = "[", postfix = "]", separator = ", ") { + "${it.psi.name} = ${this[it]}" + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluatorExtension.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluatorExtension.kt new file mode 100644 index 000000000000..a3775e4ea5cb --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/AbstractEvaluatorExtension.kt @@ -0,0 +1,112 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import com.intellij.lang.Language +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.* +import org.jetbrains.uast.values.UUndeterminedValue +import org.jetbrains.uast.values.UValue + +abstract class AbstractEvaluatorExtension(override val language: Language) : UEvaluatorExtension { + override fun evaluatePostfix( + operator: UastPostfixOperator, + operandValue: UValue, + state: UEvaluationState + ): UEvaluationInfo = UUndeterminedValue to state + + override fun evaluatePrefix( + operator: UastPrefixOperator, + operandValue: UValue, + state: UEvaluationState + ): UEvaluationInfo = UUndeterminedValue to state + + override fun evaluateBinary( + binaryExpression: UBinaryExpression, + leftValue: UValue, + rightValue: UValue, + state: UEvaluationState + ): UEvaluationInfo = UUndeterminedValue to state + + override fun evaluateQualified( + accessType: UastQualifiedExpressionAccessType, + receiverInfo: UEvaluationInfo, + selectorInfo: UEvaluationInfo + ): UEvaluationInfo = UUndeterminedValue to selectorInfo.state + + override fun evaluateMethodCall( + target: PsiMethod, + argumentValues: List, + state: UEvaluationState + ): UEvaluationInfo = UUndeterminedValue to state + + override fun evaluateVariable( + variable: UVariable, + state: UEvaluationState + ): UEvaluationInfo = UUndeterminedValue to state +} + +abstract class SimpleEvaluatorExtension : AbstractEvaluatorExtension(Language.ANY) { + override final fun evaluatePostfix(operator: UastPostfixOperator, operandValue: UValue, state: UEvaluationState): UEvaluationInfo { + val result = evaluatePostfix(operator, operandValue) + return if (result != UUndeterminedValue) + result.toConstant() to state + else + super.evaluatePostfix(operator, operandValue, state) + } + + open fun evaluatePostfix(operator: UastPostfixOperator, operandValue: UValue): Any? = UUndeterminedValue + + override final fun evaluatePrefix(operator: UastPrefixOperator, operandValue: UValue, state: UEvaluationState): UEvaluationInfo { + val result = evaluatePrefix(operator, operandValue) + return if (result != UUndeterminedValue) + result.toConstant() to state + else + super.evaluatePrefix(operator, operandValue, state) + } + + open fun evaluatePrefix(operator: UastPrefixOperator, operandValue: UValue): Any? = UUndeterminedValue + + override final fun evaluateBinary(binaryExpression: UBinaryExpression, leftValue: UValue, rightValue: UValue, state: UEvaluationState): UEvaluationInfo { + val result = evaluateBinary(binaryExpression, leftValue, rightValue) + return if (result != UUndeterminedValue) + result.toConstant() to state + else + super.evaluateBinary(binaryExpression, leftValue, rightValue, state) + } + + open fun evaluateBinary(binaryExpression: UBinaryExpression, leftValue: UValue, rightValue: UValue): Any? = UUndeterminedValue + + override final fun evaluateMethodCall(target: PsiMethod, argumentValues: List, state: UEvaluationState): UEvaluationInfo { + val result = evaluateMethodCall(target, argumentValues) + return if (result != UUndeterminedValue) + result.toConstant() to state + else + super.evaluateMethodCall(target, argumentValues, state) + } + + open fun evaluateMethodCall(target: PsiMethod, argumentValues: List): Any? = UUndeterminedValue + + override final fun evaluateVariable(variable: UVariable, state: UEvaluationState): UEvaluationInfo { + val result = evaluateVariable(variable) + return if (result != UUndeterminedValue) + result.toConstant() to state + else + super.evaluateVariable(variable, state) + } + + open fun evaluateVariable(variable: UVariable): Any? = UUndeterminedValue +} diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/DelegatingEvaluationState.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/DelegatingEvaluationState.kt new file mode 100644 index 000000000000..fbdf117768cf --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/DelegatingEvaluationState.kt @@ -0,0 +1,32 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UVariable +import org.jetbrains.uast.values.UVariableValue + +class DelegatingEvaluationState( + boundElement: UElement, + private val variableValue: UVariableValue, + private val baseState: UEvaluationState +) : AbstractEvaluationState(boundElement) { + + override val variables = baseState.variables + variableValue.variable + + override fun get(variable: UVariable) = + if (variable == variableValue.variable) variableValue else baseState[variable] +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/EmptyEvaluationState.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/EmptyEvaluationState.kt new file mode 100644 index 000000000000..89417f3658ed --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/EmptyEvaluationState.kt @@ -0,0 +1,27 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UVariable +import org.jetbrains.uast.values.UUndeterminedValue + +class EmptyEvaluationState(boundElement: UElement) : AbstractEvaluationState(boundElement) { + override val variables: Set + get() = emptySet() + + override fun get(variable: UVariable) = UUndeterminedValue +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/MapBasedEvaluationContext.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/MapBasedEvaluationContext.kt new file mode 100644 index 000000000000..3a7f65bc23c8 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/MapBasedEvaluationContext.kt @@ -0,0 +1,79 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.* +import org.jetbrains.uast.values.UUndeterminedValue +import org.jetbrains.uast.visitor.UastVisitor +import java.lang.ref.SoftReference +import java.util.* + +class MapBasedEvaluationContext( + override val uastContext: UastContext, + override val extensions: List +) : UEvaluationContext { + private val evaluators = WeakHashMap>() + + override fun analyzeAll(file: UFile, state: UEvaluationState): UEvaluationContext { + file.accept(object: UastVisitor { + override fun visitElement(node: UElement) = false + + override fun visitMethod(node: UMethod): Boolean { + analyze(node, state) + return true + } + + override fun visitVariable(node: UVariable): Boolean { + if (node is UField) { + analyze(node, state) + return true + } + else return false + } + }) + return this + } + + private fun getOrCreateEvaluator(declaration: UDeclaration, state: UEvaluationState? = null) = + evaluators[declaration]?.get() ?: createEvaluator(uastContext, extensions).apply { + when (declaration) { + is UMethod -> this.analyze(declaration, state ?: declaration.createEmptyState()) + is UField -> this.analyze(declaration, state ?: declaration.createEmptyState()) + } + evaluators[declaration] = SoftReference(this) + } + + override fun analyze(declaration: UDeclaration, state: UEvaluationState) = getOrCreateEvaluator(declaration, state) + + override fun getEvaluator(declaration: UDeclaration) = getOrCreateEvaluator(declaration) + + private fun getEvaluator(expression: UExpression): UEvaluator? { + var containingElement = expression.uastParent + while (containingElement != null) { + if (containingElement is UDeclaration) { + val evaluator = evaluators[containingElement]?.get() + if (evaluator != null) { + return evaluator + } + } + containingElement = containingElement.uastParent + } + return null + } + + override fun valueOf(expression: UExpression) = + getEvaluator(expression)?.evaluate(expression) ?: UUndeterminedValue +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/MergingEvaluationState.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/MergingEvaluationState.kt new file mode 100644 index 000000000000..71da9b46cf2e --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/MergingEvaluationState.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.UVariable + +class MergingEvaluationState( + private val first: UEvaluationState, + private val second: UEvaluationState +) : AbstractEvaluationState() { + + override val variables = first.variables + second.variables + + override fun get(variable: UVariable) = first[variable].merge(second[variable]) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/TreeBasedEvaluator.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/TreeBasedEvaluator.kt new file mode 100644 index 000000000000..e7682a6abb34 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/TreeBasedEvaluator.kt @@ -0,0 +1,652 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiType +import com.intellij.psi.PsiVariable +import org.jetbrains.uast.* +import org.jetbrains.uast.values.* +import org.jetbrains.uast.values.UNothingValue.JumpKind.BREAK +import org.jetbrains.uast.values.UNothingValue.JumpKind.CONTINUE +import org.jetbrains.uast.visitor.UastTypedVisitor + +class TreeBasedEvaluator( + override val context: UastContext, + val extensions: List +) : UastTypedVisitor, UEvaluator { + + override fun getDependents(dependency: UDependency): Set { + return resultCache.values.map { it.value }.filter { dependency in it.dependencies }.toSet() + } + + private val inputStateCache = mutableMapOf() + + private val resultCache = mutableMapOf() + + override fun visitElement(node: UElement, data: UEvaluationState): UEvaluationInfo { + return UEvaluationInfo(UUndeterminedValue, data).apply { + if (node is UExpression) { + this storeResultFor node + } + } + } + + override fun analyze(method: UMethod, state: UEvaluationState) { + method.uastBody?.accept(this, state) + } + + override fun analyze(field: UField, state: UEvaluationState) { + field.uastInitializer?.accept(this, state) + } + + override fun evaluate(expression: UExpression, state: UEvaluationState?): UValue { + if (state == null) { + val result = resultCache[expression] + if (result != null) return result.value + } + val inputState = state ?: inputStateCache[expression] ?: expression.createEmptyState() + return expression.accept(this, inputState).value + } + + // ----------------------- // + + private infix fun UValue.to(state: UEvaluationState) = UEvaluationInfo(this, state) + + private infix fun UEvaluationInfo.storeResultFor(expression: UExpression) = apply { + resultCache[expression] = this + } + + override fun visitLiteralExpression(node: ULiteralExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val value = node.value + return value.toConstant(node) to data storeResultFor node + } + + override fun visitClassLiteralExpression(node: UClassLiteralExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return (node.type?.let { value -> UClassConstant(value, node) } ?: UUndeterminedValue) to data storeResultFor node + } + + override fun visitReturnExpression(node: UReturnExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val argument = node.returnExpression + return UValue.UNREACHABLE to (argument?.accept(this, data)?.state ?: data) storeResultFor node + } + + override fun visitBreakExpression(node: UBreakExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return UNothingValue(node) to data storeResultFor node + } + override fun visitContinueExpression(node: UContinueExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return UNothingValue(node) to data storeResultFor node + } + + override fun visitThrowExpression(node: UThrowExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return UValue.UNREACHABLE to data storeResultFor node + } + // ----------------------- // + + override fun visitSimpleNameReferenceExpression( + node: USimpleNameReferenceExpression, + data: UEvaluationState + ): UEvaluationInfo { + inputStateCache[node] = data + val resolvedElement = node.resolveToUElement() + return when (resolvedElement) { + is UEnumConstant -> UEnumEntryValueConstant(resolvedElement, node) + is UField -> if (resolvedElement.hasModifierProperty(PsiModifier.FINAL)) { + data[resolvedElement].ifUndetermined { + val helper = JavaPsiFacade.getInstance(resolvedElement.project).constantEvaluationHelper + val evaluated = helper.computeConstantExpression(resolvedElement.initializer) + evaluated?.toConstant() ?: UUndeterminedValue + } + } + else { + return super.visitSimpleNameReferenceExpression(node, data) + } + is UVariable -> data[resolvedElement].ifUndetermined { + node.evaluateViaExtensions { evaluateVariable(resolvedElement, data) }?.value ?: UUndeterminedValue + } + else -> return super.visitSimpleNameReferenceExpression(node, data) + } to data storeResultFor node + } + + override fun visitReferenceExpression( + node: UReferenceExpression, + data: UEvaluationState + ): UEvaluationInfo { + inputStateCache[node] = data + return UCallResultValue(node, emptyList()) to data storeResultFor node + } + + // ----------------------- // + + private fun UExpression.assign( + valueInfo: UEvaluationInfo, + operator: UastBinaryOperator.AssignOperator = UastBinaryOperator.ASSIGN + ): UEvaluationInfo { + this.accept(this@TreeBasedEvaluator, valueInfo.state) + if (this is UResolvable) { + val resolvedElement = resolve() + if (resolvedElement is PsiVariable) { + val variable = context.getVariable(resolvedElement) + val currentValue = valueInfo.state[variable] + val result = when (operator) { + UastBinaryOperator.ASSIGN -> valueInfo.value + UastBinaryOperator.PLUS_ASSIGN -> currentValue + valueInfo.value + UastBinaryOperator.MINUS_ASSIGN -> currentValue - valueInfo.value + UastBinaryOperator.MULTIPLY_ASSIGN -> currentValue * valueInfo.value + UastBinaryOperator.DIVIDE_ASSIGN -> currentValue / valueInfo.value + UastBinaryOperator.REMAINDER_ASSIGN -> currentValue % valueInfo.value + UastBinaryOperator.AND_ASSIGN -> currentValue bitwiseAnd valueInfo.value + UastBinaryOperator.OR_ASSIGN -> currentValue bitwiseOr valueInfo.value + UastBinaryOperator.XOR_ASSIGN -> currentValue bitwiseXor valueInfo.value + UastBinaryOperator.SHIFT_LEFT_ASSIGN -> currentValue shl valueInfo.value + UastBinaryOperator.SHIFT_RIGHT_ASSIGN -> currentValue shr valueInfo.value + UastBinaryOperator.UNSIGNED_SHIFT_RIGHT_ASSIGN -> currentValue ushr valueInfo.value + else -> UUndeterminedValue + } + return result to valueInfo.state.assign(variable, result, this) + } + } + return UUndeterminedValue to valueInfo.state + } + + private fun UExpression.assign( + operator: UastBinaryOperator.AssignOperator, + value: UExpression, + data: UEvaluationState + ) = assign(value.accept(this@TreeBasedEvaluator, data), operator) + + override fun visitPrefixExpression(node: UPrefixExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val operandInfo = node.operand.accept(this, data) + val operandValue = operandInfo.value + if (!operandValue.reachable) return operandInfo storeResultFor node + return when (node.operator) { + UastPrefixOperator.UNARY_PLUS -> operandValue + UastPrefixOperator.UNARY_MINUS -> -operandValue + UastPrefixOperator.LOGICAL_NOT -> !operandValue + UastPrefixOperator.INC -> { + val resultValue = operandValue.inc() + val newState = node.operand.assign(resultValue to operandInfo.state).state + return resultValue to newState storeResultFor node + } + UastPrefixOperator.DEC -> { + val resultValue = operandValue.dec() + val newState = node.operand.assign(resultValue to operandInfo.state).state + return resultValue to newState storeResultFor node + } + else -> { + return node.evaluateViaExtensions { evaluatePrefix(node.operator, operandValue, operandInfo.state) } + ?: UUndeterminedValue to operandInfo.state storeResultFor node + } + } to operandInfo.state storeResultFor node + } + + inline fun UElement.evaluateViaExtensions(block: UEvaluatorExtension.() -> UEvaluationInfo): UEvaluationInfo? { + for (ext in extensions) { + val extResult = ext.block() + if (extResult.value != UUndeterminedValue) return extResult + } + languageExtension()?.block()?.let { if (it.value != UUndeterminedValue) return it } + return null + } + + override fun visitPostfixExpression(node: UPostfixExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val operandInfo = node.operand.accept(this, data) + val operandValue = operandInfo.value + if (!operandValue.reachable) return operandInfo storeResultFor node + return when (node.operator) { + UastPostfixOperator.INC -> { + operandValue to node.operand.assign(operandValue.inc() to operandInfo.state).state + } + UastPostfixOperator.DEC -> { + operandValue to node.operand.assign(operandValue.dec() to operandInfo.state).state + } + else -> { + return node.evaluateViaExtensions { evaluatePostfix(node.operator, operandValue, operandInfo.state) } + ?: UUndeterminedValue to operandInfo.state storeResultFor node + } + } storeResultFor node + } + + private fun UastBinaryOperator.evaluate(left: UValue, right: UValue): UValue? = + when (this) { + UastBinaryOperator.PLUS -> left + right + UastBinaryOperator.MINUS -> left - right + UastBinaryOperator.MULTIPLY -> left * right + UastBinaryOperator.DIV -> left / right + UastBinaryOperator.MOD -> left % right + UastBinaryOperator.EQUALS -> left valueEquals right + UastBinaryOperator.NOT_EQUALS -> left valueNotEquals right + UastBinaryOperator.IDENTITY_EQUALS -> left identityEquals right + UastBinaryOperator.IDENTITY_NOT_EQUALS -> left identityNotEquals right + UastBinaryOperator.GREATER -> left greater right + UastBinaryOperator.LESS -> left less right + UastBinaryOperator.GREATER_OR_EQUALS -> left greaterOrEquals right + UastBinaryOperator.LESS_OR_EQUALS -> left lessOrEquals right + UastBinaryOperator.LOGICAL_AND -> left and right + UastBinaryOperator.LOGICAL_OR -> left or right + UastBinaryOperator.BITWISE_AND -> left bitwiseAnd right + UastBinaryOperator.BITWISE_OR -> left bitwiseOr right + UastBinaryOperator.BITWISE_XOR -> left bitwiseXor right + UastBinaryOperator.SHIFT_LEFT -> left shl right + UastBinaryOperator.SHIFT_RIGHT -> left shr right + UastBinaryOperator.UNSIGNED_SHIFT_RIGHT -> left ushr right + else -> null + } + + override fun visitBinaryExpression(node: UBinaryExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val operator = node.operator + + if (operator is UastBinaryOperator.AssignOperator) { + return node.leftOperand.assign(operator, node.rightOperand, data) storeResultFor node + } + + val leftInfo = node.leftOperand.accept(this, data) + if (!leftInfo.reachable) { + return leftInfo storeResultFor node + } + + val rightInfo = node.rightOperand.accept(this, leftInfo.state) + + operator.evaluate(leftInfo.value, rightInfo.value)?.let { + return it to rightInfo.state storeResultFor node + } + + return node.evaluateViaExtensions { evaluateBinary(node, leftInfo.value, rightInfo.value, rightInfo.state) } + ?: UUndeterminedValue to rightInfo.state storeResultFor node + } + + override fun visitPolyadicExpression(node: UPolyadicExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val operator = node.operator + + val infos = node.operands.map { + it.accept(this, data).apply { + if (!reachable) { + return this storeResultFor node + } + } + } + + val lastInfo = infos.last() + val firstValue = infos.first().value + val restInfos = infos.drop(1) + + return restInfos.fold(firstValue) { accumulator, info -> + operator.evaluate(accumulator, info.value) ?: return UUndeterminedValue to info.state storeResultFor node + } to lastInfo.state storeResultFor node + } + + private fun evaluateTypeCast(operandInfo: UEvaluationInfo, type: PsiType): UEvaluationInfo { + val constant = operandInfo.value.toConstant() ?: return UUndeterminedValue to operandInfo.state + val resultConstant = when (type) { + PsiType.BOOLEAN -> { + constant as? UBooleanConstant + } + PsiType.CHAR -> when (constant) { + // Join the following three in UNumericConstant + // when https://youtrack.jetbrains.com/issue/KT-14868 is fixed + is UIntConstant -> UCharConstant(constant.value.toChar()) + is ULongConstant -> UCharConstant(constant.value.toChar()) + is UFloatConstant -> UCharConstant(constant.value.toChar()) + + is UCharConstant -> constant + else -> null + } + PsiType.LONG -> { + (constant as? UNumericConstant)?.value?.toLong()?.let { value -> ULongConstant(value) } + } + PsiType.BYTE, PsiType.SHORT, PsiType.INT -> { + (constant as? UNumericConstant)?.value?.toInt()?.let { UIntConstant(it, type) } + } + PsiType.FLOAT, PsiType.DOUBLE -> { + (constant as? UNumericConstant)?.value?.toDouble()?.let { UFloatConstant.create(it, type) } + } + else -> when (type.name) { + "java.lang.String" -> UStringConstant(constant.asString()) + else -> null + } + } ?: return UUndeterminedValue to operandInfo.state + return when (operandInfo.value) { + resultConstant -> return operandInfo + is UConstant -> resultConstant + is UDependentValue -> UDependentValue.create(resultConstant, operandInfo.value.dependencies) + else -> UUndeterminedValue + } to operandInfo.state + } + + private fun evaluateTypeCheck(operandInfo: UEvaluationInfo, type: PsiType): UEvaluationInfo { + val constant = operandInfo.value.toConstant() ?: return UUndeterminedValue to operandInfo.state + val valid = when (type) { + PsiType.BOOLEAN -> constant is UBooleanConstant + PsiType.LONG -> constant is ULongConstant + PsiType.BYTE, PsiType.SHORT, PsiType.INT, PsiType.CHAR -> constant is UIntConstant + PsiType.FLOAT, PsiType.DOUBLE -> constant is UFloatConstant + else -> when (type.name) { + "java.lang.String" -> constant is UStringConstant + else -> false + } + } + return UBooleanConstant.valueOf(valid) to operandInfo.state + } + + override fun visitBinaryExpressionWithType( + node: UBinaryExpressionWithType, data: UEvaluationState + ): UEvaluationInfo { + inputStateCache[node] = data + val operandInfo = node.operand.accept(this, data) + if (!operandInfo.reachable || operandInfo.value == UUndeterminedValue) { + return operandInfo storeResultFor node + } + return when (node.operationKind) { + UastBinaryExpressionWithTypeKind.TYPE_CAST -> evaluateTypeCast(operandInfo, node.type) + UastBinaryExpressionWithTypeKind.INSTANCE_CHECK -> evaluateTypeCheck(operandInfo, node.type) + else -> UUndeterminedValue to operandInfo.state + } storeResultFor node + } + + override fun visitParenthesizedExpression(node: UParenthesizedExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return node.expression.accept(this, data) storeResultFor node + } + + override fun visitLabeledExpression(node: ULabeledExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return node.expression.accept(this, data) storeResultFor node + } + + override fun visitCallExpression(node: UCallExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + + var currentInfo = UUndeterminedValue to data + currentInfo = node.receiver?.accept(this, currentInfo.state) ?: currentInfo + if (!currentInfo.reachable) return currentInfo storeResultFor node + val argumentValues = mutableListOf() + for (valueArgument in node.valueArguments) { + currentInfo = valueArgument.accept(this, currentInfo.state) + if (!currentInfo.reachable) return currentInfo storeResultFor node + argumentValues.add(currentInfo.value) + } + + return (node.evaluateViaExtensions { + node.resolve()?.let { method -> evaluateMethodCall(method, argumentValues, currentInfo.state) } + ?: UUndeterminedValue to currentInfo.state + } ?: UCallResultValue(node, argumentValues) to currentInfo.state) storeResultFor node + } + + override fun visitQualifiedReferenceExpression( + node: UQualifiedReferenceExpression, + data: UEvaluationState + ): UEvaluationInfo { + inputStateCache[node] = data + + var currentInfo = UUndeterminedValue to data + currentInfo = node.receiver.accept(this, currentInfo.state) + if (!currentInfo.reachable) return currentInfo storeResultFor node + + val selectorInfo = node.selector.accept(this, currentInfo.state) + return when (node.accessType) { + UastQualifiedExpressionAccessType.SIMPLE -> { + selectorInfo + } + else -> { + return node.evaluateViaExtensions { evaluateQualified(node.accessType, currentInfo, selectorInfo) } + ?: UUndeterminedValue to selectorInfo.state storeResultFor node + } + } storeResultFor node + } + + override fun visitDeclarationsExpression( + node: UDeclarationsExpression, + data: UEvaluationState + ): UEvaluationInfo { + inputStateCache[node] = data + var currentInfo = UUndeterminedValue to data + for (variable in node.declarations) { + currentInfo = variable.accept(this, currentInfo.state) + if (!currentInfo.reachable) return currentInfo storeResultFor node + } + return currentInfo storeResultFor node + } + + override fun visitVariable(node: UVariable, data: UEvaluationState): UEvaluationInfo { + val initializer = node.uastInitializer + val initializerInfo = initializer?.accept(this, data) ?: UUndeterminedValue to data + if (!initializerInfo.reachable) return initializerInfo + return UUndeterminedValue to initializerInfo.state.assign(node, initializerInfo.value, node) + } + + // ----------------------- // + + override fun visitBlockExpression(node: UBlockExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + var currentInfo = UUndeterminedValue to data + for (expression in node.expressions) { + currentInfo = expression.accept(this, currentInfo.state) + if (!currentInfo.reachable) return currentInfo storeResultFor node + } + return currentInfo storeResultFor node + } + + override fun visitIfExpression(node: UIfExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val conditionInfo = node.condition.accept(this, data) + if (!conditionInfo.reachable) return conditionInfo storeResultFor node + + val thenInfo = node.thenExpression?.accept(this, conditionInfo.state) + val elseInfo = node.elseExpression?.accept(this, conditionInfo.state) + val conditionValue = conditionInfo.value + val defaultInfo = UUndeterminedValue to conditionInfo.state + val constantConditionValue = conditionValue.toConstant() + + return when (constantConditionValue) { + is UBooleanConstant -> { + if (constantConditionValue.value) thenInfo ?: defaultInfo + else elseInfo ?: defaultInfo + } + else -> when { + thenInfo == null -> elseInfo?.merge(defaultInfo) ?: defaultInfo + elseInfo == null -> thenInfo.merge(defaultInfo) + else -> thenInfo.merge(elseInfo) + } + } storeResultFor node + } + + override fun visitSwitchExpression(node: USwitchExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val subjectInfo = node.expression?.accept(this, data) ?: UUndeterminedValue to data + if (!subjectInfo.reachable) return subjectInfo storeResultFor node + + var resultInfo: UEvaluationInfo? = null + var clauseInfo = subjectInfo + var fallThroughCondition: UValue = UBooleanConstant.False + + fun List.evaluateAndFold(): UValue = + this.map { + clauseInfo = it.accept(this@TreeBasedEvaluator, clauseInfo.state) + (clauseInfo.value valueEquals subjectInfo.value).toConstant() as? UValueBase ?: UUndeterminedValue + }.fold(UBooleanConstant.False) { previous: UValue, next -> previous or next } + + clausesLoop@ for (expression in node.body.expressions) { + val switchClauseWithBody = expression as USwitchClauseExpressionWithBody + val caseCondition = switchClauseWithBody.caseValues.evaluateAndFold().or(fallThroughCondition) + + if (caseCondition != UBooleanConstant.False) { + for (bodyExpression in switchClauseWithBody.body.expressions) { + clauseInfo = bodyExpression.accept(this, clauseInfo.state) + if (!clauseInfo.reachable) break + } + val clauseValue = clauseInfo.value + if (clauseValue is UNothingValue && clauseValue.containingLoopOrSwitch == node) { + // break from switch + resultInfo = resultInfo?.merge(clauseInfo) ?: clauseInfo + if (caseCondition == UBooleanConstant.True) break@clausesLoop + clauseInfo = subjectInfo + fallThroughCondition = UBooleanConstant.False + } + // TODO: jump out + else { + fallThroughCondition = caseCondition + clauseInfo = clauseInfo.merge(subjectInfo) + } + } + } + + resultInfo = resultInfo ?: subjectInfo + val resultValue = resultInfo.value + if (resultValue is UNothingValue && resultValue.containingLoopOrSwitch == node) { + resultInfo = resultInfo.copy(UUndeterminedValue) + } + return resultInfo storeResultFor node + } + + private fun evaluateLoop( + loop: ULoopExpression, + inputState: UEvaluationState, + condition: UExpression? = null, + infinite: Boolean = false, + update: UExpression? = null + ): UEvaluationInfo { + + fun evaluateCondition(inputState: UEvaluationState): UEvaluationInfo = + condition?.accept(this, inputState) + ?: (if (infinite) UBooleanConstant.True else UUndeterminedValue) to inputState + + var resultInfo = UUndeterminedValue to inputState + do { + val previousInfo = resultInfo + resultInfo = evaluateCondition(resultInfo.state) + val conditionConstant = resultInfo.value.toConstant() + if (conditionConstant == UBooleanConstant.False) { + return resultInfo.copy(UUndeterminedValue) storeResultFor loop + } + val bodyInfo = loop.body.accept(this, resultInfo.state) + val bodyValue = bodyInfo.value + if (bodyValue is UNothingValue) { + if (bodyValue.kind == BREAK && bodyValue.containingLoopOrSwitch == loop) { + return if (conditionConstant == UBooleanConstant.True) { + bodyInfo.copy(UUndeterminedValue) + } + else { + bodyInfo.copy(UUndeterminedValue).merge(previousInfo) + } storeResultFor loop + } + else if (bodyValue.kind == CONTINUE && bodyValue.containingLoopOrSwitch == loop) { + val updateInfo = update?.accept(this, bodyInfo.state) ?: bodyInfo + resultInfo = updateInfo.copy(UUndeterminedValue).merge(previousInfo) + } + else { + return if (conditionConstant == UBooleanConstant.True) { + bodyInfo + } + else { + resultInfo.copy(UUndeterminedValue) + } storeResultFor loop + } + } + else { + val updateInfo = update?.accept(this, bodyInfo.state) ?: bodyInfo + resultInfo = updateInfo.merge(previousInfo) + } + } while (previousInfo != resultInfo) + return resultInfo.copy(UUndeterminedValue) storeResultFor loop + } + + override fun visitForEachExpression(node: UForEachExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val iterableInfo = node.iteratedValue.accept(this, data) + return evaluateLoop(node, iterableInfo.state) + } + + override fun visitForExpression(node: UForExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val initialState = node.declaration?.accept(this, data)?.state ?: data + return evaluateLoop(node, initialState, node.condition, node.condition == null, node.update) + } + + override fun visitWhileExpression(node: UWhileExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + return evaluateLoop(node, data, node.condition) + } + + override fun visitDoWhileExpression(node: UDoWhileExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val bodyInfo = node.body.accept(this, data) + return evaluateLoop(node, bodyInfo.state, node.condition) + } + + override fun visitTryExpression(node: UTryExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val tryInfo = node.tryClause.accept(this, data) + val mergedTryInfo = tryInfo.merge(UUndeterminedValue to data) + val catchInfoList = node.catchClauses.map { it.accept(this, mergedTryInfo.state) } + val mergedTryCatchInfo = catchInfoList.fold(mergedTryInfo, UEvaluationInfo::merge) + val finallyInfo = node.finallyClause?.accept(this, mergedTryCatchInfo.state) ?: mergedTryCatchInfo + return finallyInfo storeResultFor node + } + + // ----------------------- // + + override fun visitObjectLiteralExpression(node: UObjectLiteralExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val objectInfo = node.declaration.accept(this, data) + val resultState = data.merge(objectInfo.state) + return UUndeterminedValue to resultState storeResultFor node + } + + override fun visitLambdaExpression(node: ULambdaExpression, data: UEvaluationState): UEvaluationInfo { + inputStateCache[node] = data + val lambdaInfo = node.body.accept(this, data) + val resultState = data.merge(lambdaInfo.state) + return UUndeterminedValue to resultState storeResultFor node + } + + override fun visitClass(node: UClass, data: UEvaluationState): UEvaluationInfo { + // fields / initializers / nested classes? + var resultState = data + for (method in node.methods) { + resultState = resultState.merge(method.accept(this, resultState).state) + } + return UUndeterminedValue to resultState + } + + override fun visitMethod(node: UMethod, data: UEvaluationState): UEvaluationInfo { + return UUndeterminedValue to (node.uastBody?.accept(this, data)?.state ?: data) + } +} + +fun Any?.toConstant(node: ULiteralExpression? = null) = when(this) { + null -> UNullConstant + is Float -> UFloatConstant.create(this.toDouble(), UNumericType.FLOAT, node) + is Double -> UFloatConstant.create(this, UNumericType.DOUBLE, node) + is Long -> ULongConstant(this, node) + is Int -> UIntConstant(this, UNumericType.INT, node) + is Short -> UIntConstant(this.toInt(), UNumericType.SHORT, node) + is Byte -> UIntConstant(this.toInt(), UNumericType.BYTE, node) + is Char -> UCharConstant(this, node) + is Boolean -> UBooleanConstant.valueOf(this) + is String -> UStringConstant(this, node) + else -> UUndeterminedValue +} diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationContext.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationContext.kt new file mode 100644 index 000000000000..daad664fcd0f --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationContext.kt @@ -0,0 +1,63 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import com.intellij.openapi.util.Key +import org.jetbrains.uast.* +import org.jetbrains.uast.values.UValue +import java.lang.ref.SoftReference + +interface UEvaluationContext { + val uastContext: UastContext + + val extensions: List + + fun analyzeAll(file: UFile, state: UEvaluationState = file.createEmptyState()): UEvaluationContext + + fun analyze(declaration: UDeclaration, state: UEvaluationState = declaration.createEmptyState()): UEvaluator + + fun valueOf(expression: UExpression): UValue + + fun getEvaluator(declaration: UDeclaration): UEvaluator +} + +fun UFile.analyzeAll(context: UastContext = getUastContext(), extensions: List = emptyList()): UEvaluationContext = + MapBasedEvaluationContext(context, extensions).analyzeAll(this) + +@JvmOverloads +fun UExpression.uValueOf(extensions: List = emptyList()): UValue? { + val declaration = getContainingDeclaration() ?: return null + val context = declaration.getEvaluationContextWithCaching(extensions) + context.analyze(declaration) + return context.valueOf(this) +} + +fun UExpression.uValueOf(vararg extensions: UEvaluatorExtension): UValue? = uValueOf(extensions.asList()) + +fun UDeclaration.getEvaluationContextWithCaching(extensions: List = emptyList()): UEvaluationContext { + return containingFile?.let { file -> + val cachedContext = file.getUserData(EVALUATION_CONTEXT_KEY)?.get() + if (cachedContext != null && cachedContext.extensions == extensions) + cachedContext + else + MapBasedEvaluationContext(getUastContext(), extensions).apply { + file.putUserData(EVALUATION_CONTEXT_KEY, SoftReference(this)) + } + + } ?: MapBasedEvaluationContext(getUastContext(), extensions) +} + +val EVALUATION_CONTEXT_KEY = Key>("uast.EvaluationContext") diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationInfo.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationInfo.kt new file mode 100644 index 000000000000..f2b73e0477ca --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationInfo.kt @@ -0,0 +1,35 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.values.UValue + +data class UEvaluationInfo(val value: UValue, val state: UEvaluationState) { + fun merge(otherInfo: UEvaluationInfo): UEvaluationInfo { + // info with 'UNothingValue' is just ignored, if other is not UNothingValue + if (!reachable && otherInfo.reachable) return otherInfo + if (!otherInfo.reachable && reachable) return this + // Regular merge + val mergedValue = value.merge(otherInfo.value) + val mergedState = state.merge(otherInfo.state) + return UEvaluationInfo(mergedValue, mergedState) + } + + fun copy(value: UValue) = if (value != this.value) UEvaluationInfo(value, state) else this + + val reachable: Boolean + get() = value.reachable +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationState.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationState.kt new file mode 100644 index 000000000000..e8e90ad959d1 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluationState.kt @@ -0,0 +1,38 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UVariable +import org.jetbrains.uast.values.UValue + +// Role: stores current values for all variables (and may be something else) +// Immutable +interface UEvaluationState { + val boundElement: UElement? + + val variables: Set + + operator fun get(variable: UVariable): UValue + + // Creates new evaluation state with state[variable] = value and boundElement = at + fun assign(variable: UVariable, value: UValue, at: UElement): UEvaluationState + + // Merged two states + fun merge(otherState: UEvaluationState): UEvaluationState +} + +fun UElement.createEmptyState(): UEvaluationState = EmptyEvaluationState(this) \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluator.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluator.kt new file mode 100644 index 000000000000..4b2acb2e87d6 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluator.kt @@ -0,0 +1,50 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import com.intellij.openapi.extensions.Extensions +import com.intellij.psi.PsiElement +import org.jetbrains.uast.* +import org.jetbrains.uast.values.UDependency +import org.jetbrains.uast.values.UValue + +// Role: at the current state, evaluate expression(s) +interface UEvaluator { + + val context: UastContext + + val languageExtensions: List + get() { + val rootArea = Extensions.getRootArea() + if (!rootArea.hasExtensionPoint(UEvaluatorExtension.EXTENSION_POINT_NAME.name)) return listOf() + return rootArea.getExtensionPoint(UEvaluatorExtension.EXTENSION_POINT_NAME).extensions.toList() + } + + fun PsiElement.languageExtension() = languageExtensions.firstOrNull { it.language == language } + + fun UElement.languageExtension() = psi?.languageExtension() + + fun analyze(method: UMethod, state: UEvaluationState = method.createEmptyState()) + + fun analyze(field: UField, state: UEvaluationState = field.createEmptyState()) + + fun evaluate(expression: UExpression, state: UEvaluationState? = null): UValue + + fun getDependents(dependency: UDependency): Set +} + +fun createEvaluator(context: UastContext, extensions: List): UEvaluator = + TreeBasedEvaluator(context, extensions) diff --git a/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluatorExtension.kt b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluatorExtension.kt new file mode 100644 index 000000000000..ffe3d3117da5 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/evaluation/UEvaluatorExtension.kt @@ -0,0 +1,70 @@ +/* + * 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 org.jetbrains.uast.evaluation + +import com.intellij.lang.Language +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.* +import org.jetbrains.uast.values.UValue + +interface UEvaluatorExtension { + + companion object { + val EXTENSION_POINT_NAME: ExtensionPointName = + ExtensionPointName.create("org.jetbrains.uast.evaluation.UEvaluatorExtension") + } + + infix fun UValue.to(state: UEvaluationState) = UEvaluationInfo(this, state) + + val language: Language + + fun evaluatePostfix( + operator: UastPostfixOperator, + operandValue: UValue, + state: UEvaluationState + ): UEvaluationInfo + + fun evaluatePrefix( + operator: UastPrefixOperator, + operandValue: UValue, + state: UEvaluationState + ): UEvaluationInfo + + fun evaluateBinary( + binaryExpression: UBinaryExpression, + leftValue: UValue, + rightValue: UValue, + state: UEvaluationState + ): UEvaluationInfo + + fun evaluateQualified( + accessType: UastQualifiedExpressionAccessType, + receiverInfo: UEvaluationInfo, + selectorInfo: UEvaluationInfo + ): UEvaluationInfo + + fun evaluateMethodCall( + target: PsiMethod, + argumentValues: List, + state: UEvaluationState + ): UEvaluationInfo + + fun evaluateVariable( + variable: UVariable, + state: UEvaluationState + ): UEvaluationInfo +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UArrayAccessExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UArrayAccessExpression.kt new file mode 100644 index 000000000000..25749ba3ac51 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UArrayAccessExpression.kt @@ -0,0 +1,52 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents `receiver[index0, ..., indexN]` expression. + */ +interface UArrayAccessExpression : UExpression { + /** + * Returns the receiver expression. + */ + val receiver: UExpression + + /** + * Returns the list of index expressions. + */ + val indices: List + + override fun accept(visitor: UastVisitor) { + if (visitor.visitArrayAccessExpression(this)) return + annotations.acceptList(visitor) + receiver.accept(visitor) + indices.acceptList(visitor) + visitor.afterVisitArrayAccessExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitArrayAccessExpression(this, data) + + override fun asLogString() = log() + + override fun asRenderString() = receiver.asRenderString() + + indices.joinToString(prefix = "[", postfix = "]") { it.asRenderString() } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpression.kt new file mode 100644 index 000000000000..e0e59948de07 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpression.kt @@ -0,0 +1,65 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a binary expression (value1 op value2), eg. `2 + "A"`. + */ +interface UBinaryExpression : UPolyadicExpression { + /** + * Returns the left operand. + */ + val leftOperand: UExpression + + /** + * Returns the right operand. + */ + val rightOperand: UExpression + + /** + * Returns the operator identifier. + */ + val operatorIdentifier: UIdentifier? + + /** + * Resolve the operator method. + * + * @return the resolved method, or null if the method can't be resolved, or if the expression is not a method call. + */ + fun resolveOperator(): PsiMethod? + + override val operands: List + get() = listOf(leftOperand, rightOperand) + + override fun accept(visitor: UastVisitor) { + if (visitor.visitBinaryExpression(this)) return + annotations.acceptList(visitor) + leftOperand.accept(visitor) + rightOperand.accept(visitor) + visitor.afterVisitBinaryExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitBinaryExpression(this, data) + + override fun asLogString() = log("operator = $operator") +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpressionWithType.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpressionWithType.kt new file mode 100644 index 000000000000..6791715ddc09 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UBinaryExpressionWithType.kt @@ -0,0 +1,63 @@ +/* + * 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 org.jetbrains.uast + + +import com.intellij.psi.PsiType +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a binary expression with type (value op type), e.g. ("A" instanceof String). + */ +interface UBinaryExpressionWithType : UExpression { + /** + * Returns the operand expression. + */ + val operand: UExpression + + /** + * Returns the operation kind. + */ + val operationKind: UastBinaryExpressionWithTypeKind + + /** + * Returns the type reference of this expression. + */ + val typeReference: UTypeReferenceExpression? + + /** + * Returns the type. + */ + val type: PsiType + + override fun asLogString() = log() + + override fun asRenderString() = "${operand.asRenderString()} ${operationKind.name} ${type.name}" + + override fun accept(visitor: UastVisitor) { + if (visitor.visitBinaryExpressionWithType(this)) return + annotations.acceptList(visitor) + operand.accept(visitor) + typeReference?.accept(visitor) + visitor.afterVisitBinaryExpressionWithType(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitBinaryExpressionWithType(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UBlockExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UBlockExpression.kt new file mode 100644 index 000000000000..1dd672603c42 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UBlockExpression.kt @@ -0,0 +1,49 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents the code block expression: `{ /* code */ }`. + */ +interface UBlockExpression : UExpression { + /** + * Returns the list of block expressions. + */ + val expressions: List + + override fun accept(visitor: UastVisitor) { + if (visitor.visitBlockExpression(this)) return + annotations.acceptList(visitor) + expressions.acceptList(visitor) + visitor.afterVisitBlockExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitBlockExpression(this, data) + + override fun asLogString() = log() + + override fun asRenderString() = buildString { + appendln("{") + expressions.forEach { appendln(it.asRenderString().withMargin) } + append("}") + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UBreakExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UBreakExpression.kt new file mode 100644 index 000000000000..f01003db9f53 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UBreakExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a `break` expression. + */ +interface UBreakExpression : UJumpExpression { + + override fun accept(visitor: UastVisitor) { + if (visitor.visitBreakExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitBreakExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitBreakExpression(this, data) + + override fun asLogString() = log("label = $label") + + override fun asRenderString() = label?.let { "break@$it" } ?: "break" +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UCallExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UCallExpression.kt new file mode 100644 index 000000000000..8c8505bc916f --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UCallExpression.kt @@ -0,0 +1,116 @@ +/* + * 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 org.jetbrains.uast + + +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a call expression (method/constructor call, array initializer). + */ +interface UCallExpression : UExpression, UResolvable { + /** + * Returns the call kind. + */ + val kind: UastCallKind + + /** + * Returns the called method name, or null if the call is not a method call. + * This property should return the actual resolved function name. + */ + val methodName: String? + + /** + * Returns the expression receiver. + * For example, for call `a.b.[c()]` the receiver is `a.b`. + */ + val receiver: UExpression? + + /** + * Returns the receiver type, or null if the call has not a receiver. + */ + val receiverType: PsiType? + + /** + * Returns the function reference expression if the call is a non-constructor method call, null otherwise. + */ + val methodIdentifier: UIdentifier? + + /** + * Returns the class reference if the call is a constructor call, null otherwise. + */ + val classReference: UReferenceExpression? + + /** + * Returns the value argument count. + * + * Retrieving the argument count could be faster than getting the [valueArguments.size], + * because there is no need to create actual [UExpression] instances. + */ + val valueArgumentCount: Int + + /** + * Returns the list of value arguments. + */ + val valueArguments: List + + /** + * Returns the type argument count. + */ + val typeArgumentCount: Int + + /** + * Returns the type arguments for the call. + */ + val typeArguments: List + + /** + * Returns the return type of the called function, or null if the call is not a function call. + */ + val returnType: PsiType? + + /** + * Resolve the called method. + * + * @return the [PsiMethod], or null if the method was not resolved. + * Note that the [PsiMethod] is an unwrapped [PsiMethod], not a [UMethod]. + */ + override fun resolve(): PsiMethod? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitCallExpression(this)) return + annotations.acceptList(visitor) + methodIdentifier?.accept(visitor) + classReference?.accept(visitor) + valueArguments.acceptList(visitor) + visitor.afterVisitCallExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitCallExpression(this, data) + + override fun asLogString() = log("kind = $kind, argCount = $valueArgumentCount)") + + override fun asRenderString(): String { + val ref = classReference?.asRenderString() ?: methodName ?: methodIdentifier?.asRenderString() ?: "" + return ref + "(" + valueArguments.joinToString { it.asRenderString() } + ")" + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UCallableReferenceExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UCallableReferenceExpression.kt new file mode 100644 index 000000000000..cb8de92cb8e5 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UCallableReferenceExpression.kt @@ -0,0 +1,67 @@ +/* + * 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 org.jetbrains.uast + + +import com.intellij.psi.PsiType +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a callable reference expression, e.g. `Clazz::methodName`. + */ +interface UCallableReferenceExpression : UReferenceExpression { + /** + * Returns the qualifier expression. + * Can be null if the [qualifierType] is known. + */ + val qualifierExpression: UExpression? + + /** + * Returns the qualifier type. + * Can be null if the qualifier is an expression. + */ + val qualifierType: PsiType? + + /** + * Returns the callable name. + */ + val callableName: String + + override fun accept(visitor: UastVisitor) { + if (visitor.visitCallableReferenceExpression(this)) return + annotations.acceptList(visitor) + qualifierExpression?.accept(visitor) + visitor.afterVisitCallableReferenceExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitCallableReferenceExpression(this, data) + + override fun asLogString() = log("name = $callableName") + + override fun asRenderString() = buildString { + qualifierExpression?.let { + append(it.asRenderString()) + } ?: qualifierType?.let { + append(it.name) + } + append("::") + append(callableName) + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UClassLiteralExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UClassLiteralExpression.kt new file mode 100644 index 000000000000..e7c6224744b6 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UClassLiteralExpression.kt @@ -0,0 +1,53 @@ +/* + * 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 org.jetbrains.uast + + +import com.intellij.psi.PsiType +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents the class literal expression, e.g. `Clazz.class`. + */ +interface UClassLiteralExpression : UExpression { + override fun asLogString() = log() + + override fun asRenderString() = (type?.name) ?: "(${expression?.asRenderString() ?: ""})" + "::class" + + /** + * Returns the type referenced by this class literal, or null if the type can't be determined in a compile-time. + */ + val type: PsiType? + + /** + * Returns an expression for this class literal expression. + * Might be null if the [type] is specified. + */ + val expression: UExpression? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitClassLiteralExpression(this)) return + annotations.acceptList(visitor) + expression?.accept(visitor) + visitor.afterVisitClassLiteralExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitClassLiteralExpression(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UContinueExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UContinueExpression.kt new file mode 100644 index 000000000000..944faeadaae3 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UContinueExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a `continue` expression. + */ +interface UContinueExpression : UJumpExpression { + + override fun accept(visitor: UastVisitor) { + if (visitor.visitContinueExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitContinueExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitContinueExpression(this, data) + + override fun asLogString() = log("label = $label") + + override fun asRenderString() = label?.let { "continue@$it" } ?: "continue" +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UDeclarationsExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UDeclarationsExpression.kt new file mode 100644 index 000000000000..08768cea2413 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UDeclarationsExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a list of declarations. + * Example in Java: `int a = 4, b = 3`. + */ +interface UDeclarationsExpression : UExpression { + /** + * Returns the list of declarations inside this [UDeclarationsExpression]. + */ + val declarations: List + + override fun accept(visitor: UastVisitor) { + if (visitor.visitDeclarationsExpression(this)) return + annotations.acceptList(visitor) + declarations.acceptList(visitor) + visitor.afterVisitDeclarationsExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitDeclarationsExpression(this, data) + + override fun asRenderString() = declarations.joinToString(LINE_SEPARATOR) { it.asRenderString() } + + override fun asLogString() = log() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UExpressionList.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UExpressionList.kt new file mode 100644 index 000000000000..7d68ad02291a --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UExpressionList.kt @@ -0,0 +1,52 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a generic list of expressions. + */ +interface UExpressionList : UExpression { + /** + * Returns the list of expressions. + */ + val expressions: List + + /** + * Returns the list kind. + */ + val kind: UastSpecialExpressionKind + + override fun accept(visitor: UastVisitor) { + if (visitor.visitExpressionList(this)) return + annotations.acceptList(visitor) + expressions.acceptList(visitor) + visitor.afterVisitExpressionList(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitExpressionList(this, data) + + fun firstOrNull(): UExpression? = expressions.firstOrNull() + + override fun asLogString() = log(kind.name) + + override fun asRenderString() = kind.name + " " + expressions.joinToString(" : ") { it.asRenderString() } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UInstanceExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UInstanceExpression.kt new file mode 100644 index 000000000000..2a603da512d8 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UInstanceExpression.kt @@ -0,0 +1,22 @@ +/* + * 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 org.jetbrains.uast + +/** + * A common parent for "this" and "super" expressions. + */ +interface UInstanceExpression : UExpression, ULabeled, UResolvable \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UJumpExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UJumpExpression.kt new file mode 100644 index 000000000000..d5275811e4e9 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UJumpExpression.kt @@ -0,0 +1,26 @@ +/* + * 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 org.jetbrains.uast + +/** + * Represents jump expression (break / continue) with label + */ +interface UJumpExpression : UExpression { + /** + * Returns the expression label, or null if the label is not specified. + */ + val label: String? +} diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/ULabeledExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/ULabeledExpression.kt new file mode 100644 index 000000000000..48a0becd0ed7 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/ULabeledExpression.kt @@ -0,0 +1,52 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents an expression with the label specified. + */ +interface ULabeledExpression : UExpression, ULabeled { + /** + * Returns the expression label. + */ + override val label: String + + /** + * Returns the expression itself. + */ + val expression: UExpression + + override fun accept(visitor: UastVisitor) { + if (visitor.visitLabeledExpression(this)) return + annotations.acceptList(visitor) + expression.accept(visitor) + visitor.afterVisitLabeledExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitLabeledExpression(this, data) + + override fun evaluate() = expression.evaluate() + + override fun asLogString() = log("label = $label") + + override fun asRenderString() = "$label@ ${expression.asRenderString()}" +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/ULambdaExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/ULambdaExpression.kt new file mode 100644 index 000000000000..c9e32defccd5 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/ULambdaExpression.kt @@ -0,0 +1,58 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents the lambda expression. + */ +interface ULambdaExpression : UExpression { + /** + * Returns the list of lambda value parameters. + */ + val valueParameters: List + + /** + * Returns the lambda body expression. + */ + val body: UExpression + + override fun accept(visitor: UastVisitor) { + if (visitor.visitLambdaExpression(this)) return + annotations.acceptList(visitor) + valueParameters.acceptList(visitor) + body.accept(visitor) + visitor.afterVisitLambdaExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitLambdaExpression(this, data) + + override fun asLogString() = log() + + override fun asRenderString(): String { + val renderedValueParameters = if (valueParameters.isEmpty()) + "" + else + valueParameters.joinToString { it.asRenderString() } + " ->" + LINE_SEPARATOR + + return "{ " + renderedValueParameters + body.asRenderString().withMargin + LINE_SEPARATOR + "}" + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/ULiteralExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/ULiteralExpression.kt new file mode 100644 index 000000000000..6d6027df7dc9 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/ULiteralExpression.kt @@ -0,0 +1,74 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a literal expression. + */ +interface ULiteralExpression : UExpression { + /** + * Returns the literal expression value. + * This is basically a String, Number or null if the literal is a `null` literal. + */ + val value: Any? + + /** + * Returns true if the literal is a `null`-literal, false otherwise. + */ + val isNull: Boolean + get() = value == null + + /** + * Returns true if the literal is a [String] literal, false otherwise. + */ + val isString: Boolean + get() = evaluate() is String + + /** + * Returns true if the literal is a [Boolean] literal, false otherwise. + */ + val isBoolean: Boolean + get() = evaluate() is Boolean + + override fun accept(visitor: UastVisitor) { + if (visitor.visitLiteralExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitLiteralExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitLiteralExpression(this, data) + + override fun asRenderString(): String { + val value = value + return when (value) { + null -> "null" + is Char -> "'$value'" + is String -> '"' + value.replace("\\", "\\\\") + .replace("\r", "\\r").replace("\n", "\\n") + .replace("\t", "\\t").replace("\b", "\\b") + .replace("\"", "\\\"") + '"' + else -> value.toString() + } + } + + override fun asLogString() = log("value = ${asRenderString()}") +} diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UNamedExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UNamedExpression.kt new file mode 100644 index 000000000000..9580c1941aa7 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UNamedExpression.kt @@ -0,0 +1,38 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +interface UNamedExpression: UExpression { + val name: String? + val expression: UExpression + + override fun accept(visitor: UastVisitor) { + if (visitor.visitElement(this)) return + annotations.acceptList(visitor) + expression.accept(visitor) + visitor.afterVisitElement(this) + } + + override fun asLogString() = log("name = $name") + + override fun asRenderString() = name + " = " + expression.asRenderString() + + override fun evaluate() = expression.evaluate() +} diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UObjectLiteralExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UObjectLiteralExpression.kt new file mode 100644 index 000000000000..4456f85dbfc3 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UObjectLiteralExpression.kt @@ -0,0 +1,65 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiType +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents an object literal expression, e.g. `new Runnable() {}` in Java. + */ +interface UObjectLiteralExpression : UCallExpression { + /** + * Returns the class declaration. + */ + val declaration: UClass + + override val methodIdentifier: UIdentifier? + get() = null + + override val kind: UastCallKind + get() = UastCallKind.CONSTRUCTOR_CALL + + override val methodName: String? + get() = null + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null + + override val returnType: PsiType? + get() = null + + + override fun accept(visitor: UastVisitor) { + if (visitor.visitObjectLiteralExpression(this)) return + annotations.acceptList(visitor) + declaration.accept(visitor) + visitor.afterVisitObjectLiteralExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitObjectLiteralExpression(this, data) + + override fun asLogString() = log() + + override fun asRenderString() = "anonymous " + declaration.text +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UParenthesizedExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UParenthesizedExpression.kt new file mode 100644 index 000000000000..64d4963e61f2 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UParenthesizedExpression.kt @@ -0,0 +1,47 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a parenthesized expression, e.g. `(23 + 3)`. + */ +interface UParenthesizedExpression : UExpression { + /** + * Returns an expression inside the parenthesis. + */ + val expression: UExpression + + override fun accept(visitor: UastVisitor) { + if (visitor.visitParenthesizedExpression(this)) return + annotations.acceptList(visitor) + expression.accept(visitor) + visitor.afterVisitParenthesizedExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitParenthesizedExpression(this, data) + + override fun evaluate() = expression.evaluate() + + override fun asLogString() = log() + + override fun asRenderString() = '(' + expression.asRenderString() + ')' +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UPolyadicExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UPolyadicExpression.kt new file mode 100644 index 000000000000..5d69cb5e72f2 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UPolyadicExpression.kt @@ -0,0 +1,53 @@ +/* + * 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 org.jetbrains.uast + + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a polyadic expression (value1 op value2 op value3 op ...), eg. `2 + "A" + c + d`. + */ +interface UPolyadicExpression : UExpression { + + /** + * Returns a list of expression operands. + */ + val operands: List + + /** + * Returns the operator. + */ + val operator: UastBinaryOperator + + override fun accept(visitor: UastVisitor) { + if (visitor.visitPolyadicExpression(this)) return + annotations.acceptList(visitor) + operands.acceptList(visitor) + visitor.afterVisitPolyadicExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitPolyadicExpression(this, data) + + override fun asLogString() = log("operator = $operator") + + override fun asRenderString() = + operands.joinToString(separator = " ${operator.text} ", transform = UExpression::asRenderString) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UQualifiedReferenceExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UQualifiedReferenceExpression.kt new file mode 100644 index 000000000000..78f1abc805ef --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UQualifiedReferenceExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents the qualified expression (receiver.selector). + */ +interface UQualifiedReferenceExpression : UReferenceExpression { + /** + * Returns the expression receiver. + */ + val receiver: UExpression + + /** + * Returns the expression selector. + */ + val selector: UExpression + + /** + * Returns the access type (simple, safe access, etc.). + */ + val accessType: UastQualifiedExpressionAccessType + + override fun asRenderString() = receiver.asRenderString() + accessType.name + selector.asRenderString() + + override fun accept(visitor: UastVisitor) { + if (visitor.visitQualifiedReferenceExpression(this)) return + annotations.acceptList(visitor) + receiver.accept(visitor) + selector.accept(visitor) + visitor.afterVisitQualifiedReferenceExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitQualifiedReferenceExpression(this, data) + + override fun asLogString() = log() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UReferenceExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UReferenceExpression.kt new file mode 100644 index 000000000000..1b26e639a1b4 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UReferenceExpression.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor + +interface UReferenceExpression : UExpression, UResolvable { + /** + * Returns the resolved name for this reference, or null if the reference can't be resolved. + */ + val resolvedName: String? + + override fun asLogString() = log() + + override fun accept(visitor: UastTypedVisitor, data: D) = visitor.visitReferenceExpression(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UReturnExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UReturnExpression.kt new file mode 100644 index 000000000000..0b416a442795 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UReturnExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a `return` expression. + */ +interface UReturnExpression : UExpression { + /** + * Returns the `return` value. + */ + val returnExpression: UExpression? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitReturnExpression(this)) return + annotations.acceptList(visitor) + returnExpression?.accept(visitor) + visitor.afterVisitReturnExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitReturnExpression(this, data) + + override fun asRenderString() = returnExpression.let { if (it == null) "return" else "return " + it.asRenderString() } + + override fun asLogString() = log() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/USimpleNameReferenceExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/USimpleNameReferenceExpression.kt new file mode 100644 index 000000000000..86aa7de21808 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/USimpleNameReferenceExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a simple reference expression (a non-qualified identifier). + */ +interface USimpleNameReferenceExpression : UReferenceExpression { + /** + * Returns the identifier name. + */ + val identifier: String + + override fun accept(visitor: UastVisitor) { + if (visitor.visitSimpleNameReferenceExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitSimpleNameReferenceExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitSimpleNameReferenceExpression(this, data) + + override fun asLogString() = log("identifier = $identifier") + + override fun asRenderString() = identifier +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/USuperExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/USuperExpression.kt new file mode 100644 index 000000000000..cbcc6e76de47 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/USuperExpression.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a `super` expression. + * Qualified `super` is not supported at the moment. + */ +interface USuperExpression : UInstanceExpression { + override fun asLogString() = log("label = $label") + + override fun asRenderString() = "super" + + override fun accept(visitor: UastVisitor) { + if (visitor.visitSuperExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitSuperExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitSuperExpression(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt new file mode 100644 index 000000000000..aae64c01b5d9 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a `this` expression. + * Qualified `this` is not supported at the moment. + */ +interface UThisExpression : UInstanceExpression { + override fun asLogString() = log("label = $label") + + override fun asRenderString() = "this" + + override fun accept(visitor: UastVisitor) { + if (visitor.visitThisExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitThisExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitThisExpression(this, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UThrowExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UThrowExpression.kt new file mode 100644 index 000000000000..6f5d19adc515 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UThrowExpression.kt @@ -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 org.jetbrains.uast + +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Represents a `throw` expression. + */ +interface UThrowExpression : UExpression { + /** + * Returns ths thrown expression. + */ + val thrownExpression: UExpression + + override fun accept(visitor: UastVisitor) { + if (visitor.visitThrowExpression(this)) return + annotations.acceptList(visitor) + thrownExpression.accept(visitor) + visitor.afterVisitThrowExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitThrowExpression(this, data) + + override fun asRenderString() = "throw " + thrownExpression.asRenderString() + + override fun asLogString() = log() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UTypeReferenceExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UTypeReferenceExpression.kt new file mode 100644 index 000000000000..6a8fc9439740 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UTypeReferenceExpression.kt @@ -0,0 +1,48 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiType +import com.intellij.psi.util.PsiTypesUtil +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +interface UTypeReferenceExpression : UExpression { + /** + * Returns the resolved type for this reference. + */ + val type: PsiType + + /** + * Returns the qualified name of the class type, or null if the [type] is not a class type. + */ + fun getQualifiedName() = PsiTypesUtil.getPsiClass(type)?.qualifiedName + + override fun accept(visitor: UastVisitor) { + if (visitor.visitTypeReferenceExpression(this)) return + annotations.acceptList(visitor) + visitor.afterVisitTypeReferenceExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitTypeReferenceExpression(this, data) + + override fun asLogString() = log("name = ${type.name}") + + override fun asRenderString(): String = type.name +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UUnaryExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UUnaryExpression.kt new file mode 100644 index 000000000000..83ca5c947495 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UUnaryExpression.kt @@ -0,0 +1,92 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.internal.log +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor + +interface UUnaryExpression : UExpression { + /** + * Returns the expression operand. + */ + val operand: UExpression + + /** + * Returns the expression operator. + */ + val operator: UastOperator + + /** + * Returns the operator identifier. + */ + val operatorIdentifier: UIdentifier? + + /** + * Resolve the operator method. + * + * @return the resolved method, or null if the method can't be resolved, or if the expression is not a method call. + */ + fun resolveOperator(): PsiMethod? + + override fun accept(visitor: UastVisitor) { + if (visitor.visitUnaryExpression(this)) return + annotations.acceptList(visitor) + operand.accept(visitor) + visitor.afterVisitUnaryExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitUnaryExpression(this, data) +} + +interface UPrefixExpression : UUnaryExpression { + override val operator: UastPrefixOperator + + override fun accept(visitor: UastVisitor) { + if (visitor.visitPrefixExpression(this)) return + annotations.acceptList(visitor) + operand.accept(visitor) + visitor.afterVisitPrefixExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitPrefixExpression(this, data) + + override fun asLogString() = log("operator = $operator") + + override fun asRenderString() = operator.text + operand.asRenderString() +} + +interface UPostfixExpression : UUnaryExpression { + override val operator: UastPostfixOperator + + override fun accept(visitor: UastVisitor) { + if (visitor.visitPostfixExpression(this)) return + annotations.acceptList(visitor) + operand.accept(visitor) + visitor.afterVisitPostfixExpression(this) + } + + override fun accept(visitor: UastTypedVisitor, data: D) = + visitor.visitPostfixExpression(this, data) + + override fun asLogString() = log("operator = $operator") + + override fun asRenderString() = operand.asRenderString() + operator.text +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/uastLiteralUtils.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/uastLiteralUtils.kt new file mode 100644 index 000000000000..e8dec4910a75 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/uastLiteralUtils.kt @@ -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. + */ +@file:JvmName("UastLiteralUtils") +package org.jetbrains.uast + +/** + * Checks if the [UElement] is a null literal. + * + * @return true if the receiver is a null literal, false otherwise. + */ +fun UElement.isNullLiteral(): Boolean = this is ULiteralExpression && this.isNull + +/** + * Checks if the [UElement] is a boolean literal. + * + * @return true if the receiver is a boolean literal, false otherwise. + */ +fun UElement.isBooleanLiteral(): Boolean = this is ULiteralExpression && this.isBoolean + +/** + * Checks if the [UElement] is a `true` boolean literal. + * + * @return true if the receiver is a `true` boolean literal, false otherwise. + */ +fun UElement.isTrueLiteral(): Boolean = this is ULiteralExpression && this.isBoolean && this.value == true + +/** + * Checks if the [UElement] is a `false` boolean literal. + * + * @return true if the receiver is a `false` boolean literal, false otherwise. + */ +fun UElement.isFalseLiteral(): Boolean = this is ULiteralExpression && this.isBoolean && this.value == false + +/** + * Checks if the [UElement] is a [String] literal. + * + * @return true if the receiver is a [String] literal, false otherwise. + */ +fun UElement.isStringLiteral(): Boolean = this is ULiteralExpression && this.isString + +/** + * Returns the [String] literal value. + * + * @return literal text if the receiver is a valid [String] literal, null otherwise. + */ +fun UElement.getValueIfStringLiteral(): String? = + if (isStringLiteral()) (this as ULiteralExpression).value as String else null + +/** + * Checks if the [UElement] is a [Number] literal (Integer, Long, Float, Double, etc.). + * + * @return true if the receiver is a [Number] literal, false otherwise. + */ +fun UElement.isNumberLiteral(): Boolean = this is ULiteralExpression && this.value is Number + +/** + * Checks if the [UElement] is an integral literal (is an [Integer], [Long], [Short], [Char] or [Byte]). + * + * @return true if the receiver is an integral literal, false otherwise. + */ +fun UElement.isIntegralLiteral(): Boolean = this is ULiteralExpression && when (value) { + is Int -> true + is Long -> true + is Short -> true + is Char -> true + is Byte -> true + else -> false +} + +/** + * Returns the integral value of the literal. + * + * @return long representation of the literal expression value, + * 0 if the receiver literal expression is not a integral one. + */ +fun ULiteralExpression.getLongValue(): Long = value.let { + when (it) { + is Long -> it + is Int -> it.toLong() + is Short -> it.toLong() + is Char -> it.toLong() + is Byte -> it.toLong() + else -> 0 + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/internal/implementationUtils.kt b/uast/uast-common/src/org/jetbrains/uast/internal/implementationUtils.kt new file mode 100644 index 000000000000..5c5301a15cbd --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/internal/implementationUtils.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast.internal + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.visitor.UastVisitor + +fun List.acceptList(visitor: UastVisitor) { + for (element in this) { + element.accept(visitor) + } +} + +@Suppress("unused") +inline fun T.log(text: String = ""): String { + val className = T::class.java.simpleName + return if (text.isEmpty()) className else "$className ($text)" +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/internal/internalUastUtils.kt b/uast/uast-common/src/org/jetbrains/uast/internal/internalUastUtils.kt new file mode 100644 index 000000000000..24cf3cfd514b --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/internal/internalUastUtils.kt @@ -0,0 +1,45 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiModifierListOwner +import com.intellij.psi.PsiType + +internal val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n" + +val String.withMargin: String + get() = lines().joinToString(LINE_SEPARATOR) { " " + it } + +internal operator fun String.times(n: Int) = this.repeat(n) + +internal fun List.asLogString() = joinToString(LINE_SEPARATOR) { it.asLogString().withMargin } + +internal tailrec fun UExpression.unwrapParenthesis(): UExpression = when (this) { + is UParenthesizedExpression -> expression.unwrapParenthesis() + else -> this +} + +internal fun lz(f: () -> T) = lazy(LazyThreadSafetyMode.NONE, f) + +internal val PsiType.name: String + get() = getCanonicalText(false) + + +internal fun PsiModifierListOwner.renderModifiers(): String { + val modifiers = PsiModifier.MODIFIERS.filter { hasModifierProperty(it) }.joinToString(" ") + return if (modifiers.isEmpty()) "" else modifiers + " " +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryExpressionWithTypeKind.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryExpressionWithTypeKind.kt new file mode 100644 index 000000000000..1e386ff0e3db --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryExpressionWithTypeKind.kt @@ -0,0 +1,37 @@ +/* + * 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. + */ +@file:JvmName("UastBinaryExpressionWithTypeUtils") +package org.jetbrains.uast + +/** + * Kinds of [UBinaryExpressionWithType]. + * Examples: type casts, instance checks. + */ +open class UastBinaryExpressionWithTypeKind(val name: String) { + open class TypeCast(name: String) : UastBinaryExpressionWithTypeKind(name) + open class InstanceCheck(name: String) : UastBinaryExpressionWithTypeKind(name) + + companion object { + @JvmField + val TYPE_CAST = TypeCast("as") + + @JvmField + val INSTANCE_CHECK = InstanceCheck("is") + + @JvmField + val UNKNOWN = UastBinaryExpressionWithTypeKind("") + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryOperator.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryOperator.kt new file mode 100644 index 000000000000..e68be7e32575 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastBinaryOperator.kt @@ -0,0 +1,133 @@ +/* + * 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 org.jetbrains.uast + +/** + * Kinds of operators in [UBinaryExpression]. + */ +open class UastBinaryOperator(override val text: String): UastOperator { + class LogicalOperator(text: String): UastBinaryOperator(text) + class ComparisonOperator(text: String): UastBinaryOperator(text) + class ArithmeticOperator(text: String): UastBinaryOperator(text) + class BitwiseOperator(text: String): UastBinaryOperator(text) + class AssignOperator(text: String): UastBinaryOperator(text) + + companion object { + @JvmField + val ASSIGN = AssignOperator("=") + + @JvmField + val PLUS = ArithmeticOperator("+") + + @JvmField + val MINUS = ArithmeticOperator("-") + + @JvmField + val MULTIPLY = ArithmeticOperator("*") + + @JvmField + val DIV = ArithmeticOperator("/") + + @JvmField + val MOD = ArithmeticOperator("%") + + @JvmField + val LOGICAL_OR = LogicalOperator("||") + + @JvmField + val LOGICAL_AND = LogicalOperator("&&") + + @JvmField + val BITWISE_OR = BitwiseOperator("|") + + @JvmField + val BITWISE_AND = BitwiseOperator("&") + + @JvmField + val BITWISE_XOR = BitwiseOperator("^") + + @JvmField + val EQUALS = ComparisonOperator("==") + + @JvmField + val NOT_EQUALS = ComparisonOperator("!=") + + @JvmField + val IDENTITY_EQUALS = ComparisonOperator("===") + + @JvmField + val IDENTITY_NOT_EQUALS = ComparisonOperator("!==") + + @JvmField + val GREATER = ComparisonOperator(">") + + @JvmField + val GREATER_OR_EQUALS = ComparisonOperator(">=") + + @JvmField + val LESS = ComparisonOperator("<") + + @JvmField + val LESS_OR_EQUALS = ComparisonOperator("<=") + + @JvmField + val SHIFT_LEFT = BitwiseOperator("<<") + + @JvmField + val SHIFT_RIGHT = BitwiseOperator(">>") + + @JvmField + val UNSIGNED_SHIFT_RIGHT = BitwiseOperator(">>>") + + @JvmField + val OTHER = UastBinaryOperator("") + + @JvmField + val PLUS_ASSIGN = AssignOperator("+=") + + @JvmField + val MINUS_ASSIGN = AssignOperator("-=") + + @JvmField + val MULTIPLY_ASSIGN = AssignOperator("*=") + + @JvmField + val DIVIDE_ASSIGN = AssignOperator("/=") + + @JvmField + val REMAINDER_ASSIGN = AssignOperator("%=") + + @JvmField + val AND_ASSIGN = AssignOperator("&=") + + @JvmField + val XOR_ASSIGN = AssignOperator("^=") + + @JvmField + val OR_ASSIGN = AssignOperator("|=") + + @JvmField + val SHIFT_LEFT_ASSIGN = AssignOperator("<<=") + + @JvmField + val SHIFT_RIGHT_ASSIGN = AssignOperator(">>=") + + @JvmField + val UNSIGNED_SHIFT_RIGHT_ASSIGN = AssignOperator(">>>=") + } + + override fun toString() = text +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastCallKind.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastCallKind.kt new file mode 100644 index 000000000000..9d069dc3a447 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastCallKind.kt @@ -0,0 +1,47 @@ +/* + * 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 org.jetbrains.uast + +/** + * Kinds of [UCallExpression]. + */ +open class UastCallKind(val name: String) { + companion object { + @JvmField + val METHOD_CALL = UastCallKind("method_call") + + @JvmField + val CONSTRUCTOR_CALL = UastCallKind("constructor_call") + + @JvmField + val NEW_ARRAY_WITH_DIMENSIONS = UastCallKind("new_array_with_dimensions") + + /** + * Initializer parts are available in call expression as value arguments. + * [NEW_ARRAY_WITH_INITIALIZER] is a top-level initializer. In case of multi-dimensional arrays, inner initializers + * have type of [NESTED_ARRAY_INITIALIZER]. + */ + @JvmField + val NEW_ARRAY_WITH_INITIALIZER = UastCallKind("new_array_with_initializer") + + @JvmField + val NESTED_ARRAY_INITIALIZER = UastCallKind("array_initializer") + } + + override fun toString(): String{ + return "UastCallKind(name='$name')" + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastClassKind.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastClassKind.kt new file mode 100644 index 000000000000..563c8fb0a2fe --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastClassKind.kt @@ -0,0 +1,43 @@ +/* + * 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 org.jetbrains.uast + +/** + * Kinds of [UClass]. + */ +open class UastClassKind(val text: String) { + companion object { + @JvmField + val CLASS = UastClassKind("class") + + @JvmField + val INTERFACE = UastClassKind("interface") + + @JvmField + val ANNOTATION = UastClassKind("annotation") + + @JvmField + val ENUM = UastClassKind("enum") + + @JvmField + val OBJECT = UastClassKind("object") + } + + override fun toString(): String{ + return "UastClassKind(text='$text')" + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastOperator.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastOperator.kt new file mode 100644 index 000000000000..790be93bc134 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastOperator.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast + +/** + * Uast operator base interface. + * + * @see [UastPrefixOperator], [UastPostfixOperator], [UastBinaryOperator] + */ +interface UastOperator { + /** + * Returns the operator text to render in [UElement.asRenderString]. + */ + val text: String +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastPostfixOperator.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastPostfixOperator.kt new file mode 100644 index 000000000000..db9342a56e6e --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastPostfixOperator.kt @@ -0,0 +1,34 @@ +/* + * 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 org.jetbrains.uast + +/** + * [UPostfixExpression] operators. + */ +open class UastPostfixOperator(override val text: String): UastOperator { + companion object { + @JvmField + val INC = UastPostfixOperator("++") + + @JvmField + val DEC = UastPostfixOperator("--") + + @JvmField + val UNKNOWN = UastPostfixOperator("") + } + + override fun toString() = text +} diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastPrefixOperator.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastPrefixOperator.kt new file mode 100644 index 000000000000..a6ea6e94c0bc --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastPrefixOperator.kt @@ -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 org.jetbrains.uast + +/** + * [UPrefixExpression] operators. + */ +class UastPrefixOperator(override val text: String): UastOperator { + companion object { + @JvmField + val INC = UastPrefixOperator("++") + + @JvmField + val DEC = UastPrefixOperator("--") + + @JvmField + val UNARY_MINUS = UastPrefixOperator("-") + + @JvmField + val UNARY_PLUS = UastPrefixOperator("+") + + @JvmField + val LOGICAL_NOT = UastPrefixOperator("!") + + @JvmField + val BITWISE_NOT = UastPrefixOperator("~") + + @JvmField + val UNKNOWN = UastPrefixOperator("") + } + + override fun toString() = text +} diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastQualifiedExpressionAccessType.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastQualifiedExpressionAccessType.kt new file mode 100644 index 000000000000..1b7115423810 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastQualifiedExpressionAccessType.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast + +/** + * Access types of [UQualifiedReferenceExpression]. + * Additional type examples: Kotlin safe call (?.). + */ +open class UastQualifiedExpressionAccessType(val name: String) { + companion object { + @JvmField + val SIMPLE = UastQualifiedExpressionAccessType(".") + } + + override fun toString(): String{ + return "UastQualifiedExpressionAccessType(name='$name')" + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastSpecialExpressionKind.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastSpecialExpressionKind.kt new file mode 100644 index 000000000000..83c041a7b69f --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastSpecialExpressionKind.kt @@ -0,0 +1,25 @@ +/* + * 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 org.jetbrains.uast + +/** + * Kinds of [UExpressionList]. + */ +open class UastSpecialExpressionKind(val name: String) { + override fun toString(): String{ + return "UastSpecialExpressionKind(name='$name')" + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/kinds/UastVisibility.kt b/uast/uast-common/src/org/jetbrains/uast/kinds/UastVisibility.kt new file mode 100644 index 000000000000..124071a87ccd --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/kinds/UastVisibility.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast + +import com.intellij.psi.PsiLocalVariable +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiModifierListOwner + +enum class UastVisibility(val text: String) { + PUBLIC("public"), + PRIVATE("private"), + PROTECTED("protected"), + PACKAGE_LOCAL("packageLocal"), + LOCAL("local"); + + override fun toString() = text + + companion object { + operator fun get(declaration: PsiModifierListOwner): UastVisibility { + if (declaration.hasModifierProperty(PsiModifier.PUBLIC)) return UastVisibility.PUBLIC + if (declaration.hasModifierProperty(PsiModifier.PROTECTED)) return UastVisibility.PROTECTED + if (declaration.hasModifierProperty(PsiModifier.PRIVATE)) return UastVisibility.PRIVATE + if (declaration is PsiLocalVariable) return UastVisibility.LOCAL + return UastVisibility.PACKAGE_LOCAL + } + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/psi/UElementWithLocation.kt b/uast/uast-common/src/org/jetbrains/uast/psi/UElementWithLocation.kt new file mode 100644 index 000000000000..fa47f99f862e --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/psi/UElementWithLocation.kt @@ -0,0 +1,21 @@ +/* + * 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 org.jetbrains.uast.psi + +import com.intellij.openapi.util.Segment +import org.jetbrains.uast.UElement + +interface UElementWithLocation : UElement, Segment \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/psi/UastPsiParameterNotResolved.kt b/uast/uast-common/src/org/jetbrains/uast/psi/UastPsiParameterNotResolved.kt new file mode 100644 index 000000000000..b1452f80b288 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/psi/UastPsiParameterNotResolved.kt @@ -0,0 +1,26 @@ +/* + * 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 org.jetbrains.uast.psi + +import com.intellij.lang.Language +import com.intellij.psi.PsiElement +import com.intellij.psi.impl.light.LightParameter +import org.jetbrains.uast.UastErrorType + +class UastPsiParameterNotResolved( + declarationScope: PsiElement, + language: Language +) : LightParameter("error", UastErrorType, declarationScope, language) \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/qualifiedUtils.kt b/uast/uast-common/src/org/jetbrains/uast/qualifiedUtils.kt new file mode 100644 index 000000000000..f63c35b68d0a --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/qualifiedUtils.kt @@ -0,0 +1,199 @@ +/* + * 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. + */ +@file:JvmMultifileClass +@file:JvmName("UastUtils") +package org.jetbrains.uast + +import org.jetbrains.uast.visitor.UastVisitor + +/** + * Get the topmost parent qualified expression for the call expression. + * + * Example 1: + * Code: variable.call(args) + * Call element: E = call(args) + * Qualified parent (return value): Q = [getQualifiedCallElement](E) = variable.call(args) + * + * Example 2: + * Code: call(args) + * Call element: E = call(args) + * Qualified parent (return value): Q = [getQualifiedCallElement](E) = call(args) (no qualifier) + * + * @return containing qualified expression if the call is a child of the qualified expression, call element otherwise. + */ +fun UExpression.getQualifiedParentOrThis(): UExpression { + fun findParent(current: UExpression?, previous: UExpression): UExpression? = when (current) { + is UQualifiedReferenceExpression -> { + if (current.selector == previous) + findParent(current.uastParent as? UExpression, current) ?: current + else + previous + } + is UParenthesizedExpression -> findParent(current.expression, previous) ?: previous + else -> null + } + + return findParent(uastParent as? UExpression, this) ?: this +} + + +fun UExpression.asQualifiedPath(): List? { + if (this is USimpleNameReferenceExpression) { + return listOf(this.identifier) + } else if (this !is UQualifiedReferenceExpression) { + return null + } + + var error = false + val list = mutableListOf() + fun addIdentifiers(expr: UQualifiedReferenceExpression) { + val receiver = expr.receiver.unwrapParenthesis() + val selector = expr.selector as? USimpleNameReferenceExpression ?: run { error = true; return } + when (receiver) { + is UQualifiedReferenceExpression -> addIdentifiers(receiver) + is USimpleNameReferenceExpression -> list += receiver.identifier + else -> { + error = true + return + } + } + list += selector.identifier + } + + addIdentifiers(this) + return if (error) null else list +} + +/** + * Return the list of qualified expressions. + * + * Example: + * Code: obj.call(param).anotherCall(param2).getter + * Qualified chain: [obj, call(param), anotherCall(param2), getter] + * + * @return list of qualified expressions, or the empty list if the received expression is not a qualified expression. + */ +fun UExpression?.getQualifiedChain(): List { + fun collect(expr: UQualifiedReferenceExpression, chains: MutableList) { + val receiver = expr.receiver.unwrapParenthesis() + if (receiver is UQualifiedReferenceExpression) { + collect(receiver, chains) + } else { + chains += receiver + } + + val selector = expr.selector.unwrapParenthesis() + if (selector is UQualifiedReferenceExpression) { + collect(selector, chains) + } else { + chains += selector + } + } + + if (this == null) return emptyList() + val qualifiedExpression = this as? UQualifiedReferenceExpression ?: return listOf(this) + val chains = mutableListOf() + collect(qualifiedExpression, chains) + return chains +} + +/** + * Return the outermost qualified expression. + * + * @return the outermost qualified expression, + * this element if the parent expression is not a qualified expression, + * or null if the element is not a qualified expression. + * + * Example: + * Code: a.b.c(asd).g + * Call element: c(asd) + * Outermost qualified (return value): a.b.c(asd).g + */ +fun UExpression.getOutermostQualified(): UQualifiedReferenceExpression? { + tailrec fun getOutermostQualified(current: UElement?, previous: UExpression): UQualifiedReferenceExpression? = when (current) { + is UQualifiedReferenceExpression -> getOutermostQualified(current.uastParent, current) + is UParenthesizedExpression -> getOutermostQualified(current.uastParent, previous) + else -> if (previous is UQualifiedReferenceExpression) previous else null + } + + return getOutermostQualified(this.uastParent, this) +} + +/** + * Checks if the received expression is a qualified chain of identifiers, and the trailing part of such chain is [fqName]. + * + * @param fqName the chain part to check against. Sequence of identifiers, separated by dot ('.'). Example: "com.example". + * @return true, if the received expression is a qualified chain of identifiers, and the trailing part of such chain is [fqName]. + */ +fun UExpression.matchesQualified(fqName: String): Boolean { + val identifiers = this.asQualifiedPath() ?: return false + val passedIdentifiers = fqName.trim('.').split('.') + return identifiers == passedIdentifiers +} + +/** + * Checks if the received expression is a qualified chain of identifiers, and the leading part of such chain is [fqName]. + * + * @param fqName the chain part to check against. Sequence of identifiers, separated by dot ('.'). Example: "com.example". + * @return true, if the received expression is a qualified chain of identifiers, and the leading part of such chain is [fqName]. + */ +fun UExpression.startsWithQualified(fqName: String): Boolean { + val identifiers = this.asQualifiedPath() ?: return false + val passedIdentifiers = fqName.trim('.').split('.') + if (identifiers.size < passedIdentifiers.size) return false + passedIdentifiers.forEachIndexed { i, passedIdentifier -> + if (passedIdentifier != identifiers[i]) return false + } + return true +} + +/** + * Checks if the received expression is a qualified chain of identifiers, and the trailing part of such chain is [fqName]. + * + * @param fqName the chain part to check against. Sequence of identifiers, separated by dot ('.'). Example: "com.example". + * @return true, if the received expression is a qualified chain of identifiers, and the trailing part of such chain is [fqName]. + */ +fun UExpression.endsWithQualified(fqName: String): Boolean { + val identifiers = this.asQualifiedPath()?.asReversed() ?: return false + val passedIdentifiers = fqName.trim('.').split('.').asReversed() + if (identifiers.size < passedIdentifiers.size) return false + passedIdentifiers.forEachIndexed { i, passedIdentifier -> + if (passedIdentifier != identifiers[i]) return false + } + return true +} + +fun UElement.asRecursiveLogString(): String { + val stringBuilder = StringBuilder() + val indent = " " + + accept(object : UastVisitor { + private var level = 0 + + override fun visitElement(node: UElement): Boolean { + stringBuilder.append(indent.repeat(level)) + stringBuilder.appendln(node.asLogString()) + level++ + return false + } + + override fun afterVisitElement(node: UElement) { + super.afterVisitElement(node) + level-- + } + }) + return stringBuilder.toString() +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/util/callUtils.kt b/uast/uast-common/src/org/jetbrains/uast/util/callUtils.kt new file mode 100644 index 000000000000..dc9eb32792af --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/util/callUtils.kt @@ -0,0 +1,43 @@ +/* + * 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. + */ + +@file:JvmName("UastExpressionUtils") +package org.jetbrains.uast.util + +import org.jetbrains.uast.* + +fun UElement.isConstructorCall() = (this as? UCallExpression)?.kind == UastCallKind.CONSTRUCTOR_CALL + +fun UElement.isMethodCall() = (this as? UCallExpression)?.kind == UastCallKind.METHOD_CALL + +fun UElement.isNewArray() = isNewArrayWithDimensions() || isNewArrayWithInitializer() + +fun UElement.isNewArrayWithDimensions() = (this as? UCallExpression)?.kind == UastCallKind.NEW_ARRAY_WITH_DIMENSIONS + +fun UElement.isNewArrayWithInitializer() = (this as? UCallExpression)?.kind == UastCallKind.NEW_ARRAY_WITH_INITIALIZER + +@Deprecated("Use isArrayInitializer()", ReplaceWith("isArrayInitializer()")) +fun UElement.isNestedArrayInitializer() = isArrayInitializer() + +fun UElement.isArrayInitializer() = (this as? UCallExpression)?.kind == UastCallKind.NESTED_ARRAY_INITIALIZER + +fun UElement.isTypeCast() = (this as? UBinaryExpressionWithType)?.operationKind is UastBinaryExpressionWithTypeKind.TypeCast + +fun UElement.isInstanceCheck() = (this as? UBinaryExpressionWithType)?.operationKind is UastBinaryExpressionWithTypeKind.InstanceCheck + +fun UElement.isAssignment() = (this as? UBinaryExpression)?.operator is UastBinaryOperator.AssignOperator + +fun UVariable.isResourceVariable() = uastParent is UTryExpression diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UCallResultValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UCallResultValue.kt new file mode 100644 index 000000000000..1b56a2fe5bd9 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UCallResultValue.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast.values + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UResolvable + +// Value of something resolvable (e.g. call or property access) +// that we cannot or do not want to evaluate +class UCallResultValue(val resolvable: UResolvable, val arguments: List) : UValueBase(), UDependency { + override fun equals(other: Any?) = other is UCallResultValue && resolvable == other.resolvable && arguments == other.arguments + + override fun hashCode() = resolvable.hashCode() + + override fun toString(): String { + return "external ${(resolvable as? UElement)?.asRenderString() ?: "???"}(${arguments.joinToString()})" + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UConstant.kt b/uast/uast-common/src/org/jetbrains/uast/values/UConstant.kt new file mode 100644 index 000000000000..9cc7d52b5dd8 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UConstant.kt @@ -0,0 +1,426 @@ +/* + * 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 org.jetbrains.uast.values + +import com.intellij.psi.PsiEnumConstant +import com.intellij.psi.PsiType +import org.jetbrains.uast.* + +interface UConstant : UValue { + val value: Any? + + val source: UExpression? + + // Used for string concatenation + fun asString(): String + + // Used for logging / debugging purposes + override fun toString(): String +} + +abstract class UAbstractConstant : UValueBase(), UConstant { + override fun valueEquals(other: UValue) = when (other) { + this -> UBooleanConstant.True + is UConstant -> UBooleanConstant.False + else -> super.valueEquals(other) + } + + override fun equals(other: Any?) = other is UAbstractConstant && value == other.value + + override fun hashCode() = value?.hashCode() ?: 0 + + override fun toString() = "$value" + + override fun asString() = toString() +} + +enum class UNumericType(val prefix: String = "") { + BYTE("(byte)"), + SHORT("(short)"), + INT(), + LONG("(long)"), + FLOAT("(float)"), + DOUBLE(); + + fun merge(other: UNumericType): UNumericType { + if (this == DOUBLE || other == DOUBLE) return DOUBLE + if (this == FLOAT || other == FLOAT) return FLOAT + if (this == LONG || other == LONG) return LONG + return INT + } +} + +abstract class UNumericConstant(val type: UNumericType, override val source: ULiteralExpression?) : UAbstractConstant() { + override abstract val value: Number + + override fun toString() = "${type.prefix}$value" + + override fun asString() = "$value" +} + +private fun PsiType.toNumeric(): UNumericType = when (this) { + PsiType.LONG -> UNumericType.LONG + PsiType.INT -> UNumericType.INT + PsiType.SHORT -> UNumericType.SHORT + PsiType.BYTE -> UNumericType.BYTE + PsiType.DOUBLE -> UNumericType.DOUBLE + PsiType.FLOAT -> UNumericType.FLOAT + else -> throw AssertionError("Conversion is impossible for type $canonicalText") +} + +private fun Int.asType(type: UNumericType): Int = when (type) { + UNumericType.BYTE -> toByte().toInt() + UNumericType.SHORT -> toShort().toInt() + else -> this +} + +class UIntConstant( + rawValue: Int, type: UNumericType = UNumericType.INT, override val source: ULiteralExpression? = null +) : UNumericConstant(type, source) { + + init { + when (type) { + UNumericType.INT, UNumericType.SHORT, UNumericType.BYTE -> {} + else -> throw AssertionError("Incorrect UIntConstant type: $type") + } + } + + override val value: Int = rawValue.asType(type) + + constructor(value: Int, type: PsiType): this(value, type.toNumeric()) + + override fun plus(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value + other.value, type.merge(other.type)) + is ULongConstant -> other + this + is UFloatConstant -> other + this + else -> super.plus(other) + } + + override fun times(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value * other.value, type.merge(other.type)) + is ULongConstant -> other * this + is UFloatConstant -> other * this + else -> super.times(other) + } + + override fun div(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value / other.value, type.merge(other.type)) + is ULongConstant -> ULongConstant(value / other.value) + is UFloatConstant -> UFloatConstant.create(value / other.value, type.merge(other.type)) + else -> super.div(other) + } + + override fun mod(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value % other.value, type.merge(other.type)) + is ULongConstant -> ULongConstant(value % other.value) + is UFloatConstant -> UFloatConstant.create(value % other.value, type.merge(other.type)) + else -> super.mod(other) + } + + override fun unaryMinus() = UIntConstant(-value, type) + + override fun greater(other: UValue) = when (other) { + is UIntConstant -> UBooleanConstant.valueOf(value > other.value) + is ULongConstant -> UBooleanConstant.valueOf(value > other.value) + is UFloatConstant -> UBooleanConstant.valueOf(value > other.value) + else -> super.greater(other) + } + + override fun inc() = UIntConstant(value + 1, type) + + override fun dec() = UIntConstant(value - 1, type) + + override fun bitwiseAnd(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value and other.value, type.merge(other.type)) + else -> super.bitwiseAnd(other) + } + + override fun bitwiseOr(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value or other.value, type.merge(other.type)) + else -> super.bitwiseOr(other) + } + + override fun bitwiseXor(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value xor other.value, type.merge(other.type)) + else -> super.bitwiseXor(other) + } + + override fun shl(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value shl other.value, type.merge(other.type)) + else -> super.shl(other) + } + + override fun shr(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value shr other.value, type.merge(other.type)) + else -> super.shr(other) + } + + override fun ushr(other: UValue) = when (other) { + is UIntConstant -> UIntConstant(value ushr other.value, type.merge(other.type)) + else -> super.ushr(other) + } +} + +class ULongConstant(override val value: Long, source: ULiteralExpression? = null) : UNumericConstant(UNumericType.LONG, source) { + override fun plus(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value + other.value) + is UIntConstant -> ULongConstant(value + other.value) + is UFloatConstant -> other + this + else -> super.plus(other) + } + + override fun times(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value * other.value) + is UIntConstant -> ULongConstant(value * other.value) + is UFloatConstant -> other * this + else -> super.times(other) + } + + override fun div(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value / other.value) + is UIntConstant -> ULongConstant(value / other.value) + is UFloatConstant -> UFloatConstant.create(value / other.value, type.merge(other.type)) + else -> super.div(other) + } + + override fun mod(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value % other.value) + is UIntConstant -> ULongConstant(value % other.value) + is UFloatConstant -> UFloatConstant.create(value % other.value, type.merge(other.type)) + else -> super.mod(other) + } + + override fun unaryMinus() = ULongConstant(-value) + + override fun greater(other: UValue) = when (other) { + is ULongConstant -> UBooleanConstant.valueOf(value > other.value) + is UIntConstant -> UBooleanConstant.valueOf(value > other.value) + is UFloatConstant -> UBooleanConstant.valueOf(value > other.value) + else -> super.greater(other) + } + + override fun inc() = ULongConstant(value + 1) + + override fun dec() = ULongConstant(value - 1) + + override fun bitwiseAnd(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value and other.value) + else -> super.bitwiseAnd(other) + } + + override fun bitwiseOr(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value or other.value) + else -> super.bitwiseOr(other) + } + + override fun bitwiseXor(other: UValue) = when (other) { + is ULongConstant -> ULongConstant(value xor other.value) + else -> super.bitwiseXor(other) + } + + override fun shl(other: UValue) = when (other) { + is UIntConstant -> ULongConstant(value shl other.value) + else -> super.shl(other) + } + + override fun shr(other: UValue) = when (other) { + is UIntConstant -> ULongConstant(value shr other.value) + else -> super.shr(other) + } + + override fun ushr(other: UValue) = when (other) { + is UIntConstant -> ULongConstant(value ushr other.value) + else -> super.ushr(other) + } +} + +open class UFloatConstant protected constructor( + override val value: Double, type: UNumericType = UNumericType.DOUBLE, source: ULiteralExpression? = null +) : UNumericConstant(type, source) { + + override fun plus(other: UValue) = when (other) { + is ULongConstant -> create(value + other.value, type.merge(other.type)) + is UIntConstant -> create(value + other.value, type.merge(other.type)) + is UFloatConstant -> create(value + other.value, type.merge(other.type)) + else -> super.plus(other) + } + + override fun times(other: UValue) = when (other) { + is ULongConstant -> create(value * other.value, type.merge(other.type)) + is UIntConstant -> create(value * other.value, type.merge(other.type)) + is UFloatConstant -> create(value * other.value, type.merge(other.type)) + else -> super.times(other) + } + + override fun div(other: UValue) = when (other) { + is ULongConstant -> create(value / other.value, type.merge(other.type)) + is UIntConstant -> create(value / other.value, type.merge(other.type)) + is UFloatConstant -> create(value / other.value, type.merge(other.type)) + else -> super.div(other) + } + + override fun mod(other: UValue) = when (other) { + is ULongConstant -> create(value % other.value, type.merge(other.type)) + is UIntConstant -> create(value % other.value, type.merge(other.type)) + is UFloatConstant -> create(value % other.value, type.merge(other.type)) + else -> super.mod(other) + } + + override fun greater(other: UValue) = when (other) { + is ULongConstant -> UBooleanConstant.valueOf(value > other.value) + is UIntConstant -> UBooleanConstant.valueOf(value > other.value) + is UFloatConstant -> UBooleanConstant.valueOf(value > other.value) + else -> super.greater(other) + } + + override fun unaryMinus() = create(-value, type) + + override fun inc() = create(value + 1, type) + + override fun dec() = create(value - 1, type) + + companion object { + fun create(value: Double, type: UNumericType = UNumericType.DOUBLE, source: ULiteralExpression? = null) = + when (type) { + UNumericType.DOUBLE, UNumericType.FLOAT -> { + if (value.isNaN()) UNaNConstant.valueOf(type) + else UFloatConstant(value, type, source) + } + else -> throw AssertionError("Incorrect UFloatConstant type: $type") + } + + fun create(value: Double, type: PsiType) = create(value, type.toNumeric()) + } +} + +sealed class UNaNConstant(type: UNumericType = UNumericType.DOUBLE) : UFloatConstant(kotlin.Double.NaN, type) { + object Float : UNaNConstant(UNumericType.FLOAT) + + object Double : UNaNConstant(UNumericType.DOUBLE) + + override fun greater(other: UValue) = UBooleanConstant.False + + override fun less(other: UValue) = UBooleanConstant.False + + override fun greaterOrEquals(other: UValue) = UBooleanConstant.False + + override fun lessOrEquals(other: UValue) = UBooleanConstant.False + + override fun valueEquals(other: UValue) = UBooleanConstant.False + + companion object { + fun valueOf(type: UNumericType) = when (type) { + UNumericType.DOUBLE -> Double + UNumericType.FLOAT -> Float + else -> throw AssertionError("NaN exists only for Float / Double, but not for $type") + } + } +} + +class UCharConstant(override val value: Char, override val source: ULiteralExpression? = null) : UAbstractConstant() { + override fun plus(other: UValue) = when (other) { + is UIntConstant -> UCharConstant(value + other.value) + is UCharConstant -> UCharConstant(value + other.value.toInt()) + else -> super.plus(other) + } + + override fun minus(other: UValue) = when (other) { + is UIntConstant -> UCharConstant(value - other.value) + is UCharConstant -> UIntConstant(value - other.value) + else -> super.plus(other) + } + + override fun greater(other: UValue) = when (other) { + is UCharConstant -> UBooleanConstant.valueOf(value > other.value) + else -> super.greater(other) + } + + override fun inc() = this + UIntConstant(1) + + override fun dec() = this - UIntConstant(1) + + override fun toString() = "\'$value\'" + + override fun asString() = "$value" +} + +sealed class UBooleanConstant(override val value: Boolean) : UAbstractConstant() { + override val source = null + + object True : UBooleanConstant(true) { + override fun not() = False + + override fun and(other: UValue) = other as? UBooleanConstant ?: super.and(other) + + override fun or(other: UValue) = True + } + + object False : UBooleanConstant(false) { + override fun not() = True + + override fun and(other: UValue) = False + + override fun or(other: UValue) = other as? UBooleanConstant ?: super.or(other) + } + + companion object { + fun valueOf(value: Boolean) = if (value) True else False + } +} + +class UStringConstant(override val value: String, override val source: ULiteralExpression? = null) : UAbstractConstant() { + + override fun plus(other: UValue) = when (other) { + is UConstant -> UStringConstant(value + other.asString()) + else -> super.plus(other) + } + + override fun greater(other: UValue) = when (other) { + is UStringConstant -> UBooleanConstant.valueOf(value > other.value) + else -> super.greater(other) + } + + override fun asString() = value + + override fun toString() = "\"$value\"" +} + +class UEnumEntryValueConstant(override val value: PsiEnumConstant, override val source: USimpleNameReferenceExpression? = null) : UAbstractConstant() { + override fun equals(other: Any?) = + other is UEnumEntryValueConstant && + value.nameIdentifier.text == other.value.nameIdentifier.text && + value.containingClass?.qualifiedName == other.value.containingClass?.qualifiedName + + override fun hashCode(): Int { + var result = 19 + result = result * 13 + value.nameIdentifier.text.hashCode() + result = result * 13 + (value.containingClass?.qualifiedName?.hashCode() ?: 0) + return result + } + + override fun toString() = value.name?.let { "$it (enum entry)" }?: "" + + override fun asString() = value.name ?: "" +} + +class UClassConstant(override val value: PsiType, override val source: UClassLiteralExpression? = null) : UAbstractConstant() { + override fun toString() = value.name +} + +object UNullConstant : UAbstractConstant() { + override val value = null + override val source = null +} diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UDependency.kt b/uast/uast-common/src/org/jetbrains/uast/values/UDependency.kt new file mode 100644 index 000000000000..3d1a9a7a6ac8 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UDependency.kt @@ -0,0 +1,19 @@ +/* + * 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 org.jetbrains.uast.values + +interface UDependency { +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UDependentValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UDependentValue.kt new file mode 100644 index 000000000000..4f9a6c08bf17 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UDependentValue.kt @@ -0,0 +1,137 @@ +/* + * 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 org.jetbrains.uast.values + +open class UDependentValue protected constructor( + val value: UValue, + override val dependencies: Set = emptySet() +) : UValueBase() { + + private fun UValue.unwrap() = (this as? UDependentValue)?.unwrap() ?: this + + private fun unwrap(): UValue = value.unwrap() + + private val dependenciesWithThis: Set + get() = (this as? UDependency)?.let { dependencies + it } ?: dependencies + + private fun wrapBinary(result: UValue, arg: UValue): UValue { + val wrappedDependencies = (arg as? UDependentValue)?.dependenciesWithThis ?: emptySet() + val resultDependencies = dependenciesWithThis + wrappedDependencies + return create(result, resultDependencies) + } + + private fun wrapUnary(result: UValue) = create(result, dependenciesWithThis) + + override fun plus(other: UValue) = wrapBinary(unwrap() + other.unwrap(), other) + + override fun minus(other: UValue) = wrapBinary(unwrap() - other.unwrap(), other) + + override fun times(other: UValue) = wrapBinary(unwrap() * other.unwrap(), other) + + override fun div(other: UValue) = wrapBinary(unwrap() / other.unwrap(), other) + + internal fun inverseDiv(other: UValue) = wrapBinary(other.unwrap() / unwrap(), other) + + override fun mod(other: UValue) = wrapBinary(unwrap() % other.unwrap(), other) + + internal fun inverseMod(other: UValue) = wrapBinary(other.unwrap() % unwrap(), other) + + override fun unaryMinus() = wrapUnary(-unwrap()) + + override fun valueEquals(other: UValue) = wrapBinary(unwrap() valueEquals other.unwrap(), other) + + override fun valueNotEquals(other: UValue) = wrapBinary(unwrap() valueNotEquals other.unwrap(), other) + + override fun not() = wrapUnary(!unwrap()) + + override fun greater(other: UValue) = wrapBinary(unwrap() greater other.unwrap(), other) + + override fun less(other: UValue) = wrapBinary(other.unwrap() greater unwrap(), other) + + override fun inc() = wrapUnary(unwrap().inc()) + + override fun dec() = wrapUnary(unwrap().dec()) + + override fun and(other: UValue) = wrapBinary(unwrap() and other.unwrap(), other) + + override fun or(other: UValue) = wrapBinary(unwrap() or other.unwrap(), other) + + override fun bitwiseAnd(other: UValue) = wrapBinary(unwrap() bitwiseAnd other.unwrap(), other) + + override fun bitwiseOr(other: UValue) = wrapBinary(unwrap() bitwiseOr other.unwrap(), other) + + override fun bitwiseXor(other: UValue) = wrapBinary(unwrap() bitwiseXor other.unwrap(), other) + + override fun shl(other: UValue) = wrapBinary(unwrap() shl other.unwrap(), other) + + internal fun inverseShiftLeft(other: UValue) = wrapBinary(other.unwrap() shl unwrap(), other) + + override fun shr(other: UValue) = wrapBinary(unwrap() shr other.unwrap(), other) + + internal fun inverseShiftRight(other: UValue) = wrapBinary(other.unwrap() shr unwrap(), other) + + override fun ushr(other: UValue) = wrapBinary(unwrap() ushr other.unwrap(), other) + + internal fun inverseShiftRightUnsigned(other: UValue) = + wrapBinary(other.unwrap() ushr unwrap(), other) + + override fun merge(other: UValue) = when (other) { + this -> this + value -> this + is UDependentValue -> { + if (value != other.value) UPhiValue.create(this, other) + else UDependentValue(value, dependencies + other.dependencies) + } + else -> UPhiValue.create(this, other) + } + + override fun toConstant() = value.toConstant() + + open internal fun copy(dependencies: Set) = + if (dependencies == this.dependencies) this else create(value, dependencies) + + override fun coerceConstant(constant: UConstant): UValue = + if (toConstant() == constant) this + else create(value.coerceConstant(constant), dependencies) + + override fun equals(other: Any?) = + other is UDependentValue + && javaClass == other.javaClass + && value == other.value + && dependencies == other.dependencies + + override fun hashCode(): Int { + var result = 31 + result = result * 19 + value.hashCode() + result = result * 19 + dependencies.hashCode() + return result + } + + override fun toString() = + if (dependencies.isNotEmpty()) + "$value" + dependencies.joinToString(prefix = " (depending on: ", postfix = ")", separator = ", ") + else + "$value" + + companion object { + fun create(value: UValue, dependencies: Set): UValue = + if (dependencies.isNotEmpty()) UDependentValue(value, dependencies) + else value + + internal fun UValue.coerceConstant(constant: UConstant): UValue = + (this as? UValueBase)?.coerceConstant(constant) ?: constant + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UNothingValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UNothingValue.kt new file mode 100644 index 000000000000..e966f752c51e --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UNothingValue.kt @@ -0,0 +1,79 @@ +/* + * 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 org.jetbrains.uast.values + +import org.jetbrains.uast.* + +// Something that never can be reached / created +internal class UNothingValue private constructor( + val containingLoopOrSwitch: UExpression?, + val kind: JumpKind +) : UValueBase() { + + constructor(jump: UJumpExpression) : this(jump.containingLoopOrSwitch(), jump.kind()) + + constructor() : this(null, JumpKind.OTHER) + + enum class JumpKind { + BREAK, + CONTINUE, + OTHER; + } + + override val reachable = false + + override fun merge(other: UValue) = when (other) { + is UNothingValue -> { + val mergedLoopOrSwitch = + if (containingLoopOrSwitch == other.containingLoopOrSwitch) containingLoopOrSwitch + else null + val mergedKind = if (mergedLoopOrSwitch == null || kind != other.kind) JumpKind.OTHER else kind + UNothingValue(mergedLoopOrSwitch, mergedKind) + } + else -> super.merge(other) + } + + override fun toString() = "Nothing" + when (kind) { + JumpKind.BREAK -> "(break)" + JumpKind.CONTINUE -> "(continue)" + else -> "" + } + + companion object { + private fun UJumpExpression.containingLoopOrSwitch(): UExpression? { + var containingElement = uastParent + while (containingElement != null) { + if (this is UBreakExpression && label == null && containingElement is USwitchExpression) { + return containingElement + } + if (containingElement is ULoopExpression) { + val containingLabeled = containingElement.uastParent as? ULabeledExpression + if (label == null || label == containingLabeled?.label) { + return containingElement + } + } + containingElement = containingElement.uastParent + } + return null + } + + private fun UExpression.kind(): JumpKind = when (this) { + is UBreakExpression -> JumpKind.BREAK + is UContinueExpression -> JumpKind.CONTINUE + else -> JumpKind.OTHER + } + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UOperand.kt b/uast/uast-common/src/org/jetbrains/uast/values/UOperand.kt new file mode 100644 index 000000000000..9c94c8c4346a --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UOperand.kt @@ -0,0 +1,68 @@ +/* + * 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 org.jetbrains.uast.values + +interface UOperand { + operator fun plus(other: UValue): UValue + + operator fun minus(other: UValue): UValue + + operator fun times(other: UValue): UValue + + operator fun div(other: UValue): UValue + + operator fun mod(other: UValue): UValue + + operator fun unaryMinus(): UValue + + operator fun not(): UValue + + infix fun valueEquals(other: UValue): UValue + + infix fun valueNotEquals(other: UValue): UValue + + infix fun identityEquals(other: UValue): UValue + + infix fun identityNotEquals(other: UValue): UValue + + infix fun greater(other: UValue): UValue + + infix fun less(other: UValue): UValue + + infix fun greaterOrEquals(other: UValue): UValue + + infix fun lessOrEquals(other: UValue): UValue + + fun inc(): UValue + + fun dec(): UValue + + infix fun and(other: UValue): UValue + + infix fun or(other: UValue): UValue + + infix fun bitwiseAnd(other: UValue): UValue + + infix fun bitwiseOr(other: UValue): UValue + + infix fun bitwiseXor(other: UValue): UValue + + infix fun shl(other: UValue): UValue + + infix fun shr(other: UValue): UValue + + infix fun ushr(other: UValue): UValue +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UPhiValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UPhiValue.kt new file mode 100644 index 000000000000..186505e07170 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UPhiValue.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast.values + +class UPhiValue private constructor(val values: Set): UValueBase() { + + override val dependencies: Set = values.flatMapTo(linkedSetOf()) { it.dependencies } + + override fun equals(other: Any?) = other is UPhiValue && values == other.values + + override fun hashCode() = values.hashCode() + + override fun toString() = values.joinToString(prefix = "Phi(", postfix = ")", separator = ", ") + + companion object { + fun create(values: Iterable): UPhiValue { + val flattenedValues = values.flatMapTo(linkedSetOf()) { (it as? UPhiValue)?.values ?: listOf(it) } + if (flattenedValues.size <= 1) { + throw AssertionError("UPhiValue should contain two or more values: $flattenedValues") + } + return UPhiValue(flattenedValues) + } + + fun create(vararg values: UValue) = create(values.asIterable()) + } +} + diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UUndeterminedValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UUndeterminedValue.kt new file mode 100644 index 000000000000..e900df99f7fe --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UUndeterminedValue.kt @@ -0,0 +1,23 @@ +/* + * 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 org.jetbrains.uast.values + +// Something with value that cannot be evaluated +object UUndeterminedValue : UValueBase() { + override fun toString() = "Undetermined" +} + +fun UValue.ifUndetermined(block: () -> UValue) = if (this == UUndeterminedValue) block() else this diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UValue.kt new file mode 100644 index 000000000000..49cabf599489 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UValue.kt @@ -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 org.jetbrains.uast.values + +interface UValue : UOperand { + + fun merge(other: UValue): UValue + + val dependencies: Set + get() = emptySet() + + fun toConstant(): UConstant? + + val reachable: Boolean + + companion object { + val UNREACHABLE: UValue = UNothingValue() + } +} + +fun UValue.toPossibleConstants(): Set { + val results = mutableSetOf() + toPossibleConstants(results) + return results +} + +private fun UValue.toPossibleConstants(result: MutableSet) { + when (this) { + is UDependentValue -> value.toPossibleConstants(result) + is UPhiValue -> values.forEach { it.toPossibleConstants(result) } + else -> toConstant()?.let { result.add(it) } + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UValueBase.kt b/uast/uast-common/src/org/jetbrains/uast/values/UValueBase.kt new file mode 100644 index 000000000000..c41b2800c1d2 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UValueBase.kt @@ -0,0 +1,100 @@ +/* + * 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 org.jetbrains.uast.values + +abstract class UValueBase : UValue { + + override operator fun plus(other: UValue): UValue = + if (other is UDependentValue) other + this else UUndeterminedValue + + override operator fun minus(other: UValue): UValue = this + (-other) + + override operator fun times(other: UValue): UValue = + if (other is UDependentValue) other * this else UUndeterminedValue + + override operator fun div(other: UValue): UValue = + (other as? UDependentValue)?.inverseDiv(this) ?: UUndeterminedValue + + override operator fun mod(other: UValue): UValue = + (other as? UDependentValue)?.inverseMod(this) ?: UUndeterminedValue + + override fun unaryMinus(): UValue = UUndeterminedValue + + override fun valueEquals(other: UValue): UValue = + if (other is UDependentValue || other is UNaNConstant) other.valueEquals(this) else UUndeterminedValue + + override fun valueNotEquals(other: UValue): UValue = !this.valueEquals(other) + + override fun identityEquals(other: UValue): UValue = valueEquals(other) + + override fun identityNotEquals(other: UValue): UValue = !this.identityEquals(other) + + override fun not(): UValue = UUndeterminedValue + + override fun greater(other: UValue): UValue = + if (other is UDependentValue || other is UNaNConstant) other.less(this) else UUndeterminedValue + + override fun less(other: UValue): UValue = other.greater(this) + + override fun greaterOrEquals(other: UValue) = this.greater(other) or this.valueEquals(other) + + override fun lessOrEquals(other: UValue) = this.less(other) or this.valueEquals(other) + + override fun inc(): UValue = UUndeterminedValue + + override fun dec(): UValue = UUndeterminedValue + + override fun and(other: UValue): UValue = + if (other is UDependentValue || other == UBooleanConstant.False) other and this else UUndeterminedValue + + override fun or(other: UValue): UValue = + if (other is UDependentValue || other == UBooleanConstant.True) other or this else UUndeterminedValue + + override fun bitwiseAnd(other: UValue): UValue = + if (other is UDependentValue) other bitwiseAnd this else UUndeterminedValue + + override fun bitwiseOr(other: UValue): UValue = + if (other is UDependentValue) other bitwiseOr this else UUndeterminedValue + + override fun bitwiseXor(other: UValue): UValue = + if (other is UDependentValue) other bitwiseXor this else UUndeterminedValue + + override fun shl(other: UValue): UValue = + (other as? UDependentValue)?.inverseShiftLeft(this) ?: UUndeterminedValue + + override fun shr(other: UValue): UValue = + (other as? UDependentValue)?.inverseShiftRight(this) ?: UUndeterminedValue + + override fun ushr(other: UValue): UValue = + (other as? UDependentValue)?.inverseShiftRightUnsigned(this) ?: UUndeterminedValue + + override fun merge(other: UValue): UValue = when (other) { + this -> this + is UVariableValue -> other.merge(this) + else -> UPhiValue.create(this, other) + } + + override val dependencies: Set + get() = emptySet() + + override fun toConstant(): UConstant? = this as? UConstant + + internal open fun coerceConstant(constant: UConstant): UValue = constant + + override val reachable = true + + override abstract fun toString(): String +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/values/UVariableValue.kt b/uast/uast-common/src/org/jetbrains/uast/values/UVariableValue.kt new file mode 100644 index 000000000000..2185cd9e38ed --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/values/UVariableValue.kt @@ -0,0 +1,104 @@ +/* + * 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 org.jetbrains.uast.values + +import com.intellij.psi.PsiType +import org.jetbrains.uast.UVariable + +class UVariableValue private constructor( + val variable: UVariable, + value: UValue, + dependencies: Set +) : UDependentValue(value, dependencies), UDependency { + + override fun identityEquals(other: UValue): UValue = + if (this == other) super.valueEquals(other) + else when (variable.psi.type) { + PsiType.BYTE, PsiType.FLOAT, PsiType.DOUBLE, PsiType.LONG, + PsiType.SHORT, PsiType.INT, PsiType.CHAR, PsiType.BOOLEAN -> super.valueEquals(other) + + else -> UUndeterminedValue + } + + override fun merge(other: UValue) = when (other) { + this -> this + value -> this + is UVariableValue -> { + if (variable != other.variable || value != other.value) UPhiValue.create(this, other) + else create(variable, value, dependencies + other.dependencies) + } + is UDependentValue -> { + if (value != other.value) UPhiValue.create(this, other) + else create(variable, value, dependencies + other.dependencies) + } + else -> UPhiValue.create(this, other) + } + + override fun copy(dependencies: Set) = + if (dependencies == this.dependencies) this else create(variable, value, dependencies) + + override fun coerceConstant(constant: UConstant): UValue = + if (constant == toConstant()) this + else create(variable, value.coerceConstant(constant), dependencies) + + override fun equals(other: Any?) = + other is UVariableValue + && variable == other.variable + && value == other.value + && dependencies == other.dependencies + + override fun hashCode(): Int { + var result = 31 + result = result * 19 + variable.hashCode() + result = result * 19 + value.hashCode() + result = result * 19 + dependencies.hashCode() + return result + } + + override fun toString() = "(var ${variable.name ?: ""} = ${super.toString()})" + + companion object { + + private fun Set.filterNot(variable: UVariable) = + filterTo(linkedSetOf()) { it !is UVariableValue || variable != it.variable } + + fun create(variable: UVariable, value: UValue, dependencies: Set = emptySet()): UVariableValue { + when (variable.psi.type) { + PsiType.BYTE, PsiType.SHORT -> { + val constant = value.toConstant() + if (constant is UIntConstant && constant.type == UNumericType.INT) { + val castConstant = UIntConstant(constant.value, variable.psi.type) + return create(variable, value.coerceConstant(castConstant), dependencies) + } + } + } + val dependenciesWithoutSelf = dependencies.filterNot(variable) + return when { + value is UVariableValue + && variable == value.variable + && dependenciesWithoutSelf == value.dependencies -> value + + value is UDependentValue -> { + val valueDependencies = value.dependencies.filterNot(variable) + val modifiedValue = value.copy(valueDependencies) + UVariableValue(variable, modifiedValue, dependenciesWithoutSelf) + } + + else -> UVariableValue(variable, value, dependenciesWithoutSelf) + } + } + } +} diff --git a/uast/uast-common/src/org/jetbrains/uast/visitor/DelegatingUastVisitor.kt b/uast/uast-common/src/org/jetbrains/uast/visitor/DelegatingUastVisitor.kt new file mode 100644 index 000000000000..35544f9a0d74 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/visitor/DelegatingUastVisitor.kt @@ -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 org.jetbrains.uast.visitor + +import org.jetbrains.uast.* + + +class DelegatingUastVisitor(private val visitors: List): UastVisitor { + override fun visitElement(node: UElement): Boolean { + return visitors.all { it.visitElement(node) } + } + + override fun visitVariable(node: UVariable): Boolean { + return visitors.all { it.visitVariable(node) } + } + + override fun visitMethod(node: UMethod): Boolean { + return visitors.all { it.visitMethod(node) } + } + + override fun visitLabeledExpression(node: ULabeledExpression): Boolean { + return visitors.all { it.visitLabeledExpression(node) } + } + + override fun visitDeclarationsExpression(node: UDeclarationsExpression): Boolean { + return visitors.all { it.visitDeclarationsExpression(node) } + } + + override fun visitBlockExpression(node: UBlockExpression): Boolean { + return visitors.all { it.visitBlockExpression(node) } + } + + override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression): Boolean { + return visitors.all { it.visitQualifiedReferenceExpression(node) } + } + + override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean { + return visitors.all { it.visitSimpleNameReferenceExpression(node) } + } + + override fun visitTypeReferenceExpression(node: UTypeReferenceExpression): Boolean { + return visitors.all { it.visitTypeReferenceExpression(node) } + } + + override fun visitCallExpression(node: UCallExpression): Boolean { + return visitors.all { it.visitCallExpression(node) } + } + + override fun visitBinaryExpression(node: UBinaryExpression): Boolean { + return visitors.all { it.visitBinaryExpression(node) } + } + + override fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType): Boolean { + return visitors.all { it.visitBinaryExpressionWithType(node) } + } + + override fun visitParenthesizedExpression(node: UParenthesizedExpression): Boolean { + return visitors.all { it.visitParenthesizedExpression(node) } + } + + override fun visitUnaryExpression(node: UUnaryExpression): Boolean { + return visitors.all { it.visitUnaryExpression(node) } + } + + override fun visitPrefixExpression(node: UPrefixExpression): Boolean { + return visitors.all { it.visitPrefixExpression(node) } + } + + override fun visitPostfixExpression(node: UPostfixExpression): Boolean { + return visitors.all { it.visitPostfixExpression(node) } + } + + override fun visitExpressionList(node: UExpressionList): Boolean { + return visitors.all { it.visitExpressionList(node) } + } + + override fun visitIfExpression(node: UIfExpression): Boolean { + return visitors.all { it.visitIfExpression(node) } + } + + override fun visitSwitchExpression(node: USwitchExpression): Boolean { + return visitors.all { it.visitSwitchExpression(node) } + } + + override fun visitSwitchClauseExpression(node: USwitchClauseExpression): Boolean { + return visitors.all { it.visitSwitchClauseExpression(node) } + } + + override fun visitWhileExpression(node: UWhileExpression): Boolean { + return visitors.all { it.visitWhileExpression(node) } + } + + override fun visitDoWhileExpression(node: UDoWhileExpression): Boolean { + return visitors.all { it.visitDoWhileExpression(node) } + } + + override fun visitForExpression(node: UForExpression): Boolean { + return visitors.all { it.visitForExpression(node) } + } + + override fun visitForEachExpression(node: UForEachExpression): Boolean { + return visitors.all { it.visitForEachExpression(node) } + } + + override fun visitTryExpression(node: UTryExpression): Boolean { + return visitors.all { it.visitTryExpression(node) } + } + + override fun visitCatchClause(node: UCatchClause): Boolean { + return visitors.all { it.visitCatchClause(node) } + } + + override fun visitLiteralExpression(node: ULiteralExpression): Boolean { + return visitors.all { it.visitLiteralExpression(node) } + } + + override fun visitThisExpression(node: UThisExpression): Boolean { + return visitors.all { it.visitThisExpression(node) } + } + + override fun visitSuperExpression(node: USuperExpression): Boolean { + return visitors.all { it.visitSuperExpression(node) } + } + + override fun visitReturnExpression(node: UReturnExpression): Boolean { + return visitors.all { it.visitReturnExpression(node) } + } + + override fun visitBreakExpression(node: UBreakExpression): Boolean { + return visitors.all { it.visitBreakExpression(node) } + } + + override fun visitContinueExpression(node: UContinueExpression): Boolean { + return visitors.all { it.visitContinueExpression(node) } + } + + override fun visitThrowExpression(node: UThrowExpression): Boolean { + return visitors.all { it.visitThrowExpression(node) } + } + + override fun visitArrayAccessExpression(node: UArrayAccessExpression): Boolean { + return visitors.all { it.visitArrayAccessExpression(node) } + } + + override fun visitCallableReferenceExpression(node: UCallableReferenceExpression): Boolean { + return visitors.all { it.visitCallableReferenceExpression(node) } + } + + override fun visitClassLiteralExpression(node: UClassLiteralExpression): Boolean { + return visitors.all { it.visitClassLiteralExpression(node) } + } + + override fun visitLambdaExpression(node: ULambdaExpression): Boolean { + return visitors.all { it.visitLambdaExpression(node) } + } + + override fun visitObjectLiteralExpression(node: UObjectLiteralExpression): Boolean { + return visitors.all { it.visitObjectLiteralExpression(node) } + } +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/visitor/UastTypedVisitor.kt b/uast/uast-common/src/org/jetbrains/uast/visitor/UastTypedVisitor.kt new file mode 100644 index 000000000000..f4cf5305aa05 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/visitor/UastTypedVisitor.kt @@ -0,0 +1,84 @@ +/* + * 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 org.jetbrains.uast.visitor + +import org.jetbrains.uast.* + +interface UastTypedVisitor { + fun visitElement(node: UElement, data: D): R + // Just elements + fun visitFile(node: UFile, data: D): R = visitElement(node, data) + fun visitImportStatement(node: UImportStatement, data: D): R = visitElement(node, data) + fun visitAnnotation(node: UAnnotation, data: D): R = visitElement(node, data) + fun visitCatchClause(node: UCatchClause, data: D) = visitElement(node, data) + // Declarations + fun visitDeclaration(node: UDeclaration, data: D) = visitElement(node, data) + fun visitClass(node: UClass, data: D): R = visitDeclaration(node, data) + fun visitMethod(node: UMethod, data: D): R = visitDeclaration(node, data) + fun visitClassInitializer(node: UClassInitializer, data: D): R = visitDeclaration(node, data) + // Variables + fun visitVariable(node: UVariable, data: D): R = visitDeclaration(node, data) + fun visitParameter(node: UParameter, data: D): R = visitVariable(node, data) + fun visitField(node: UField, data: D): R = visitVariable(node, data) + fun visitLocalVariable(node: ULocalVariable, data: D): R = visitVariable(node, data) + fun visitEnumConstantExpression(node: UEnumConstant, data: D) = visitVariable(node, data) + // Expressions + fun visitExpression(node: UExpression, data: D) = visitElement(node, data) + fun visitLabeledExpression(node: ULabeledExpression, data: D) = visitExpression(node, data) + fun visitDeclarationsExpression(node: UDeclarationsExpression, data: D) = visitExpression(node, data) + fun visitBlockExpression(node: UBlockExpression, data: D) = visitExpression(node, data) + fun visitTypeReferenceExpression(node: UTypeReferenceExpression, data: D) = visitExpression(node, data) + fun visitExpressionList(node: UExpressionList, data: D) = visitExpression(node, data) + fun visitLiteralExpression(node: ULiteralExpression, data: D) = visitExpression(node, data) + fun visitThisExpression(node: UThisExpression, data: D) = visitExpression(node, data) + fun visitSuperExpression(node: USuperExpression, data: D) = visitExpression(node, data) + fun visitArrayAccessExpression(node: UArrayAccessExpression, data: D) = visitExpression(node, data) + fun visitClassLiteralExpression(node: UClassLiteralExpression, data: D) = visitExpression(node, data) + fun visitLambdaExpression(node: ULambdaExpression, data: D) = visitExpression(node, data) + fun visitPolyadicExpression(node: UPolyadicExpression, data: D) = visitExpression(node, data) + // Calls + fun visitCallExpression(node: UCallExpression, data: D) = visitExpression(node, data) + fun visitObjectLiteralExpression(node: UObjectLiteralExpression, data: D) = visitCallExpression(node, data) + // Operations + fun visitBinaryExpression(node: UBinaryExpression, data: D) = visitPolyadicExpression(node, data) + fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType, data: D) = visitExpression(node, data) + fun visitParenthesizedExpression(node: UParenthesizedExpression, data: D) = visitExpression(node, data) + // Unary operations + fun visitUnaryExpression(node: UUnaryExpression, data: D) = visitExpression(node, data) + fun visitPrefixExpression(node: UPrefixExpression, data: D) = visitUnaryExpression(node, data) + fun visitPostfixExpression(node: UPostfixExpression, data: D) = visitUnaryExpression(node, data) + // References + fun visitReferenceExpression(node: UReferenceExpression, data: D) = visitExpression(node, data) + fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression, data: D) = visitReferenceExpression(node, data) + fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression, data: D) = visitReferenceExpression(node, data) + fun visitCallableReferenceExpression(node: UCallableReferenceExpression, data: D) = visitReferenceExpression(node, data) + // Control structures + fun visitIfExpression(node: UIfExpression, data: D) = visitExpression(node, data) + fun visitSwitchExpression(node: USwitchExpression, data: D) = visitExpression(node, data) + fun visitSwitchClauseExpression(node: USwitchClauseExpression, data: D) = visitExpression(node, data) + fun visitTryExpression(node: UTryExpression, data: D) = visitExpression(node, data) + // Jumps + fun visitReturnExpression(node: UReturnExpression, data: D) = visitExpression(node, data) + fun visitBreakExpression(node: UBreakExpression, data: D) = visitExpression(node, data) + fun visitContinueExpression(node: UContinueExpression, data: D) = visitExpression(node, data) + fun visitThrowExpression(node: UThrowExpression, data: D) = visitExpression(node, data) + // Loops + fun visitLoopExpression(node: ULoopExpression, data: D) = visitExpression(node, data) + fun visitWhileExpression(node: UWhileExpression, data: D) = visitLoopExpression(node, data) + fun visitDoWhileExpression(node: UDoWhileExpression, data: D) = visitLoopExpression(node, data) + fun visitForExpression(node: UForExpression, data: D) = visitLoopExpression(node, data) + fun visitForEachExpression(node: UForEachExpression, data: D) = visitLoopExpression(node, data) +} \ No newline at end of file diff --git a/uast/uast-common/src/org/jetbrains/uast/visitor/UastVisitor.kt b/uast/uast-common/src/org/jetbrains/uast/visitor/UastVisitor.kt new file mode 100644 index 000000000000..7e2b61071132 --- /dev/null +++ b/uast/uast-common/src/org/jetbrains/uast/visitor/UastVisitor.kt @@ -0,0 +1,134 @@ +/* + * 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 org.jetbrains.uast.visitor + +import org.jetbrains.uast.* + +interface UastVisitor { + fun visitElement(node: UElement): Boolean + + fun visitFile(node: UFile): Boolean = visitElement(node) + fun visitImportStatement(node: UImportStatement): Boolean = visitElement(node) + fun visitClass(node: UClass): Boolean = visitElement(node) + fun visitInitializer(node: UClassInitializer): Boolean = visitElement(node) + fun visitMethod(node: UMethod): Boolean = visitElement(node) + fun visitVariable(node: UVariable): Boolean = visitElement(node) + fun visitParameter(node: UParameter): Boolean = visitVariable(node) + fun visitField(node: UField): Boolean = visitVariable(node) + fun visitLocalVariable(node: ULocalVariable): Boolean = visitVariable(node) + fun visitEnumConstant(node: UEnumConstant): Boolean = visitField(node) + + fun visitAnnotation(node: UAnnotation): Boolean = visitElement(node) + + // Expressions + fun visitLabeledExpression(node: ULabeledExpression) = visitElement(node) + fun visitDeclarationsExpression(node: UDeclarationsExpression) = visitElement(node) + fun visitBlockExpression(node: UBlockExpression) = visitElement(node) + fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) = visitElement(node) + fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression) = visitElement(node) + fun visitTypeReferenceExpression(node: UTypeReferenceExpression) = visitElement(node) + fun visitCallExpression(node: UCallExpression) = visitElement(node) + fun visitBinaryExpression(node: UBinaryExpression) = visitElement(node) + fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType) = visitElement(node) + fun visitPolyadicExpression(node: UPolyadicExpression) = visitElement(node) + fun visitParenthesizedExpression(node: UParenthesizedExpression) = visitElement(node) + fun visitUnaryExpression(node: UUnaryExpression) = visitElement(node) + fun visitPrefixExpression(node: UPrefixExpression) = visitElement(node) + fun visitPostfixExpression(node: UPostfixExpression) = visitElement(node) + fun visitExpressionList(node: UExpressionList) = visitElement(node) + fun visitIfExpression(node: UIfExpression) = visitElement(node) + fun visitSwitchExpression(node: USwitchExpression) = visitElement(node) + fun visitSwitchClauseExpression(node: USwitchClauseExpression) = visitElement(node) + fun visitWhileExpression(node: UWhileExpression) = visitElement(node) + fun visitDoWhileExpression(node: UDoWhileExpression) = visitElement(node) + fun visitForExpression(node: UForExpression) = visitElement(node) + fun visitForEachExpression(node: UForEachExpression) = visitElement(node) + fun visitTryExpression(node: UTryExpression) = visitElement(node) + fun visitCatchClause(node: UCatchClause) = visitElement(node) + fun visitLiteralExpression(node: ULiteralExpression) = visitElement(node) + fun visitThisExpression(node: UThisExpression) = visitElement(node) + fun visitSuperExpression(node: USuperExpression) = visitElement(node) + fun visitReturnExpression(node: UReturnExpression) = visitElement(node) + fun visitBreakExpression(node: UBreakExpression) = visitElement(node) + fun visitContinueExpression(node: UContinueExpression) = visitElement(node) + fun visitThrowExpression(node: UThrowExpression) = visitElement(node) + fun visitArrayAccessExpression(node: UArrayAccessExpression) = visitElement(node) + fun visitCallableReferenceExpression(node: UCallableReferenceExpression) = visitElement(node) + fun visitClassLiteralExpression(node: UClassLiteralExpression) = visitElement(node) + fun visitLambdaExpression(node: ULambdaExpression) = visitElement(node) + fun visitObjectLiteralExpression(node: UObjectLiteralExpression) = visitElement(node) + + // After + + fun afterVisitElement(node: UElement) {} + + fun afterVisitFile(node: UFile) { afterVisitElement(node) } + fun afterVisitImportStatement(node: UImportStatement) { afterVisitElement(node) } + fun afterVisitClass(node: UClass) { afterVisitElement(node) } + fun afterVisitInitializer(node: UClassInitializer) { afterVisitElement(node) } + fun afterVisitMethod(node: UMethod) { afterVisitElement(node) } + fun afterVisitVariable(node: UVariable) { afterVisitElement(node) } + fun afterVisitParameter(node: UParameter){ afterVisitVariable(node) } + fun afterVisitField(node: UField){ afterVisitVariable(node) } + fun afterVisitLocalVariable(node: ULocalVariable){ afterVisitVariable(node) } + fun afterVisitEnumConstant(node: UEnumConstant){ afterVisitField(node) } + fun afterVisitAnnotation(node: UAnnotation) { afterVisitElement(node) } + + // Expressions + fun afterVisitLabeledExpression(node: ULabeledExpression) { afterVisitElement(node) } + fun afterVisitDeclarationsExpression(node: UDeclarationsExpression) { afterVisitElement(node) } + fun afterVisitBlockExpression(node: UBlockExpression) { afterVisitElement(node) } + fun afterVisitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) { afterVisitElement(node) } + fun afterVisitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression) { afterVisitElement(node) } + fun afterVisitTypeReferenceExpression(node: UTypeReferenceExpression) { afterVisitElement(node) } + fun afterVisitCallExpression(node: UCallExpression) { afterVisitElement(node) } + fun afterVisitBinaryExpression(node: UBinaryExpression) { afterVisitElement(node) } + fun afterVisitBinaryExpressionWithType(node: UBinaryExpressionWithType) { afterVisitElement(node) } + fun afterVisitParenthesizedExpression(node: UParenthesizedExpression) { afterVisitElement(node) } + fun afterVisitUnaryExpression(node: UUnaryExpression) { afterVisitElement(node) } + fun afterVisitPrefixExpression(node: UPrefixExpression) { afterVisitElement(node) } + fun afterVisitPostfixExpression(node: UPostfixExpression) { afterVisitElement(node) } + fun afterVisitExpressionList(node: UExpressionList) { afterVisitElement(node) } + fun afterVisitIfExpression(node: UIfExpression) { afterVisitElement(node) } + fun afterVisitSwitchExpression(node: USwitchExpression) { afterVisitElement(node) } + fun afterVisitSwitchClauseExpression(node: USwitchClauseExpression) { afterVisitElement(node) } + fun afterVisitWhileExpression(node: UWhileExpression) { afterVisitElement(node) } + fun afterVisitDoWhileExpression(node: UDoWhileExpression) { afterVisitElement(node) } + fun afterVisitForExpression(node: UForExpression) { afterVisitElement(node) } + fun afterVisitForEachExpression(node: UForEachExpression) { afterVisitElement(node) } + fun afterVisitTryExpression(node: UTryExpression) { afterVisitElement(node) } + fun afterVisitCatchClause(node: UCatchClause) { afterVisitElement(node) } + fun afterVisitLiteralExpression(node: ULiteralExpression) { afterVisitElement(node) } + fun afterVisitThisExpression(node: UThisExpression) { afterVisitElement(node) } + fun afterVisitSuperExpression(node: USuperExpression) { afterVisitElement(node) } + fun afterVisitReturnExpression(node: UReturnExpression) { afterVisitElement(node) } + fun afterVisitBreakExpression(node: UBreakExpression) { afterVisitElement(node) } + fun afterVisitContinueExpression(node: UContinueExpression) { afterVisitElement(node) } + fun afterVisitThrowExpression(node: UThrowExpression) { afterVisitElement(node) } + fun afterVisitArrayAccessExpression(node: UArrayAccessExpression) { afterVisitElement(node) } + fun afterVisitCallableReferenceExpression(node: UCallableReferenceExpression) { afterVisitElement(node) } + fun afterVisitClassLiteralExpression(node: UClassLiteralExpression) { afterVisitElement(node) } + fun afterVisitLambdaExpression(node: ULambdaExpression) { afterVisitElement(node) } + fun afterVisitObjectLiteralExpression(node: UObjectLiteralExpression) { afterVisitElement(node) } + fun afterVisitPolyadicExpression(node: UPolyadicExpression) { afterVisitElement(node) } +} + +abstract class AbstractUastVisitor : UastVisitor { + override fun visitElement(node: UElement): Boolean = false + +} + +object EmptyUastVisitor : AbstractUastVisitor() \ No newline at end of file diff --git a/uast/uast-common/uast-common.iml b/uast/uast-common/uast-common.iml new file mode 100644 index 000000000000..3b903da78f6f --- /dev/null +++ b/uast/uast-common/uast-common.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt b/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt new file mode 100644 index 000000000000..30c5a1d272b2 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt @@ -0,0 +1,53 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiExpression +import com.intellij.psi.PsiType +import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.java.internal.JavaUElementWithComments + +abstract class JavaAbstractUElement : JavaUElementWithComments { + override fun equals(other: Any?): Boolean { + if (other !is UElement || other.javaClass != this.javaClass) return false + return this.psi == other.psi + } + + override fun asSourceString(): String { + return this.psi?.text ?: super.asSourceString() + } + + override fun toString() = asRenderString() +} + +abstract class JavaAbstractUExpression : JavaAbstractUElement(), UExpression { + override fun evaluate(): Any? { + val project = psi?.project ?: return null + return JavaPsiFacade.getInstance(project).constantEvaluationHelper.computeConstantExpression(psi) + } + + override val annotations: List + get() = emptyList() + + override fun getExpressionType(): PsiType? { + val expression = psi as? PsiExpression ?: return null + return expression.type + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt b/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt new file mode 100644 index 000000000000..46c9652380ca --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt @@ -0,0 +1,334 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.lang.Language +import com.intellij.lang.java.JavaLanguage +import com.intellij.psi.* +import org.jetbrains.uast.* +import org.jetbrains.uast.java.expressions.JavaUNamedExpression +import org.jetbrains.uast.java.expressions.JavaUSynchronizedExpression + +class JavaUastLanguagePlugin : UastLanguagePlugin { + override val priority = 0 + + override fun isFileSupported(fileName: String) = fileName.endsWith(".java", ignoreCase = true) + + override val language: Language + get() = JavaLanguage.INSTANCE + + override fun isExpressionValueUsed(element: UExpression): Boolean = when (element) { + is JavaUDeclarationsExpression -> false + is UnknownJavaExpression -> (element.uastParent as? UExpression)?.let { isExpressionValueUsed(it) } ?: false + else -> { + val statement = element.psi as? PsiStatement + statement != null && statement.parent !is PsiExpressionStatement + } + } + + override fun getMethodCallExpression( + element: PsiElement, + containingClassFqName: String?, + methodName: String + ): UastLanguagePlugin.ResolvedMethod? { + if (element !is PsiMethodCallExpression) return null + if (element.methodExpression.referenceName != methodName) return null + + val uElement = convertElementWithParent(element, null) + val callExpression = when (uElement) { + is UCallExpression -> uElement + is UQualifiedReferenceExpression -> uElement.selector as UCallExpression + else -> error("Invalid element type: $uElement") + } + + val method = callExpression.resolve() ?: return null + if (containingClassFqName != null) { + val containingClass = method.containingClass ?: return null + if (containingClass.qualifiedName != containingClassFqName) return null + } + + return UastLanguagePlugin.ResolvedMethod(callExpression, method) + } + + override fun getConstructorCallExpression( + element: PsiElement, + fqName: String + ): UastLanguagePlugin.ResolvedConstructor? { + if (element !is PsiNewExpression) return null + val simpleName = fqName.substringAfterLast('.') + if (element.classReference?.referenceName != simpleName) return null + + val callExpression = convertElementWithParent(element, null) as? UCallExpression ?: return null + + val constructorMethod = element.resolveConstructor() ?: return null + val containingClass = constructorMethod.containingClass ?: return null + if (containingClass.qualifiedName != fqName) return null + + return UastLanguagePlugin.ResolvedConstructor(callExpression, constructorMethod, containingClass) + } + + override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class?): UElement? { + if (element !is PsiElement) return null + val parentCallback = parent.toCallback() + return convertDeclaration(element, parentCallback, requiredType) ?: + JavaConverter.convertPsiElement(element, parentCallback, requiredType) + } + + override fun convertElementWithParent(element: PsiElement, requiredType: Class?): UElement? { + if (element !is PsiElement) return null + if (element is PsiJavaFile) return requiredType.el { JavaUFile(element, this) } + JavaConverter.getCached(element)?.let { return it } + + val parentCallback = fun(): UElement? { + val parent = JavaConverter.unwrapElements(element.parent) ?: return null + return convertElementWithParent(parent, null) ?: return null + } + return convertDeclaration(element, parentCallback, requiredType) ?: + JavaConverter.convertPsiElement(element, parentCallback, requiredType) + } + + private fun convertDeclaration(element: PsiElement, + parentCallback: (() -> UElement?)?, + requiredType: Class?): UElement? { + fun

build(ctor: (P, UElement?) -> UElement): () -> UElement? { + return fun(): UElement? { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + return ctor(element as P, parent) + } + } + + if (element.isValid) element.getUserData(JAVA_CACHED_UELEMENT_KEY)?.let { ref -> + ref.get()?.let { return it } + } + + return with (requiredType) { when (element) { + is PsiJavaFile -> el { JavaUFile(element, this@JavaUastLanguagePlugin) } + is UDeclaration -> el { element } + is PsiClass -> el { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + JavaUClass.create(element, parent) + } + is PsiMethod -> el { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + JavaUMethod.create(element, this@JavaUastLanguagePlugin, parent) + } + is PsiClassInitializer -> el(build(::JavaUClassInitializer)) + is PsiEnumConstant -> el(build(::JavaUEnumConstant)) + is PsiLocalVariable -> el(build(::JavaULocalVariable)) + is PsiParameter -> el(build(::JavaUParameter)) + is PsiField -> el(build(::JavaUField)) + is PsiVariable -> el(build(::JavaUVariable)) + is PsiAnnotation -> el(build(::JavaUAnnotation)) + else -> null + }} + } +} + +internal inline fun Class?.el(f: () -> UElement?): UElement? { + return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null +} + +internal inline fun Class?.expr(f: () -> UExpression?): UExpression? { + return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null +} + +private fun UElement?.toCallback() = if (this != null) fun(): UElement? { return this } else null + +internal object JavaConverter { + internal inline fun getCached(element: PsiElement): T? { + return null + //todo + } + + internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) { + is PsiExpressionStatement -> unwrapElements(element.parent) + is PsiParameterList -> unwrapElements(element.parent) + is PsiAnnotationParameterList -> unwrapElements(element.parent) + else -> element + } + + internal fun convertPsiElement(el: PsiElement, + parentCallback: (() -> UElement?)?, + requiredType: Class? = null): UElement? { + getCached(el)?.let { return it } + + fun

build(ctor: (P, UElement?) -> UElement): () -> UElement? { + return fun(): UElement? { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + return ctor(el as P, parent) + } + } + + return with (requiredType) { when (el) { + is PsiCodeBlock -> el(build(::JavaUCodeBlockExpression)) + is PsiResourceExpression -> convertExpression(el.expression, parentCallback, requiredType) + is PsiExpression -> convertExpression(el, parentCallback, requiredType) + is PsiStatement -> convertStatement(el, parentCallback, requiredType) + is PsiIdentifier -> el { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + JavaUSimpleNameReferenceExpression(el, el.text, parent) + } + is PsiNameValuePair -> el(build(::JavaUNamedExpression)) + is PsiArrayInitializerMemberValue -> el(build(::JavaAnnotationArrayInitializerUCallExpression)) + is PsiTypeElement -> el(build(::JavaUTypeReferenceExpression)) + is PsiJavaCodeReferenceElement -> convertReference(el, parentCallback, requiredType) + else -> null + }} + } + + internal fun convertBlock(block: PsiCodeBlock, parent: UElement?): UBlockExpression = + getCached(block) ?: JavaUCodeBlockExpression(block, parent) + + internal fun convertReference(reference: PsiJavaCodeReferenceElement, parentCallback: (() -> UElement?)?, requiredType: Class?): UExpression? { + return with (requiredType) { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + if (reference.isQualified) { + expr { JavaUQualifiedReferenceExpression(reference, parent) } + } else { + val name = reference.referenceName ?: "" + expr { JavaUSimpleNameReferenceExpression(reference, name, parent, reference) } + } + } + } + + internal fun convertExpression(el: PsiExpression, + parentCallback: (() -> UElement?)?, + requiredType: Class? = null): UExpression? { + getCached(el)?.let { return it } + + fun

build(ctor: (P, UElement?) -> UExpression): () -> UExpression? { + return fun(): UExpression? { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + return ctor(el as P, parent) + } + } + + return with (requiredType) { when (el) { + is PsiAssignmentExpression -> expr(build(::JavaUAssignmentExpression)) + is PsiConditionalExpression -> expr(build(::JavaUTernaryIfExpression)) + is PsiNewExpression -> { + if (el.anonymousClass != null) + expr(build(::JavaUObjectLiteralExpression)) + else + expr(build(::JavaConstructorUCallExpression)) + } + is PsiMethodCallExpression -> { + if (el.methodExpression.qualifierExpression != null) + expr { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + JavaUCompositeQualifiedExpression(el, parent).apply { + receiver = convertOrEmpty(el.methodExpression.qualifierExpression!!, this) + selector = JavaUCallExpression(el, this) + } + } + else + expr(build(::JavaUCallExpression)) + } + is PsiArrayInitializerExpression -> expr(build(::JavaArrayInitializerUCallExpression)) + is PsiBinaryExpression -> expr(build(::JavaUBinaryExpression)) + // Should go after PsiBinaryExpression since it implements PsiPolyadicExpression + is PsiPolyadicExpression -> expr(build(::JavaUPolyadicExpression)) + is PsiParenthesizedExpression -> expr(build(::JavaUParenthesizedExpression)) + is PsiPrefixExpression -> expr(build(::JavaUPrefixExpression)) + is PsiPostfixExpression -> expr(build(::JavaUPostfixExpression)) + is PsiLiteralExpression -> expr(build(::JavaULiteralExpression)) + is PsiMethodReferenceExpression -> expr(build(::JavaUCallableReferenceExpression)) + is PsiReferenceExpression -> convertReference(el, parentCallback, requiredType) + is PsiThisExpression -> expr(build(::JavaUThisExpression)) + is PsiSuperExpression -> expr(build(::JavaUSuperExpression)) + is PsiInstanceOfExpression -> expr(build(::JavaUInstanceCheckExpression)) + is PsiTypeCastExpression -> expr(build(::JavaUTypeCastExpression)) + is PsiClassObjectAccessExpression -> expr(build(::JavaUClassLiteralExpression)) + is PsiArrayAccessExpression -> expr(build(::JavaUArrayAccessExpression)) + is PsiLambdaExpression -> expr(build(::JavaULambdaExpression)) + else -> expr(build(::UnknownJavaExpression)) + }} + } + + internal fun convertStatement(el: PsiStatement, + parentCallback: (() -> UElement?)?, + requiredType: Class? = null): UExpression? { + getCached(el)?.let { return it } + + fun

build(ctor: (P, UElement?) -> UExpression): () -> UExpression? { + return fun(): UExpression? { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + return ctor(el as P, parent) + } + } + + return with (requiredType) { when (el) { + is PsiDeclarationStatement -> expr { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + convertDeclarations(el.declaredElements, parent!!) + } + is PsiExpressionListStatement -> expr { + val parent = if (parentCallback == null) null else (parentCallback() ?: return null) + convertDeclarations(el.expressionList.expressions, parent!!) + } + is PsiBlockStatement -> expr(build(::JavaUBlockExpression)) + is PsiLabeledStatement -> expr(build(::JavaULabeledExpression)) + is PsiExpressionStatement -> convertExpression(el.expression, parentCallback, requiredType) + is PsiIfStatement -> expr(build(::JavaUIfExpression)) + is PsiSwitchStatement -> expr(build(::JavaUSwitchExpression)) + is PsiWhileStatement -> expr(build(::JavaUWhileExpression)) + is PsiDoWhileStatement -> expr(build(::JavaUDoWhileExpression)) + is PsiForStatement -> expr(build(::JavaUForExpression)) + is PsiForeachStatement -> expr(build(::JavaUForEachExpression)) + is PsiBreakStatement -> expr(build(::JavaUBreakExpression)) + is PsiContinueStatement -> expr(build(::JavaUContinueExpression)) + is PsiReturnStatement -> expr(build(::JavaUReturnExpression)) + is PsiAssertStatement -> expr(build(::JavaUAssertExpression)) + is PsiThrowStatement -> expr(build(::JavaUThrowExpression)) + is PsiSynchronizedStatement -> expr(build(::JavaUSynchronizedExpression)) + is PsiTryStatement -> expr(build(::JavaUTryExpression)) + is PsiEmptyStatement -> expr { UastEmptyExpression } + else -> expr(build(::UnknownJavaExpression)) + }} + } + + private fun convertDeclarations(elements: Array, parent: UElement): UDeclarationsExpression { + return JavaUDeclarationsExpression(parent).apply { + val declarations = mutableListOf() + for (element in elements) { + if (element is PsiVariable) { + declarations += JavaUVariable.create(element, this) + } + else if (element is PsiClass) { + declarations += JavaUClass.create(element, this) + } + } + this.declarations = declarations + } + } + + internal fun convertOrEmpty(statement: PsiStatement?, parent: UElement?): UExpression { + return statement?.let { convertStatement(it, parent.toCallback(), null) } ?: UastEmptyExpression + } + + internal fun convertOrEmpty(expression: PsiExpression?, parent: UElement?): UExpression { + return expression?.let { convertExpression(it, parent.toCallback()) } ?: UastEmptyExpression + } + + internal fun convertOrNull(expression: PsiExpression?, parent: UElement?): UExpression? { + return if (expression != null) convertExpression(expression, parent.toCallback()) else null + } + + internal fun convertOrEmpty(block: PsiCodeBlock?, parent: UElement?): UExpression { + return if (block != null) convertBlock(block, parent) else UastEmptyExpression + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUDoWhileExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUDoWhileExpression.kt new file mode 100644 index 000000000000..0edac6d1a4f2 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUDoWhileExpression.kt @@ -0,0 +1,35 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiDoWhileStatement +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.UDoWhileExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier + +class JavaUDoWhileExpression( + override val psi: PsiDoWhileStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UDoWhileExpression { + override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } + override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } + + override val doIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.DO_KEYWORD), this) + override val whileIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.WHILE_KEYWORD), this) +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForEachExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForEachExpression.kt new file mode 100644 index 000000000000..3e81c589ee7b --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForEachExpression.kt @@ -0,0 +1,37 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiForeachStatement +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UForEachExpression +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UParameter + +class JavaUForEachExpression( + override val psi: PsiForeachStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UForEachExpression { + override val variable: UParameter + get() = JavaUParameter(psi.iterationParameter, this) + + override val iteratedValue by lz { JavaConverter.convertOrEmpty(psi.iteratedValue, this) } + override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } + + override val forIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.FOR_KEYWORD), this) +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForExpression.kt new file mode 100644 index 000000000000..e057b8a2aa2d --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUForExpression.kt @@ -0,0 +1,35 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiForStatement +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UForExpression +import org.jetbrains.uast.UIdentifier + +class JavaUForExpression( + override val psi: PsiForStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UForExpression { + override val declaration by lz { psi.initialization?.let { JavaConverter.convertStatement(it, { this }) } } + override val condition by lz { psi.condition?.let { JavaConverter.convertExpression(it, { this }) } } + override val update by lz { psi.update?.let { JavaConverter.convertStatement(it, { this }) } } + override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } + + override val forIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.FOR_KEYWORD), this) +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUIfExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUIfExpression.kt new file mode 100644 index 000000000000..9cae21dcd6d5 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUIfExpression.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiIfStatement +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UIfExpression + +class JavaUIfExpression( + override val psi: PsiIfStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UIfExpression { + override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } + override val thenExpression by lz { JavaConverter.convertOrEmpty(psi.thenBranch, this) } + override val elseExpression by lz { JavaConverter.convertOrEmpty(psi.elseBranch, this) } + + override val isTernary: Boolean + get() = false + + override val ifIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.IF_KEYWORD), this) + + override val elseIdentifier: UIdentifier? + get() = psi.getChildByRole(ChildRole.ELSE_KEYWORD)?.let { UIdentifier(it, this) } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt new file mode 100644 index 000000000000..a048e9e538b5 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt @@ -0,0 +1,116 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.* +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.* +import org.jetbrains.uast.java.expressions.JavaUExpressionList +import org.jetbrains.uast.java.kinds.JavaSpecialExpressionKinds + +class JavaUSwitchExpression( + override val psi: PsiSwitchStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), USwitchExpression { + override val expression by lz { JavaConverter.convertOrEmpty(psi.expression, this) } + + override val body: UExpressionList by lz { + object : JavaUExpressionList(psi, JavaSpecialExpressionKinds.SWITCH, this) { + override fun asRenderString() = expressions.joinToString("\n") { + it.asRenderString().withMargin + } + }.apply { + expressions = this@JavaUSwitchExpression.psi.body?.convertToSwitchEntryList(this) ?: emptyList() + } + } + + + override val switchIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.SWITCH_KEYWORD), this) +} + +private fun PsiCodeBlock.convertToSwitchEntryList(containingElement: UExpression): List { + var currentLabels = listOf() + var currentBody = listOf() + val result = mutableListOf() + for (statement in statements) { + if (statement is PsiSwitchLabelStatement) { + if (currentBody.isEmpty()) { + currentLabels += statement + } + else if (currentLabels.isNotEmpty()) { + result += JavaUSwitchEntry(currentLabels, currentBody, containingElement) + currentLabels = listOf(statement) + currentBody = listOf() + } + } + else { + currentBody += statement + } + } + if (currentLabels.isNotEmpty()) { + result += JavaUSwitchEntry(currentLabels, currentBody, containingElement) + } + return result +} + +class JavaUSwitchEntry( + val labels: List, + val statements: List, + override val uastParent: UExpression +) : JavaAbstractUExpression(), USwitchClauseExpressionWithBody { + override val psi: PsiSwitchLabelStatement = labels.first() + + override val caseValues by lz { + labels.mapNotNull { + if (it.isDefaultCase) { + JavaUDefaultCaseExpression + } + else { + val value = it.caseValue + value?.let { JavaConverter.convertExpression(it, { this }) } + } + } + } + + override val body: UExpressionList by lz { + object : JavaUExpressionList(psi, JavaSpecialExpressionKinds.SWITCH_ENTRY, this) { + override fun asRenderString() = buildString { + appendln("{") + expressions.forEach { appendln(it.asRenderString().withMargin) } + appendln("}") + } + }.apply { + val statements = this@JavaUSwitchEntry.statements + expressions = statements.map { JavaConverter.convertOrEmpty(it, this) } + } + } +} + +object JavaUDefaultCaseExpression : UExpression { + override val uastParent: UElement? + get() = null + + override val psi: PsiElement? + get() = null + + override val annotations: List + get() = emptyList() + + override fun asLogString() = "UDefaultCaseExpression" + + override fun asRenderString() = "else" +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTernaryIfExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTernaryIfExpression.kt new file mode 100644 index 000000000000..0438c02686a8 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTernaryIfExpression.kt @@ -0,0 +1,39 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiConditionalExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UIfExpression + +class JavaUTernaryIfExpression( + override val psi: PsiConditionalExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UIfExpression { + override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } + override val thenExpression by lz { JavaConverter.convertOrEmpty(psi.thenExpression, this) } + override val elseExpression by lz { JavaConverter.convertOrEmpty(psi.elseExpression, this) } + + override val isTernary: Boolean + get() = true + + override val ifIdentifier: UIdentifier + get() = UIdentifier(null, this) + + override val elseIdentifier: UIdentifier? + get() = UIdentifier(null, this) +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTryExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTryExpression.kt new file mode 100644 index 000000000000..13cb8b1461a6 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUTryExpression.kt @@ -0,0 +1,65 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.* +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.* + +class JavaUTryExpression( + override val psi: PsiTryStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UTryExpression { + override val tryClause by lz { JavaConverter.convertOrEmpty(psi.tryBlock, this) } + override val catchClauses by lz { psi.catchSections.map { JavaUCatchClause(it, this) } } + override val finallyClause by lz { psi.finallyBlock?.let { JavaConverter.convertBlock(it, this) } } + + override val resourceVariables by lz { + psi.resourceList + ?.filterIsInstance() + ?.map { JavaUVariable.create(it, this) } + ?: emptyList() + } + + override val hasResources: Boolean + get() = psi.resourceList != null + + override val tryIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.TRY_KEYWORD), this) + + override val finallyIdentifier: UIdentifier? + get() = psi.getChildByRole(ChildRole.FINALLY_KEYWORD)?.let { UIdentifier(it, this) } +} + +class JavaUCatchClause( + override val psi: PsiCatchSection, + override val uastParent: UElement? +) : JavaAbstractUElement(), UCatchClause { + override val body by lz { JavaConverter.convertOrEmpty(psi.catchBlock, this) } + + override val parameters by lz { + (psi.parameter?.let { listOf(it) } ?: emptyList()).map { JavaUParameter(it, this) } + } + + override val typeReferences by lz { + val typeElement = psi.parameter?.typeElement ?: return@lz emptyList() + if (typeElement.type is PsiDisjunctionType) { + typeElement.children.filterIsInstance().map { JavaUTypeReferenceExpression(it, this) } + } else { + listOf(JavaUTypeReferenceExpression(typeElement, this)) + } + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUWhileExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUWhileExpression.kt new file mode 100644 index 000000000000..79739d156285 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUWhileExpression.kt @@ -0,0 +1,33 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiWhileStatement +import com.intellij.psi.impl.source.tree.ChildRole +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UWhileExpression + +class JavaUWhileExpression( + override val psi: PsiWhileStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UWhileExpression { + override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } + override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } + + override val whileIdentifier: UIdentifier + get() = UIdentifier(psi.getChildByRole(ChildRole.WHILE_KEYWORD), this) +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUAnnotation.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUAnnotation.kt new file mode 100644 index 000000000000..460a74d59473 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUAnnotation.kt @@ -0,0 +1,61 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiClass +import org.jetbrains.uast.* +import org.jetbrains.uast.java.expressions.JavaUNamedExpression + +class JavaUAnnotation( + override val psi: PsiAnnotation, + override val uastParent: UElement? +) : UAnnotation { + override val qualifiedName: String? + get() = psi.qualifiedName + + override val attributeValues: List by lz { + val context = getUastContext() + val attributes = psi.parameterList.attributes + + attributes.map { attribute -> JavaUNamedExpression(attribute, this) } + } + + override fun resolve(): PsiClass? = psi.nameReferenceElement?.resolve() as? PsiClass + + override fun findAttributeValue(name: String?): UExpression? { + val context = getUastContext() + val attributeValue = psi.findAttributeValue(name) ?: return null + return context.convertElement(attributeValue, this, null) as? UExpression ?: UastEmptyExpression + } + + override fun findDeclaredAttributeValue(name: String?): UExpression? { + val context = getUastContext() + val attributeValue = psi.findDeclaredAttributeValue(name) ?: return null + return context.convertElement(attributeValue, this, null) as? UExpression ?: UastEmptyExpression + } + + companion object { + @JvmStatic + fun wrap(annotation: PsiAnnotation): UAnnotation = JavaUAnnotation(annotation, null) + + @JvmStatic + fun wrap(annotations: List): List = annotations.map { JavaUAnnotation(it, null) } + + @JvmStatic + fun wrap(annotations: Array): List = annotations.map { JavaUAnnotation(it, null) } + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt new file mode 100644 index 000000000000..8e29e2be383a --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt @@ -0,0 +1,88 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiAnonymousClass +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiJavaCodeReferenceElement +import org.jetbrains.uast.* +import org.jetbrains.uast.java.internal.JavaUElementWithComments + +abstract class AbstractJavaUClass : UClass, JavaUElementWithComments { + override val uastDeclarations by lz { + mutableListOf().apply { + addAll(fields) + addAll(initializers) + addAll(methods) + addAll(innerClasses) + } + } + + override val uastSuperTypes: List + get() { + fun createJavaUTypeReferenceExpression(referenceElement: PsiJavaCodeReferenceElement) = + LazyJavaUTypeReferenceExpression(referenceElement, this) { + JavaPsiFacade.getElementFactory(referenceElement.project).createType(referenceElement) + } + + return psi.extendsList?.referenceElements?.map(::createJavaUTypeReferenceExpression).orEmpty() + + psi.implementsList?.referenceElements?.map(::createJavaUTypeReferenceExpression).orEmpty() + } + + override val uastAnchor: UElement? + get() = UIdentifier(psi.nameIdentifier, this) + + override val annotations: List + get() = psi.annotations.map { JavaUAnnotation(it, this) } + + override fun equals(other: Any?) = other is AbstractJavaUClass && psi == other.psi + override fun hashCode() = psi.hashCode() +} + +class JavaUClass private constructor(psi: PsiClass, override val uastParent: UElement?) : + AbstractJavaUClass(), PsiClass by psi { + override val psi = unwrap(psi) + + override fun getSuperClass(): UClass? = super.getSuperClass() + override fun getFields(): Array = super.getFields() + override fun getInitializers(): Array = super.getInitializers() + override fun getMethods(): Array = super.getMethods() + override fun getInnerClasses(): Array = super.getInnerClasses() + + companion object { + fun create(psi: PsiClass, containingElement: UElement?): UClass { + return if (psi is PsiAnonymousClass) + JavaUAnonymousClass(psi, containingElement) + else + JavaUClass(psi, containingElement) + } + } +} + +class JavaUAnonymousClass( + psi: PsiAnonymousClass, + override val uastParent: UElement? +) : AbstractJavaUClass(), UAnonymousClass, PsiAnonymousClass by psi { + override val psi: PsiAnonymousClass = unwrap(psi) + + override fun getSuperClass(): UClass? = super.getSuperClass() + override fun getFields(): Array = super.getFields() + override fun getInitializers(): Array = super.getInitializers() + override fun getMethods(): Array = super.getMethods() + override fun getInnerClasses(): Array = super.getInnerClasses() +} diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClassInitializer.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClassInitializer.kt new file mode 100644 index 000000000000..ae554552453d --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClassInitializer.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiClassInitializer +import org.jetbrains.uast.* +import org.jetbrains.uast.java.internal.JavaUElementWithComments + +class JavaUClassInitializer( + psi: PsiClassInitializer, + override val uastParent: UElement? +) : UClassInitializer, JavaUElementWithComments, PsiClassInitializer by psi { + override val psi = unwrap(psi) + + override val uastAnchor: UElement? + get() = null + + override val uastBody by lz { + getLanguagePlugin().convertElement(psi.body, this, null) as? UExpression ?: UastEmptyExpression + } + + override val annotations by lz { psi.annotations.map { JavaUAnnotation(it, this) } } + + override fun equals(other: Any?) = this === other + override fun hashCode() = psi.hashCode() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFile.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFile.kt new file mode 100644 index 000000000000..502784629964 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFile.kt @@ -0,0 +1,51 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiJavaFile +import com.intellij.psi.PsiRecursiveElementWalkingVisitor +import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UComment +import org.jetbrains.uast.UFile +import org.jetbrains.uast.UastLanguagePlugin +import java.util.* + +class JavaUFile(override val psi: PsiJavaFile, override val languagePlugin: UastLanguagePlugin) : UFile { + override val packageName: String + get() = psi.packageName + + override val imports by lz { + psi.importList?.allImportStatements?.map { JavaUImportStatement(it, this) } ?: listOf() + } + + override val annotations: List + get() = emptyList() + + override val classes by lz { psi.classes.map { JavaUClass.create(it, this) } } + + override val allCommentsInFile by lz { + val comments = ArrayList(0) + psi.accept(object : PsiRecursiveElementWalkingVisitor() { + override fun visitComment(comment: PsiComment) { + comments += UComment(comment, this@JavaUFile) + } + }) + comments + } + + override fun equals(other: Any?) = (other as? JavaUFile)?.psi == psi +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUImportStatement.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUImportStatement.kt new file mode 100644 index 000000000000..02392e6b76ce --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUImportStatement.kt @@ -0,0 +1,30 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiImportStatementBase +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UImportStatement + +class JavaUImportStatement( + override val psi: PsiImportStatementBase, + override val uastParent: UElement? +) : UImportStatement { + override val isOnDemand: Boolean + get() = psi.isOnDemand + override val importReference by lz { psi.importReference?.let { JavaDumbUElement(it, this, it.qualifiedName) } } + override fun resolve() = psi.resolve() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUMethod.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUMethod.kt new file mode 100644 index 000000000000..535e7021a3f2 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUMethod.kt @@ -0,0 +1,68 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiAnnotationMethod +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiNameIdentifierOwner +import org.jetbrains.uast.* +import org.jetbrains.uast.java.internal.JavaUElementWithComments + +open class JavaUMethod( + psi: PsiMethod, + override val uastParent: UElement? +) : UMethod, JavaUElementWithComments, PsiMethod by psi { + override val psi = unwrap(psi) + + override val uastBody by lz { + val body = psi.body ?: return@lz null + getLanguagePlugin().convertElement(body, this) as? UExpression + } + + override val annotations by lz { psi.annotations.map { JavaUAnnotation(it, this) } } + + override val uastParameters by lz { + psi.parameterList.parameters.map { JavaUParameter(it, this) } + } + + override val isOverride: Boolean + get() = psi.modifierList.findAnnotation("java.lang.Override") != null + + override val uastAnchor: UElement + get() = UIdentifier((psi.originalElement as? PsiNameIdentifierOwner)?.nameIdentifier ?: psi.nameIdentifier, this) + + override fun equals(other: Any?) = other is JavaUMethod && psi == other.psi + override fun hashCode() = psi.hashCode() + + companion object { + fun create(psi: PsiMethod, languagePlugin: UastLanguagePlugin, containingElement: UElement?) = when (psi) { + is PsiAnnotationMethod -> JavaUAnnotationMethod(psi, languagePlugin, containingElement) + else -> JavaUMethod(psi, containingElement) + } + } +} + +class JavaUAnnotationMethod( + override val psi: PsiAnnotationMethod, + languagePlugin: UastLanguagePlugin, + containingElement: UElement? +) : JavaUMethod(psi, containingElement), UAnnotationMethod { + override val uastDefaultValue by lz { + val defaultValue = psi.defaultValue ?: return@lz null + languagePlugin.convertElement(defaultValue, this, null) as? UExpression + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt new file mode 100644 index 000000000000..ce6b19ffbcd0 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt @@ -0,0 +1,128 @@ + /* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.* +import org.jetbrains.uast.* +import org.jetbrains.uast.java.internal.JavaUElementWithComments + +abstract class AbstractJavaUVariable : PsiVariable, UVariable, JavaUElementWithComments { + override val uastInitializer by lz { + val initializer = psi.initializer ?: return@lz null + getLanguagePlugin().convertElement(initializer, this) as? UExpression + } + + override val annotations by lz { psi.annotations.map { JavaUAnnotation(it, this) } } + override val typeReference by lz { getLanguagePlugin().convertOpt(psi.typeElement, this) } + + override val uastAnchor: UElement + get() = UIdentifier(psi.nameIdentifier, this) + + override fun equals(other: Any?) = other is AbstractJavaUVariable && psi == other.psi + override fun hashCode() = psi.hashCode() +} + +open class JavaUVariable( + psi: PsiVariable, + override val uastParent: UElement? +) : AbstractJavaUVariable(), UVariable, PsiVariable by psi { + override val psi = unwrap(psi) + + companion object { + fun create(psi: PsiVariable, containingElement: UElement?): UVariable { + return when (psi) { + is PsiEnumConstant -> JavaUEnumConstant(psi, containingElement) + is PsiLocalVariable -> JavaULocalVariable(psi, containingElement) + is PsiParameter -> JavaUParameter(psi, containingElement) + is PsiField -> JavaUField(psi, containingElement) + else -> JavaUVariable(psi, containingElement) + } + } + } +} + +open class JavaUParameter( + psi: PsiParameter, + override val uastParent: UElement? +) : AbstractJavaUVariable(), UParameter, PsiParameter by psi { + override val psi = unwrap(psi) +} + +open class JavaUField( + psi: PsiField, + override val uastParent: UElement? +) : AbstractJavaUVariable(), UField, PsiField by psi { + override val psi = unwrap(psi) +} + +open class JavaULocalVariable( + psi: PsiLocalVariable, + override val uastParent: UElement? +) : AbstractJavaUVariable(), ULocalVariable, PsiLocalVariable by psi { + override val psi = unwrap(psi) +} + +open class JavaUEnumConstant( + psi: PsiEnumConstant, + override val uastParent: UElement? +) : AbstractJavaUVariable(), UEnumConstant, PsiEnumConstant by psi { + override val initializingClass: UClass? by lz { getLanguagePlugin().convertOpt(psi.initializingClass, this) } + + override val psi = unwrap(psi) + + override val kind: UastCallKind + get() = UastCallKind.CONSTRUCTOR_CALL + override val receiver: UExpression? + get() = null + override val receiverType: PsiType? + get() = null + override val methodIdentifier: UIdentifier? + get() = null + override val classReference: UReferenceExpression? + get() = JavaEnumConstantClassReference(psi, uastParent) + override val typeArgumentCount: Int + get() = 0 + override val typeArguments: List + get() = emptyList() + override val valueArgumentCount: Int + get() = psi.argumentList?.expressions?.size ?: 0 + + override val valueArguments by lz { + psi.argumentList?.expressions?.map { + getLanguagePlugin().convertElement(it, this) as? UExpression ?: UastEmptyExpression + } ?: emptyList() + } + + override val returnType: PsiType? + get() = psi.type + + override fun resolve() = psi.resolveMethod() + + override val methodName: String? + get() = null + + private class JavaEnumConstantClassReference( + override val psi: PsiEnumConstant, + override val uastParent: UElement? + ) : JavaAbstractUExpression(), USimpleNameReferenceExpression { + override fun resolve() = psi.containingClass + override val resolvedName: String? + get() = psi.containingClass?.name + override val identifier: String + get() = psi.containingClass?.name ?: "" + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaDumbUElement.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaDumbUElement.kt new file mode 100644 index 000000000000..660dae65a07f --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaDumbUElement.kt @@ -0,0 +1,29 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.UElement +import org.jetbrains.uast.internal.log + +class JavaDumbUElement( + override val psi: PsiElement?, + override val uastParent: UElement?, + private val customRenderString: String? = null +) : JavaAbstractUElement(), UElement { + override fun asLogString() = log() + override fun asRenderString() = customRenderString ?: "" +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUArrayAccessExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUArrayAccessExpression.kt new file mode 100644 index 000000000000..fc6cb42aec29 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUArrayAccessExpression.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiArrayAccessExpression +import org.jetbrains.uast.UArrayAccessExpression +import org.jetbrains.uast.UElement + +class JavaUArrayAccessExpression( + override val psi: PsiArrayAccessExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UArrayAccessExpression { + override val receiver by lz { JavaConverter.convertOrEmpty(psi.arrayExpression, this) } + override val indices by lz { singletonListOrEmpty(JavaConverter.convertOrNull(psi.indexExpression, this)) } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssertExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssertExpression.kt new file mode 100644 index 000000000000..8132ed64ca6a --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssertExpression.kt @@ -0,0 +1,67 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiAssertStatement +import com.intellij.psi.PsiType +import org.jetbrains.uast.* + + +class JavaUAssertExpression( + override val psi: PsiAssertStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UCallExpression { + val condition: UExpression by lz { JavaConverter.convertOrEmpty(psi.assertCondition, this) } + val message: UExpression? by lz { JavaConverter.convertOrNull(psi.assertDescription, this) } + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = null + + override val methodName: String + get() = "assert" + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null + + override val valueArgumentCount: Int + get() = if (message != null) 2 else 1 + + override val valueArguments by lz { + val message = this.message + if (message != null) listOf(condition, message) else listOf(condition) + } + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val returnType: PsiType + get() = PsiType.VOID + + override val kind: UastCallKind + get() = JavaUastCallKinds.ASSERT + + override fun resolve() = null +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssignmentExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssignmentExpression.kt new file mode 100644 index 000000000000..855930d158ed --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUAssignmentExpression.kt @@ -0,0 +1,35 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiAssignmentExpression +import org.jetbrains.uast.UBinaryExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier + +class JavaUAssignmentExpression( + override val psi: PsiAssignmentExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBinaryExpression { + override val leftOperand by lz { JavaConverter.convertOrEmpty(psi.lExpression, this) } + override val rightOperand by lz { JavaConverter.convertOrEmpty(psi.rExpression, this) } + override val operator by lz { psi.operationTokenType.getOperatorType() } + + override fun resolveOperator() = null + + override val operatorIdentifier: UIdentifier + get() = UIdentifier(psi.operationSign, this) +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBinaryExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBinaryExpression.kt new file mode 100644 index 000000000000..8a88a2952079 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBinaryExpression.kt @@ -0,0 +1,35 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiBinaryExpression +import org.jetbrains.uast.UBinaryExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier + +class JavaUBinaryExpression( + override val psi: PsiBinaryExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBinaryExpression { + override val leftOperand by lz { JavaConverter.convertOrEmpty(psi.lOperand, this) } + override val rightOperand by lz { JavaConverter.convertOrEmpty(psi.rOperand, this) } + override val operator by lz { psi.operationTokenType.getOperatorType() } + + override val operatorIdentifier: UIdentifier + get() = UIdentifier(psi.operationSign, this) + + override fun resolveOperator() = null +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBlockExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBlockExpression.kt new file mode 100644 index 000000000000..7134554314a2 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBlockExpression.kt @@ -0,0 +1,27 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiBlockStatement +import org.jetbrains.uast.UBlockExpression +import org.jetbrains.uast.UElement + +class JavaUBlockExpression( + override val psi: PsiBlockStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBlockExpression { + override val expressions by lz { psi.codeBlock.statements.map { JavaConverter.convertOrEmpty(it, this) } } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBreakExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBreakExpression.kt new file mode 100644 index 000000000000..4c1353f4c5df --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUBreakExpression.kt @@ -0,0 +1,29 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiBreakStatement +import org.jetbrains.uast.UBreakExpression +import org.jetbrains.uast.UElement + +class JavaUBreakExpression( + override val psi: PsiBreakStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBreakExpression { + override val label: String? + get() = psi.labelIdentifier?.text +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCallableReferenceExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCallableReferenceExpression.kt new file mode 100644 index 000000000000..2d77e6bb42e7 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCallableReferenceExpression.kt @@ -0,0 +1,40 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethodReferenceExpression +import com.intellij.psi.PsiNamedElement +import com.intellij.psi.PsiType +import org.jetbrains.uast.UCallableReferenceExpression +import org.jetbrains.uast.UElement + +class JavaUCallableReferenceExpression( + override val psi: PsiMethodReferenceExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UCallableReferenceExpression { + override val qualifierExpression by lz { JavaConverter.convertOrNull(psi.qualifierExpression, this) } + + override val qualifierType: PsiType? + get() = psi.qualifierType?.type + + override val callableName: String + get() = psi.referenceName.orAnonymous() + + override fun resolve() = psi.resolve() + + override val resolvedName: String? = (psi.resolve() as? PsiNamedElement)?.name +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUClassLiteralExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUClassLiteralExpression.kt new file mode 100644 index 000000000000..e1451dabb44c --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUClassLiteralExpression.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiClassObjectAccessExpression +import com.intellij.psi.PsiType +import org.jetbrains.uast.UClassLiteralExpression +import org.jetbrains.uast.UElement + +class JavaUClassLiteralExpression( + override val psi: PsiClassObjectAccessExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UClassLiteralExpression { + override val type: PsiType + get() = psi.operand.type + + override val expression by lz { JavaUTypeReferenceExpression(psi.operand, this) } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCodeBlockExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCodeBlockExpression.kt new file mode 100644 index 000000000000..ac82f78b5d76 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCodeBlockExpression.kt @@ -0,0 +1,27 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiCodeBlock +import org.jetbrains.uast.UBlockExpression +import org.jetbrains.uast.UElement + +class JavaUCodeBlockExpression( + override val psi: PsiCodeBlock, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBlockExpression { + override val expressions by lz { psi.statements.map { JavaConverter.convertOrEmpty(it, this) } } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCompositeQualifiedExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCompositeQualifiedExpression.kt new file mode 100644 index 000000000000..b9c409de9a32 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUCompositeQualifiedExpression.kt @@ -0,0 +1,39 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNamedElement +import org.jetbrains.uast.* + +class JavaUCompositeQualifiedExpression( + override val psi: PsiElement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UQualifiedReferenceExpression { + override lateinit var receiver: UExpression + internal set + + override lateinit var selector: UExpression + internal set + + override val resolvedName: String? + get() = (resolve() as? PsiNamedElement)?.name + + override fun resolve() = (selector as? UResolvable)?.resolve() + + override val accessType: UastQualifiedExpressionAccessType + get() = UastQualifiedExpressionAccessType.SIMPLE +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUContinueExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUContinueExpression.kt new file mode 100644 index 000000000000..f9336b9a949e --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUContinueExpression.kt @@ -0,0 +1,29 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiContinueStatement +import org.jetbrains.uast.UContinueExpression +import org.jetbrains.uast.UElement + +class JavaUContinueExpression( + override val psi: PsiContinueStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UContinueExpression { + override val label: String? + get() = psi.labelIdentifier?.text +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUDeclarationsExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUDeclarationsExpression.kt new file mode 100644 index 000000000000..ced16f893b90 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUDeclarationsExpression.kt @@ -0,0 +1,39 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UDeclaration +import org.jetbrains.uast.UDeclarationsExpression +import org.jetbrains.uast.UElement + +class JavaUDeclarationsExpression( + override val uastParent: UElement? +) : UDeclarationsExpression { + override lateinit var declarations: List + internal set + + constructor(parent: UElement?, declarations: List) : this(parent) { + this.declarations = declarations + } + + override val annotations: List + get() = emptyList() + + override val psi: PsiElement? + get() = null +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUExpressionList.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUExpressionList.kt new file mode 100644 index 000000000000..ccbe187409e0 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUExpressionList.kt @@ -0,0 +1,32 @@ +/* + * 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 org.jetbrains.uast.java.expressions + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.UExpressionList +import org.jetbrains.uast.UastSpecialExpressionKind +import org.jetbrains.uast.java.JavaAbstractUExpression + +open class JavaUExpressionList( + override val psi: PsiElement?, + override val kind: UastSpecialExpressionKind, // original element + override val uastParent: UElement? +) : JavaAbstractUExpression(), UExpressionList { + override lateinit var expressions: List + internal set +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceCheckExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceCheckExpression.kt new file mode 100644 index 000000000000..53c756b9353c --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceCheckExpression.kt @@ -0,0 +1,37 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiInstanceOfExpression +import com.intellij.psi.PsiType +import org.jetbrains.uast.UBinaryExpressionWithType +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UastBinaryExpressionWithTypeKind +import org.jetbrains.uast.UastErrorType + +class JavaUInstanceCheckExpression( + override val psi: PsiInstanceOfExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBinaryExpressionWithType { + override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) } + override val typeReference by lz { psi.checkType?.let { JavaUTypeReferenceExpression(it, this) } } + + override val type: PsiType + get() = psi.checkType?.type ?: UastErrorType + + override val operationKind: UastBinaryExpressionWithTypeKind.InstanceCheck + get() = UastBinaryExpressionWithTypeKind.INSTANCE_CHECK +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULabeledExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULabeledExpression.kt new file mode 100644 index 000000000000..f5464964791e --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULabeledExpression.kt @@ -0,0 +1,36 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiLabeledStatement +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.ULabeledExpression + +class JavaULabeledExpression( + override val psi: PsiLabeledStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), ULabeledExpression { + override val label: String + get() = psi.labelIdentifier.text + + override val labelIdentifier: UIdentifier? + get() = UIdentifier(psi.labelIdentifier, this) + + override val expression by lz { JavaConverter.convertOrEmpty(psi.statement, this) } + + override fun evaluate() = expression.evaluate() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULambdaExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULambdaExpression.kt new file mode 100644 index 000000000000..4f040cfecd61 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULambdaExpression.kt @@ -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 org.jetbrains.uast.java + +import com.intellij.psi.PsiCodeBlock +import com.intellij.psi.PsiExpression +import com.intellij.psi.PsiLambdaExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.ULambdaExpression +import org.jetbrains.uast.UastEmptyExpression + +class JavaULambdaExpression( + override val psi: PsiLambdaExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), ULambdaExpression { + override val valueParameters by lz { + psi.parameterList.parameters.map { JavaUParameter(it, this) } + } + + override val body by lz { + val b = psi.body + when (b) { + is PsiCodeBlock -> JavaConverter.convertBlock(b, this) + is PsiExpression -> JavaConverter.convertOrEmpty(b, this) + else -> UastEmptyExpression + } + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULiteralExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULiteralExpression.kt new file mode 100644 index 000000000000..10ed37cc6636 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaULiteralExpression.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiLiteralExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.ULiteralExpression + +class JavaULiteralExpression( + override val psi: PsiLiteralExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), ULiteralExpression { + override fun evaluate() = psi.value + override val value by lz { evaluate() } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUNamedExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUNamedExpression.kt new file mode 100644 index 000000000000..2377f9cd1954 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUNamedExpression.kt @@ -0,0 +1,38 @@ +/* + * 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 org.jetbrains.uast.java.expressions + +import com.intellij.psi.PsiNameValuePair +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.UNamedExpression +import org.jetbrains.uast.UastEmptyExpression +import org.jetbrains.uast.java.JavaAbstractUExpression +import org.jetbrains.uast.java.JavaConverter +import org.jetbrains.uast.java.lz + +class JavaUNamedExpression( + override val psi: PsiNameValuePair, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UNamedExpression { + override fun evaluate(): Any? = expression.evaluate() + + override val name: String? + get() = psi.name + + override val expression: UExpression by lz { + psi.value?.let { value -> JavaConverter.convertPsiElement(value, { this }) } as? UExpression ?: UastEmptyExpression } +} diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt new file mode 100644 index 000000000000..c4eaee44539f --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt @@ -0,0 +1,49 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiNewExpression +import com.intellij.psi.PsiType +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UObjectLiteralExpression +import org.jetbrains.uast.UReferenceExpression + +class JavaUObjectLiteralExpression( + override val psi: PsiNewExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UObjectLiteralExpression { + override val declaration by lz { JavaUClass.create(psi.anonymousClass!!, this) } + + override val classReference by lz { + psi.classReference?.let { ref -> + JavaConverter.convertReference(ref, { this }, null) as? UReferenceExpression + } + } + + override val valueArgumentCount: Int + get() = psi.argumentList?.expressions?.size ?: 0 + + override val valueArguments by lz { + psi.argumentList?.expressions?.map { JavaConverter.convertOrEmpty(it, this) } ?: emptyList() + } + + override val typeArgumentCount by lz { psi.classReference?.typeParameters?.size ?: 0 } + + override val typeArguments: List + get() = psi.classReference?.typeParameters?.toList() ?: emptyList() + + override fun resolve() = psi.resolveMethod() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUParenthesizedExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUParenthesizedExpression.kt new file mode 100644 index 000000000000..ce157b723754 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUParenthesizedExpression.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiParenthesizedExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UParenthesizedExpression + +class JavaUParenthesizedExpression( + override val psi: PsiParenthesizedExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UParenthesizedExpression { + override val expression by lz { JavaConverter.convertOrEmpty(psi.expression, this) } + override fun evaluate() = expression.evaluate() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPolyadicExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPolyadicExpression.kt new file mode 100644 index 000000000000..3c194395e781 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPolyadicExpression.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiPolyadicExpression +import org.jetbrains.uast.* + + +class JavaUPolyadicExpression( + override val psi: PsiPolyadicExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UPolyadicExpression { + override val operands: List by lz { + psi.operands.map { JavaConverter.convertOrEmpty(it, this) } + } + + override val operator: UastBinaryOperator by lz { psi.operationTokenType.getOperatorType() } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPostfixExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPostfixExpression.kt new file mode 100644 index 000000000000..b2bb60df5385 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPostfixExpression.kt @@ -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 org.jetbrains.uast.java + +import com.intellij.psi.JavaTokenType +import com.intellij.psi.PsiPostfixExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UPostfixExpression +import org.jetbrains.uast.UastPostfixOperator + +class JavaUPostfixExpression( + override val psi: PsiPostfixExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UPostfixExpression { + override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) } + + override val operatorIdentifier: UIdentifier? + get() = UIdentifier(psi.operationSign, this) + + override fun resolveOperator() = null + + override val operator = when (psi.operationTokenType) { + JavaTokenType.PLUSPLUS -> UastPostfixOperator.INC + JavaTokenType.MINUSMINUS -> UastPostfixOperator.DEC + else -> UastPostfixOperator.UNKNOWN + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPrefixExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPrefixExpression.kt new file mode 100644 index 000000000000..113c5fe785d4 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPrefixExpression.kt @@ -0,0 +1,45 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.JavaTokenType +import com.intellij.psi.PsiPrefixExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UPrefixExpression +import org.jetbrains.uast.UastPrefixOperator + +class JavaUPrefixExpression( + override val psi: PsiPrefixExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UPrefixExpression { + override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) } + + override val operatorIdentifier: UIdentifier? + get() = UIdentifier(psi.operationSign, this) + + override fun resolveOperator() = null + + override val operator = when (psi.operationTokenType) { + JavaTokenType.PLUS -> UastPrefixOperator.UNARY_PLUS + JavaTokenType.MINUS -> UastPrefixOperator.UNARY_MINUS + JavaTokenType.PLUSPLUS -> UastPrefixOperator.INC + JavaTokenType.MINUSMINUS-> UastPrefixOperator.DEC + JavaTokenType.EXCL -> UastPrefixOperator.LOGICAL_NOT + JavaTokenType.TILDE -> UastPrefixOperator.BITWISE_NOT + else -> UastPrefixOperator.UNKNOWN + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUQualifiedReferenceExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUQualifiedReferenceExpression.kt new file mode 100644 index 000000000000..bd4c288ceabc --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUQualifiedReferenceExpression.kt @@ -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 org.jetbrains.uast.java + +import com.intellij.psi.PsiJavaCodeReferenceElement +import com.intellij.psi.PsiNamedElement +import org.jetbrains.uast.* + +class JavaUQualifiedReferenceExpression( + override val psi: PsiJavaCodeReferenceElement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UQualifiedReferenceExpression { + override val receiver by lz { + psi.qualifier?.let { JavaConverter.convertPsiElement(it, { this }) as? UExpression } ?: UastEmptyExpression + } + + override val selector by lz { + JavaUSimpleNameReferenceExpression(psi.referenceNameElement, psi.referenceName ?: "", this, psi) + } + + override val accessType: UastQualifiedExpressionAccessType + get() = UastQualifiedExpressionAccessType.SIMPLE + + override val resolvedName: String? + get() = (psi.resolve() as? PsiNamedElement)?.name + + override fun resolve() = psi.resolve() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUReturnExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUReturnExpression.kt new file mode 100644 index 000000000000..a2e89847fefd --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUReturnExpression.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiReturnStatement +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UReturnExpression + +class JavaUReturnExpression( + override val psi: PsiReturnStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UReturnExpression { + override val returnExpression by lz { JavaConverter.convertOrNull(psi.returnValue, this) } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSimpleNameReferenceExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSimpleNameReferenceExpression.kt new file mode 100644 index 000000000000..0f5e5d674e6d --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSimpleNameReferenceExpression.kt @@ -0,0 +1,59 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.* +import org.jetbrains.uast.UElement +import org.jetbrains.uast.USimpleNameReferenceExpression +import org.jetbrains.uast.UTypeReferenceExpression + +class JavaUSimpleNameReferenceExpression( + override val psi: PsiElement?, + override val identifier: String, + override val uastParent: UElement?, + val reference: PsiReference? = null +) : JavaAbstractUExpression(), USimpleNameReferenceExpression { + override fun resolve() = (reference ?: psi as? PsiReference)?.resolve() + override val resolvedName: String? + get() = ((reference ?: psi as? PsiReference)?.resolve() as? PsiNamedElement)?.name +} + +class JavaUTypeReferenceExpression( + override val psi: PsiTypeElement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UTypeReferenceExpression { + override val type: PsiType + get() = psi.type +} + +class LazyJavaUTypeReferenceExpression( + override val psi: PsiElement, + override val uastParent: UElement?, + private val typeSupplier: () -> PsiType +) : JavaAbstractUExpression(), UTypeReferenceExpression { + override val type: PsiType by lz { typeSupplier() } +} + +class JavaClassUSimpleNameReferenceExpression( + override val identifier: String, + val ref: PsiJavaReference, + override val psi: PsiElement?, + override val uastParent: UElement? +) : JavaAbstractUExpression(), USimpleNameReferenceExpression { + override fun resolve() = ref.resolve() + override val resolvedName: String? + get() = (ref.resolve() as? PsiNamedElement)?.name +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSuperExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSuperExpression.kt new file mode 100644 index 000000000000..e033adbe11f9 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSuperExpression.kt @@ -0,0 +1,34 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiSuperExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.USuperExpression + +class JavaUSuperExpression( + override val psi: PsiSuperExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), USuperExpression { + override val label: String? + get() = psi.qualifier?.qualifiedName + + override val labelIdentifier: UIdentifier? + get() = psi.qualifier?.let { UIdentifier(it, this) } + + override fun resolve() = psi.qualifier?.resolve() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSynchronizedExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSynchronizedExpression.kt new file mode 100644 index 000000000000..9b2e110987f8 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUSynchronizedExpression.kt @@ -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 org.jetbrains.uast.java.expressions + +import com.intellij.psi.PsiSynchronizedStatement +import org.jetbrains.uast.UBlockExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.java.JavaAbstractUExpression +import org.jetbrains.uast.java.JavaConverter +import org.jetbrains.uast.java.lz +import org.jetbrains.uast.visitor.UastVisitor + +class JavaUSynchronizedExpression( + override val psi: PsiSynchronizedStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBlockExpression { + override val expressions by lz { psi.body?.statements?.map { JavaConverter.convertOrEmpty(it, this) } ?: listOf() } + val lockExpression by lz { JavaConverter.convertOrEmpty(psi.lockExpression, this) } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitBlockExpression(this)) return + expressions.acceptList(visitor) + lockExpression.accept(visitor) + visitor.afterVisitBlockExpression(this) + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThisExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThisExpression.kt new file mode 100644 index 000000000000..97facc8ffaca --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThisExpression.kt @@ -0,0 +1,34 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiThisExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UThisExpression + +class JavaUThisExpression( + override val psi: PsiThisExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UThisExpression { + override val label: String? + get() = psi.qualifier?.qualifiedName + + override val labelIdentifier: UIdentifier? + get() = psi.qualifier?.let { UIdentifier(it, this) } + + override fun resolve() = psi.qualifier?.resolve() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThrowExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThrowExpression.kt new file mode 100644 index 000000000000..a78402d2a6a2 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUThrowExpression.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiThrowStatement +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UThrowExpression + +class JavaUThrowExpression( + override val psi: PsiThrowStatement, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UThrowExpression { + override val thrownExpression by lz { JavaConverter.convertOrEmpty(psi.exception, this) } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUTypeCastExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUTypeCastExpression.kt new file mode 100644 index 000000000000..750bcff5cdaf --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUTypeCastExpression.kt @@ -0,0 +1,38 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiType +import com.intellij.psi.PsiTypeCastExpression +import org.jetbrains.uast.UBinaryExpressionWithType +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UastBinaryExpressionWithTypeKind +import org.jetbrains.uast.UastErrorType + +class JavaUTypeCastExpression( + override val psi: PsiTypeCastExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UBinaryExpressionWithType { + override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) } + + override val type: PsiType + get() = psi.castType?.type ?: UastErrorType + + override val typeReference by lz { psi.castType?.let { JavaUTypeReferenceExpression(it, this) } } + + override val operationKind: UastBinaryExpressionWithTypeKind.TypeCast + get() = UastBinaryExpressionWithTypeKind.TYPE_CAST +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/UnknownJavaExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/UnknownJavaExpression.kt new file mode 100644 index 000000000000..19278398b01d --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/UnknownJavaExpression.kt @@ -0,0 +1,31 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.PsiElement +import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression + +class UnknownJavaExpression( + override val psi: PsiElement, + override val uastParent: UElement? +) : UExpression { + override fun asLogString() = "[!] " + UnknownJavaExpression::class.java.simpleName + " ($psi)" + + override val annotations: List + get() = emptyList() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt new file mode 100644 index 000000000000..34f1f1d540e8 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt @@ -0,0 +1,225 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.psi.* +import com.intellij.psi.util.PsiTypesUtil +import org.jetbrains.uast.* +import org.jetbrains.uast.psi.UElementWithLocation + +class JavaUCallExpression( + override val psi: PsiMethodCallExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UCallExpression, UElementWithLocation { + override val kind: UastCallKind + get() = UastCallKind.METHOD_CALL + + override val methodIdentifier by lz { + val methodExpression = psi.methodExpression + val nameElement = methodExpression.referenceNameElement ?: return@lz null + UIdentifier(nameElement, this) + } + + override val classReference: UReferenceExpression? + get() = null + + override val valueArgumentCount by lz { psi.argumentList.expressions.size } + override val valueArguments by lz { psi.argumentList.expressions.map { JavaConverter.convertOrEmpty(it, this) } } + + override val typeArgumentCount by lz { psi.typeArguments.size } + + override val typeArguments: List + get() = psi.typeArguments.toList() + + override val returnType: PsiType? + get() = psi.type + + override val methodName: String? + get() = psi.methodExpression.referenceName + + override fun resolve() = psi.resolveMethod() + + override fun getStartOffset(): Int { + return psi.methodExpression.referenceNameElement?.textOffset ?: psi.methodExpression.textOffset + } + + override fun getEndOffset() = psi.textRange.endOffset + + override val receiver: UExpression? + get() { + return if (uastParent is UQualifiedReferenceExpression && uastParent.selector == this) + uastParent.receiver + else + null + } + + override val receiverType: PsiType? + get() { + val qualifierType = psi.methodExpression.qualifierExpression?.type + if (qualifierType != null) { + return qualifierType + } + + val method = resolve() ?: return null + if (method.hasModifierProperty(PsiModifier.STATIC)) return null + return method.containingClass?.let { PsiTypesUtil.getClassType(it) } + } +} + +class JavaConstructorUCallExpression( + override val psi: PsiNewExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UCallExpression { + override val kind by lz { + when { + psi.arrayInitializer != null -> UastCallKind.NEW_ARRAY_WITH_INITIALIZER + psi.arrayDimensions.isNotEmpty() -> UastCallKind.NEW_ARRAY_WITH_DIMENSIONS + else -> UastCallKind.CONSTRUCTOR_CALL + } + } + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference by lz { + psi.classReference?.let { ref -> + JavaConverter.convertReference(ref, { this }, null) as? UReferenceExpression + } + } + + override val valueArgumentCount: Int + get() { + val initializer = psi.arrayInitializer + return if (initializer != null) { + initializer.initializers.size + } else if (psi.arrayDimensions.isNotEmpty()) { + psi.arrayDimensions.size + } else { + psi.argumentList?.expressions?.size ?: 0 + } + } + + override val valueArguments by lz { + val initializer = psi.arrayInitializer + if (initializer != null) { + initializer.initializers.map { JavaConverter.convertOrEmpty(it, this) } + } + else if (psi.arrayDimensions.isNotEmpty()) { + psi.arrayDimensions.map { JavaConverter.convertOrEmpty(it, this) } + } + else { + psi.argumentList?.expressions?.map { JavaConverter.convertOrEmpty(it, this) } ?: emptyList() + } + } + + override val typeArgumentCount by lz { psi.classReference?.typeParameters?.size ?: 0 } + + override val typeArguments: List + get() = psi.classReference?.typeParameters?.toList() ?: emptyList() + + override val returnType: PsiType? + get() = (psi.classReference?.resolve() as? PsiClass)?.let { PsiTypesUtil.getClassType(it) } ?: psi.type + + override val methodName: String? + get() = null + + override fun resolve() = psi.resolveMethod() +} + +class JavaArrayInitializerUCallExpression( + override val psi: PsiArrayInitializerExpression, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UCallExpression { + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = null + + override val methodName: String? + get() = null + + override val valueArgumentCount by lz { psi.initializers.size } + override val valueArguments by lz { psi.initializers.map { JavaConverter.convertOrEmpty(it, this) } } + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val returnType: PsiType? + get() = psi.type + + override val kind: UastCallKind + get() = UastCallKind.NESTED_ARRAY_INITIALIZER + + override fun resolve() = null + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null +} + +class JavaAnnotationArrayInitializerUCallExpression( + override val psi: PsiArrayInitializerMemberValue, + override val uastParent: UElement? +) : JavaAbstractUExpression(), UCallExpression { + override val kind: UastCallKind + get() = UastCallKind.NESTED_ARRAY_INITIALIZER + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = null + + override val methodName: String? + get() = null + + override val valueArgumentCount by lz { psi.initializers.size } + + override val valueArguments by lz { + psi.initializers.map { + JavaConverter.convertPsiElement(it, { this }) as? UExpression ?: UnknownJavaExpression(it, this) + } + } + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val returnType: PsiType? + get() = null + + override fun resolve() = null + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/internal/JavaUElementWithComments.kt b/uast/uast-java/src/org/jetbrains/uast/java/internal/JavaUElementWithComments.kt new file mode 100644 index 000000000000..4d0d663306d6 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/internal/JavaUElementWithComments.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.uast.java.internal + +import com.intellij.psi.PsiComment +import org.jetbrains.uast.UComment +import org.jetbrains.uast.UElement + +interface JavaUElementWithComments : UElement { + override val comments: List + get() { + val psi = psi ?: return emptyList() + return psi.children.filter { it is PsiComment }.map { UComment(it, this) } + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt b/uast/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt new file mode 100644 index 000000000000..2fa1779809c7 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt @@ -0,0 +1,85 @@ +/* + * 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 org.jetbrains.uast.java + +import com.intellij.openapi.util.Key +import com.intellij.psi.JavaTokenType +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiModifierListOwner +import com.intellij.psi.impl.source.tree.CompositeElement +import com.intellij.psi.tree.IElementType +import org.jetbrains.uast.UDeclaration +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UastBinaryOperator +import java.lang.ref.WeakReference + +internal val JAVA_CACHED_UELEMENT_KEY = Key.create>("cached-java-uelement") + +internal fun IElementType.getOperatorType() = when (this) { + JavaTokenType.EQ -> UastBinaryOperator.ASSIGN + JavaTokenType.PLUS -> UastBinaryOperator.PLUS + JavaTokenType.MINUS -> UastBinaryOperator.MINUS + JavaTokenType.ASTERISK -> UastBinaryOperator.MULTIPLY + JavaTokenType.DIV -> UastBinaryOperator.DIV + JavaTokenType.PERC -> UastBinaryOperator.MOD + JavaTokenType.ANDAND -> UastBinaryOperator.LOGICAL_AND + JavaTokenType.OROR -> UastBinaryOperator.LOGICAL_OR + JavaTokenType.OR -> UastBinaryOperator.BITWISE_OR + JavaTokenType.AND -> UastBinaryOperator.BITWISE_AND + JavaTokenType.XOR -> UastBinaryOperator.BITWISE_XOR + JavaTokenType.EQEQ -> UastBinaryOperator.IDENTITY_EQUALS + JavaTokenType.NE -> UastBinaryOperator.IDENTITY_NOT_EQUALS + JavaTokenType.GT -> UastBinaryOperator.GREATER + JavaTokenType.GE -> UastBinaryOperator.GREATER_OR_EQUALS + JavaTokenType.LT -> UastBinaryOperator.LESS + JavaTokenType.LE -> UastBinaryOperator.LESS_OR_EQUALS + JavaTokenType.LTLT -> UastBinaryOperator.SHIFT_LEFT + JavaTokenType.GTGT -> UastBinaryOperator.SHIFT_RIGHT + JavaTokenType.GTGTGT -> UastBinaryOperator.UNSIGNED_SHIFT_RIGHT + JavaTokenType.PLUSEQ -> UastBinaryOperator.PLUS_ASSIGN + JavaTokenType.MINUSEQ -> UastBinaryOperator.MINUS_ASSIGN + JavaTokenType.ASTERISKEQ -> UastBinaryOperator.MULTIPLY_ASSIGN + JavaTokenType.DIVEQ -> UastBinaryOperator.DIVIDE_ASSIGN + JavaTokenType.PERCEQ -> UastBinaryOperator.REMAINDER_ASSIGN + JavaTokenType.ANDEQ -> UastBinaryOperator.AND_ASSIGN + JavaTokenType.XOREQ -> UastBinaryOperator.XOR_ASSIGN + JavaTokenType.OREQ -> UastBinaryOperator.OR_ASSIGN + JavaTokenType.LTLTEQ -> UastBinaryOperator.SHIFT_LEFT_ASSIGN + JavaTokenType.GTGTEQ -> UastBinaryOperator.SHIFT_RIGHT_ASSIGN + JavaTokenType.GTGTGTEQ -> UastBinaryOperator.UNSIGNED_SHIFT_RIGHT_ASSIGN + else -> UastBinaryOperator.OTHER +} + +internal fun singletonListOrEmpty(element: T?) = if (element != null) listOf(element) else emptyList() + +@Suppress("NOTHING_TO_INLINE") +internal inline fun String?.orAnonymous(kind: String = ""): String { + return this ?: "" +} + +internal fun lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer) + +val PsiModifierListOwner.annotations: Array + get() = modifierList?.annotations ?: emptyArray() + +internal inline fun unwrap(element: P): P { + val unwrapped = if (element is T) element.psi else element + assert(unwrapped !is UElement) + return unwrapped as P +} + +internal fun PsiElement.getChildByRole(role: Int) = (this as? CompositeElement)?.findChildByRoleAsPsiElement(role) \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaSpecialExpressionKinds.kt b/uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaSpecialExpressionKinds.kt new file mode 100644 index 000000000000..1fe99a24727e --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaSpecialExpressionKinds.kt @@ -0,0 +1,26 @@ +/* + * 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 org.jetbrains.uast.java.kinds + +import org.jetbrains.uast.UastSpecialExpressionKind + +object JavaSpecialExpressionKinds { + @JvmField + val SWITCH = UastSpecialExpressionKind("switch") + + @JvmField + val SWITCH_ENTRY = UastSpecialExpressionKind("switch_entry") +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaUastCallKinds.kt b/uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaUastCallKinds.kt new file mode 100644 index 000000000000..d0d2bf346184 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/kinds/JavaUastCallKinds.kt @@ -0,0 +1,23 @@ +/* + * 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 org.jetbrains.uast.java + +import org.jetbrains.uast.UastCallKind + +object JavaUastCallKinds { + @JvmField + val ASSERT = UastCallKind("assert") +} \ No newline at end of file diff --git a/uast/uast-java/uast-java.iml b/uast/uast-java/uast-java.iml new file mode 100644 index 000000000000..064a249359fa --- /dev/null +++ b/uast/uast-java/uast-java.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/common/RenderLogTestBase.kt b/uast/uast-tests/src/org/jetbrains/uast/test/common/RenderLogTestBase.kt new file mode 100644 index 000000000000..ff298fa82b76 --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/common/RenderLogTestBase.kt @@ -0,0 +1,36 @@ +/* + * 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 org.jetbrains.uast.test.common + +import org.jetbrains.uast.UFile +import org.jetbrains.uast.asRecursiveLogString +import org.jetbrains.uast.test.env.assertEqualsToFile +import java.io.File + +interface RenderLogTestBase { + fun getTestFile(testName: String, ext: String): File + + private fun getRenderFile(testName: String) = getTestFile(testName, "render.txt") + private fun getLogFile(testName: String) = getTestFile(testName, "log.txt") + + fun check(testName: String, file: UFile) { + val renderFile = getRenderFile(testName) + val logFile = getLogFile(testName) + + assertEqualsToFile("Render string", renderFile, file.asRenderString()) + assertEqualsToFile("Log string", logFile, file.asRecursiveLogString()) + } +} \ No newline at end of file diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/common/ResolveTestBase.kt b/uast/uast-tests/src/org/jetbrains/uast/test/common/ResolveTestBase.kt new file mode 100644 index 000000000000..4ac8b9a541fc --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/common/ResolveTestBase.kt @@ -0,0 +1,36 @@ +/* + * 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 org.jetbrains.uast.test.common + +import com.intellij.psi.PsiNamedElement +import org.jetbrains.uast.UFile +import org.jetbrains.uast.UResolvable +import org.jetbrains.uast.test.env.findElementByText +import org.junit.Assert.assertEquals + +interface ResolveTestBase { + fun check(testName: String, file: UFile) { + val refComment = file.allCommentsInFile.find { it.text.startsWith("// REF:") } ?: throw IllegalArgumentException("No // REF tag in file") + val resultComment = file.allCommentsInFile.find { it.text.startsWith("// RESULT:") } ?: throw IllegalArgumentException("No // RESULT tag in file") + + val refText = refComment.text.substringAfter("REF:") + val parent = refComment.uastParent + val matchingElement = parent.findElementByText(refText) + val resolveResult = matchingElement.resolve() ?: throw IllegalArgumentException("Unresolved reference") + val resultText = resolveResult.javaClass.simpleName + (if (resolveResult is PsiNamedElement) ":${resolveResult.name}" else "") + assertEquals(resultComment.text.substringAfter("RESULT:"), resultText) + } +} diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/common/TypesTestBase.kt b/uast/uast-tests/src/org/jetbrains/uast/test/common/TypesTestBase.kt new file mode 100644 index 000000000000..316400de07a2 --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/common/TypesTestBase.kt @@ -0,0 +1,71 @@ +/* + * 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 org.jetbrains.uast.test.common + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.UFile +import org.jetbrains.uast.test.env.assertEqualsToFile +import org.jetbrains.uast.visitor.UastVisitor +import java.io.File + +interface TypesTestBase { + fun getTypesFile(testName: String): File + + private fun UFile.asLogTypes() = TypesLogger().apply { + this@asLogTypes.accept(this) + }.toString() + + fun check(testName: String, file: UFile) { + val valuesFile = getTypesFile(testName) + + assertEqualsToFile("Log values", valuesFile, file.asLogTypes()) + } + + class TypesLogger : UastVisitor { + + val builder = StringBuilder() + + var level = 0 + + override fun visitElement(node: UElement): Boolean { + val initialLine = node.asLogString() + " [" + run { + val renderString = node.asRenderString().lines() + if (renderString.size == 1) { + renderString.single() + } else { + renderString.first() + "..." + renderString.last() + } + } + "]" + + (1..level).forEach { builder.append(" ") } + builder.append(initialLine) + if (node is UExpression) { + val value = node.getExpressionType() + value?.let { builder.append(" : ").append(it) } + } + builder.appendln() + level++ + return false + } + + override fun afterVisitElement(node: UElement) { + level-- + } + + override fun toString() = builder.toString() + } +} \ No newline at end of file diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/common/ValuesTestBase.kt b/uast/uast-tests/src/org/jetbrains/uast/test/common/ValuesTestBase.kt new file mode 100644 index 000000000000..9c9e198f8b63 --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/common/ValuesTestBase.kt @@ -0,0 +1,78 @@ +/* + * 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 org.jetbrains.uast.test.common + +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression +import org.jetbrains.uast.UFile +import org.jetbrains.uast.evaluation.UEvaluationContext +import org.jetbrains.uast.evaluation.UEvaluatorExtension +import org.jetbrains.uast.evaluation.analyzeAll +import org.jetbrains.uast.test.env.assertEqualsToFile +import org.jetbrains.uast.visitor.UastVisitor +import java.io.File + +interface ValuesTestBase { + fun getValuesFile(testName: String): File + fun getEvaluatorExtension(): UEvaluatorExtension? = null + + private fun UFile.asLogValues(): String { + val evaluationContext = analyzeAll(extensions = getEvaluatorExtension()?.let { listOf(it) } ?: emptyList()) + return ValueLogger(evaluationContext).apply { + this@asLogValues.accept(this) + }.toString() + } + + fun check(testName: String, file: UFile) { + val valuesFile = getValuesFile(testName) + + assertEqualsToFile("Log values", valuesFile, file.asLogValues()) + } + + class ValueLogger(val evaluationContext: UEvaluationContext) : UastVisitor { + + val builder = StringBuilder() + + var level = 0 + + override fun visitElement(node: UElement): Boolean { + val initialLine = node.asLogString() + " [" + run { + val renderString = node.asRenderString().lines() + if (renderString.size == 1) { + renderString.single() + } else { + renderString.first() + "..." + renderString.last() + } + } + "]" + + (1..level).forEach { builder.append(" ") } + builder.append(initialLine) + if (node is UExpression) { + val value = evaluationContext.valueOf(node) + builder.append(" = ").append(value) + } + builder.appendln() + level++ + return false + } + + override fun afterVisitElement(node: UElement) { + level-- + } + + override fun toString() = builder.toString() + } +} \ No newline at end of file diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractCoreEnvironment.kt b/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractCoreEnvironment.kt new file mode 100644 index 000000000000..a77433fcf830 --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractCoreEnvironment.kt @@ -0,0 +1,30 @@ +/* + * 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 org.jetbrains.uast.test.env + +import com.intellij.mock.MockProject +import java.io.File + +abstract class AbstractCoreEnvironment { + abstract val project: MockProject + + open fun dispose() { + // Do nothing + } + + abstract fun addJavaSourceRoot(root: File) + abstract fun addJar(root: File) +} \ No newline at end of file diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractTestWithCoreEnvironment.kt b/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractTestWithCoreEnvironment.kt new file mode 100644 index 000000000000..f83dc2570d98 --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractTestWithCoreEnvironment.kt @@ -0,0 +1,107 @@ +/* + * 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 org.jetbrains.uast.test.env + +import com.intellij.core.CoreApplicationEnvironment +import com.intellij.mock.MockProject +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiManager +import com.intellij.rt.execution.junit.FileComparisonFailure +import junit.framework.TestCase +import org.jetbrains.uast.UastContext +import org.jetbrains.uast.UastLanguagePlugin +import org.jetbrains.uast.evaluation.UEvaluatorExtension +import org.jetbrains.uast.java.JavaUastLanguagePlugin +import java.io.File + +abstract class AbstractTestWithCoreEnvironment : TestCase() { + private var myEnvironment: AbstractCoreEnvironment? = null + + protected val environment: AbstractCoreEnvironment + get() = myEnvironment!! + + protected lateinit var project: MockProject + + protected val uastContext: UastContext by lazy { + ServiceManager.getService(project, UastContext::class.java) + } + + protected val psiManager: PsiManager by lazy { + PsiManager.getInstance(project) + } + + override fun tearDown() { + disposeEnvironment() + } + + protected abstract fun createEnvironment(source: File): AbstractCoreEnvironment + + protected fun initializeEnvironment(source: File) { + if (myEnvironment != null) { + error("Environment is already initialized") + } + myEnvironment = createEnvironment(source) + project = environment.project + + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), + UastLanguagePlugin.extensionPointName, + UastLanguagePlugin::class.java) + + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), + UEvaluatorExtension.EXTENSION_POINT_NAME, + UEvaluatorExtension::class.java) + + project.registerService(UastContext::class.java, UastContext::class.java) + + registerUastLanguagePlugins() + } + + private fun registerUastLanguagePlugins() { + val area = Extensions.getRootArea() + + area.getExtensionPoint(UastLanguagePlugin.extensionPointName) + .registerExtension(JavaUastLanguagePlugin()) + } + + protected fun disposeEnvironment() { + myEnvironment?.dispose() + myEnvironment = null + } +} + +private fun String.trimTrailingWhitespacesAndAddNewlineAtEOF(): String = + this.split('\n').map(String::trimEnd).joinToString(separator = "\n").let { + result -> if (result.endsWith("\n")) result else result + "\n" + } + +fun assertEqualsToFile(description: String, expected: File, actual: String) { + if (!expected.exists()) { + expected.writeText(actual) + TestCase.fail("File didn't exist. New file was created (${expected.canonicalPath}).") + } + + val expectedText = + StringUtil.convertLineSeparators(expected.readText().trim()).trimTrailingWhitespacesAndAddNewlineAtEOF() + val actualText = + StringUtil.convertLineSeparators(actual.trim()).trimTrailingWhitespacesAndAddNewlineAtEOF() + if (expectedText != actualText) { + throw FileComparisonFailure(description, expectedText, actualText, expected.absolutePath) + } +} diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractUastTest.kt b/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractUastTest.kt new file mode 100644 index 000000000000..3e38a87fff58 --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/env/AbstractUastTest.kt @@ -0,0 +1,61 @@ +/* + * 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 org.jetbrains.uast.test.env + +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UFile +import org.jetbrains.uast.visitor.UastVisitor +import java.io.File + +abstract class AbstractUastTest : AbstractTestWithCoreEnvironment() { + protected companion object { + val TEST_DATA_DIR = File("testData") + } + + abstract fun getVirtualFile(testName: String): VirtualFile + abstract fun check(testName: String, file: UFile) + + fun doTest(testName: String, checkCallback: (String, UFile) -> Unit = { testName, file -> check(testName, file) }) { + val virtualFile = getVirtualFile(testName) + + val psiFile = psiManager.findFile(virtualFile) ?: error("Can't get psi file for $testName") + val uFile = uastContext.convertElementWithParent(psiFile, null) ?: error("Can't get UFile for $testName") + checkCallback(testName, uFile as UFile) + } +} + +fun UElement.findElementByText(refText: String, cls: Class): T { + val matchingElements = mutableListOf() + accept(object : UastVisitor { + override fun visitElement(node: UElement): Boolean { + if (cls.isInstance(node) && node.psi?.text == refText) { + matchingElements.add(node as T) + } + return false + } + }) + + if (matchingElements.isEmpty()) { + throw IllegalArgumentException("Reference '$refText' not found") + } + if (matchingElements.size != 1) { + throw IllegalArgumentException("Reference '$refText' is ambiguous") + } + return matchingElements.single() +} + +inline fun UElement.findElementByText(refText: String): T = findElementByText(refText, T::class.java) diff --git a/uast/uast-tests/src/org/jetbrains/uast/test/env/TestCoreEnvironment.java b/uast/uast-tests/src/org/jetbrains/uast/test/env/TestCoreEnvironment.java new file mode 100644 index 000000000000..e1e8de71f26e --- /dev/null +++ b/uast/uast-tests/src/org/jetbrains/uast/test/env/TestCoreEnvironment.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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 org.jetbrains.uast.test.env; + +import com.intellij.codeInsight.ContainerProvider; +import com.intellij.codeInsight.runner.JavaMainMethodProvider; +import com.intellij.core.CoreApplicationEnvironment; +import com.intellij.core.CoreJavaFileManager; +import com.intellij.core.JavaCoreApplicationEnvironment; +import com.intellij.core.JavaCoreProjectEnvironment; +import com.intellij.mock.MockProject; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.ExtensionsArea; +import com.intellij.openapi.fileTypes.FileTypeExtensionPoint; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.StandardFileSystems; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.openapi.vfs.impl.ZipHandler; +import com.intellij.psi.FileContextProvider; +import com.intellij.psi.PsiElementFinder; +import com.intellij.psi.augment.PsiAugmentProvider; +import com.intellij.psi.compiled.ClassFileDecompilers; +import com.intellij.psi.impl.JavaClassSupersImpl; +import com.intellij.psi.impl.PsiElementFinderImpl; +import com.intellij.psi.impl.PsiTreeChangePreprocessor; +import com.intellij.psi.impl.compiled.ClsCustomNavigationPolicy; +import com.intellij.psi.impl.file.impl.JavaFileManager; +import com.intellij.psi.meta.MetaDataContributor; +import com.intellij.psi.stubs.BinaryFileStubBuilders; +import com.intellij.psi.util.JavaClassSupers; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +public class TestCoreEnvironment extends AbstractCoreEnvironment { + private static final Object APPLICATION_LOCK = new Object(); + private static volatile JavaCoreApplicationEnvironment sEnvironment = null; + + private final Disposable mDisposable; + private volatile JavaCoreProjectEnvironment mProjectEnvironment = null; + + public TestCoreEnvironment(Disposable disposable) { + mDisposable = disposable; + } + + @Override + public void dispose() { + Disposer.dispose(mDisposable); + } + + @Override + public MockProject getProject() { + JavaCoreProjectEnvironment projectEnvironment = getProjectEnvironment(); + if (projectEnvironment == null) { + return null; + } + return projectEnvironment.getProject(); + } + + @Override + public void addJavaSourceRoot(@NotNull File root) { + VirtualFileSystem vfs = StandardFileSystems.local(); + try { + addDirectoryToClassPath(vfs, root); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addDirectoryToClassPath(VirtualFileSystem vfs, File root) throws IOException { + VirtualFile virtualFile = vfs.findFileByPath(root.getCanonicalPath()); + assert virtualFile != null; + getProjectEnvironment().addSourcesToClasspath(virtualFile); + } + + public void addJar(@NotNull File root) { + getProjectEnvironment().addJarToClassPath(root); + } + + public JavaCoreProjectEnvironment getProjectEnvironment() { + if (mProjectEnvironment != null) { + return mProjectEnvironment; + } + synchronized (APPLICATION_LOCK) { + if (mProjectEnvironment != null) { + return mProjectEnvironment; + } + JavaCoreApplicationEnvironment coreEnvironment = getCoreEnvironment(); + + mProjectEnvironment = new TestJavaCoreProjectEnvironment(coreEnvironment); + + Disposer.register(mDisposable, new Disposable() { + @Override + public void dispose() { + mProjectEnvironment = null; + } + }); + + return mProjectEnvironment; + } + } + + private static JavaCoreApplicationEnvironment getCoreEnvironment() { + if (sEnvironment != null) { + return sEnvironment; + } + synchronized (APPLICATION_LOCK) { + if (sEnvironment != null) { + return sEnvironment; + } + Disposable parentDisposable = Disposer.newDisposable(); + Extensions.cleanRootArea(parentDisposable); + registerAppExtensionPoints(); + JavaCoreApplicationEnvironment coreEnvironment = new JavaCoreApplicationEnvironment(parentDisposable); + coreEnvironment.registerApplicationService(JavaClassSupers.class, new JavaClassSupersImpl()); + + sEnvironment = coreEnvironment; + + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + synchronized (APPLICATION_LOCK) { + JavaCoreApplicationEnvironment environment = sEnvironment; + sEnvironment = null; + Disposer.dispose(environment.getParentDisposable()); + ZipHandler.clearFileAccessorCache(); + } + } + }); + return sEnvironment; + } + } + + private static void registerAppExtensionPoints() { + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class); + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), FileContextProvider.EP_NAME, FileContextProvider.class); + // + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), MetaDataContributor.EP_NAME, MetaDataContributor.class); + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class); + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class); + // + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), ContainerProvider.EP_NAME, ContainerProvider.class); + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), ClsCustomNavigationPolicy.EP_NAME, ClsCustomNavigationPolicy.class); + CoreApplicationEnvironment.registerExtensionPoint( + Extensions.getRootArea(), ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class); + } + + private class TestJavaCoreProjectEnvironment extends JavaCoreProjectEnvironment { + TestJavaCoreProjectEnvironment(JavaCoreApplicationEnvironment coreEnvironment) { + super(TestCoreEnvironment.this.mDisposable, coreEnvironment); + registerProjectExtensions(); + } + + @Override + protected void preregisterServices() { + registerProjectExtensionPoints(); + } + + private void registerProjectExtensionPoints() { + ExtensionsArea area = Extensions.getArea(myProject); + CoreApplicationEnvironment.registerExtensionPoint( + area, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor.class); + CoreApplicationEnvironment.registerExtensionPoint( + area, PsiElementFinder.EP_NAME, PsiElementFinder.class); + } + + private void registerProjectExtensions() { + ExtensionsArea area = Extensions.getArea(myProject); + + myProject.registerService(CoreJavaFileManager.class, + ((CoreJavaFileManager) ServiceManager.getService(myProject, JavaFileManager.class))); + + area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension( + new PsiElementFinderImpl(myProject, ServiceManager + .getService(myProject, JavaFileManager.class))); + } + } +} diff --git a/uast/uast-tests/uast-tests.iml b/uast/uast-tests/uast-tests.iml new file mode 100644 index 000000000000..190539c29448 --- /dev/null +++ b/uast/uast-tests/uast-tests.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uast/updateDependencies.gradle b/uast/updateDependencies.gradle new file mode 100644 index 000000000000..e477574f445f --- /dev/null +++ b/uast/updateDependencies.gradle @@ -0,0 +1,20 @@ +apply plugin: 'de.undercouch.download' + +task updateDependencies { + def downloadDir = new File(project.rootDir, "lib/download") + downloadDir.mkdirs() + + def intellijCoreZip = new File(downloadDir, "intellij-core.zip") + + download { + src "https://s3-eu-west-1.amazonaws.com/intellij-releases/com/jetbrains/intellij/idea/intellij-core/" + + "$intellij_core_version/intellij-core-${intellij_core_version}.zip" + dest intellijCoreZip + onlyIfNewer true + } + + copy { + from zipTree(intellijCoreZip) + into new File("lib/intellij-core") + } +} \ No newline at end of file