From 117bc0c483b4417d5450af7884a33428d646ea54 Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Thu, 8 Mar 2018 07:34:22 +0100 Subject: [PATCH] Bump checkerframework to 2.2.2 and stop building from source Fixes: #4709. This change stops building checker framework from the source and consumes the artifacts from Central. As the consequence, the sources are removed from the Bazel tree and we discontinue packaging the sources in Bazel source artifact. LGPL sources are still have to be included in embeded_tools archive. The source jars are included in embedded_tools archive now: $ unzip -t bazel-genfiles/src/embedded_tools.zip|grep checker_framework testing: third_party/checker_framework_dataflow/dataflow-2.2.2-sources.jar testing: third_party/checker_framework_javacutil/javacutil-2.2.2-sources.jar --- src/main/tools/jdk.BUILD | 6 - third_party/BUILD | 4 +- third_party/checker_framework_dataflow/BUILD | 19 +- .../dataflow-2.2.2-sources.jar | Bin 0 -> 160063 bytes .../dataflow-2.2.2.jar | Bin 0 -> 302199 bytes .../dataflow/analysis/AbstractValue.java | 25 - .../dataflow/analysis/Analysis.java | 767 --- .../dataflow/analysis/AnalysisResult.java | 220 - .../analysis/ConditionalTransferResult.java | 126 - .../dataflow/analysis/FlowExpressions.java | 1143 ----- .../analysis/RegularTransferResult.java | 116 - .../dataflow/analysis/Store.java | 91 - .../dataflow/analysis/TransferFunction.java | 41 - .../dataflow/analysis/TransferInput.java | 250 - .../dataflow/analysis/TransferResult.java | 104 - .../dataflow/cfg/CFGBuilder.java | 4491 ----------------- .../dataflow/cfg/CFGVisualizer.java | 167 - .../dataflow/cfg/ControlFlowGraph.java | 246 - .../dataflow/cfg/DOTCFGVisualizer.java | 511 -- .../dataflow/cfg/JavaSource2CFGDOT.java | 269 - .../dataflow/cfg/UnderlyingAST.java | 125 - .../dataflow/cfg/block/Block.java | 31 - .../dataflow/cfg/block/BlockImpl.java | 57 - .../dataflow/cfg/block/ConditionalBlock.java | 30 - .../cfg/block/ConditionalBlockImpl.java | 81 - .../dataflow/cfg/block/ExceptionBlock.java | 27 - .../cfg/block/ExceptionBlockImpl.java | 66 - .../dataflow/cfg/block/RegularBlock.java | 27 - .../dataflow/cfg/block/RegularBlockImpl.java | 59 - .../cfg/block/SingleSuccessorBlock.java | 24 - .../cfg/block/SingleSuccessorBlockImpl.java | 45 - .../dataflow/cfg/block/SpecialBlock.java | 31 - .../dataflow/cfg/block/SpecialBlockImpl.java | 22 - .../cfg/node/AbstractNodeVisitor.java | 374 -- .../dataflow/cfg/node/ArrayAccessNode.java | 81 - .../dataflow/cfg/node/ArrayCreationNode.java | 136 - .../dataflow/cfg/node/ArrayTypeNode.java | 60 - .../dataflow/cfg/node/AssertionErrorNode.java | 80 - .../dataflow/cfg/node/AssignmentContext.java | 126 - .../dataflow/cfg/node/AssignmentNode.java | 93 - .../cfg/node/BinaryOperationNode.java | 52 - .../dataflow/cfg/node/BitwiseAndNode.java | 48 - .../cfg/node/BitwiseComplementNode.java | 47 - .../dataflow/cfg/node/BitwiseOrNode.java | 48 - .../dataflow/cfg/node/BitwiseXorNode.java | 48 - .../dataflow/cfg/node/BooleanLiteralNode.java | 49 - .../dataflow/cfg/node/CaseNode.java | 81 - .../cfg/node/CharacterLiteralNode.java | 51 - .../dataflow/cfg/node/ClassNameNode.java | 120 - .../dataflow/cfg/node/ConditionalAndNode.java | 48 - .../dataflow/cfg/node/ConditionalNotNode.java | 47 - .../dataflow/cfg/node/ConditionalOrNode.java | 47 - .../dataflow/cfg/node/DoubleLiteralNode.java | 50 - .../dataflow/cfg/node/EqualToNode.java | 47 - .../cfg/node/ExplicitThisLiteralNode.java | 41 - .../dataflow/cfg/node/FieldAccessNode.java | 106 - .../dataflow/cfg/node/FloatLiteralNode.java | 50 - .../cfg/node/FloatingDivisionNode.java | 48 - .../cfg/node/FloatingRemainderNode.java | 48 - .../cfg/node/FunctionalInterfaceNode.java | 90 - .../dataflow/cfg/node/GreaterThanNode.java | 48 - .../cfg/node/GreaterThanOrEqualNode.java | 48 - .../cfg/node/ImplicitThisLiteralNode.java | 31 - .../dataflow/cfg/node/InstanceOfNode.java | 87 - .../cfg/node/IntegerDivisionNode.java | 48 - .../dataflow/cfg/node/IntegerLiteralNode.java | 51 - .../cfg/node/IntegerRemainderNode.java | 48 - .../dataflow/cfg/node/LeftShiftNode.java | 48 - .../dataflow/cfg/node/LessThanNode.java | 51 - .../cfg/node/LessThanOrEqualNode.java | 48 - .../dataflow/cfg/node/LocalVariableNode.java | 101 - .../dataflow/cfg/node/LongLiteralNode.java | 50 - .../dataflow/cfg/node/MarkerNode.java | 82 - .../dataflow/cfg/node/MethodAccessNode.java | 78 - .../cfg/node/MethodInvocationNode.java | 126 - .../cfg/node/NarrowingConversionNode.java | 76 - .../dataflow/cfg/node/Node.java | 144 - .../dataflow/cfg/node/NodeVisitor.java | 160 - .../dataflow/cfg/node/NotEqualNode.java | 48 - .../dataflow/cfg/node/NullChkNode.java | 69 - .../dataflow/cfg/node/NullLiteralNode.java | 49 - .../cfg/node/NumericalAdditionNode.java | 47 - .../dataflow/cfg/node/NumericalMinusNode.java | 47 - .../cfg/node/NumericalMultiplicationNode.java | 48 - .../dataflow/cfg/node/NumericalPlusNode.java | 47 - .../cfg/node/NumericalSubtractionNode.java | 48 - .../dataflow/cfg/node/ObjectCreationNode.java | 101 - .../dataflow/cfg/node/PackageNameNode.java | 101 - .../cfg/node/ParameterizedTypeNode.java | 67 - .../dataflow/cfg/node/PrimitiveTypeNode.java | 60 - .../dataflow/cfg/node/ReturnNode.java | 100 - .../dataflow/cfg/node/ShortLiteralNode.java | 54 - .../cfg/node/SignedRightShiftNode.java | 48 - .../node/StringConcatenateAssignmentNode.java | 57 - .../cfg/node/StringConcatenateNode.java | 48 - .../cfg/node/StringConversionNode.java | 76 - .../dataflow/cfg/node/StringLiteralNode.java | 53 - .../dataflow/cfg/node/SuperNode.java | 66 - .../dataflow/cfg/node/SynchronizedNode.java | 89 - .../cfg/node/TernaryExpressionNode.java | 94 - .../dataflow/cfg/node/ThisLiteralNode.java | 45 - .../dataflow/cfg/node/ThrowNode.java | 69 - .../dataflow/cfg/node/TypeCastNode.java | 72 - .../dataflow/cfg/node/UnaryOperationNode.java | 45 - .../cfg/node/UnsignedRightShiftNode.java | 48 - .../dataflow/cfg/node/ValueLiteralNode.java | 72 - .../cfg/node/VariableDeclarationNode.java | 71 - .../cfg/node/WideningConversionNode.java | 76 - .../ConstantPropagationPlayground.java | 27 - .../constantpropagation/Constant.java | 102 - .../ConstantPropagationStore.java | 163 - .../ConstantPropagationTransfer.java | 85 - .../dataflow/qual/Deterministic.java | 87 - .../checkerframework/dataflow/qual/Pure.java | 30 - .../dataflow/qual/SideEffectFree.java | 54 - .../dataflow/qual/TerminatesExecution.java | 34 - .../dataflow/util/HashCodeUtils.java | 102 - .../dataflow/util/MostlySingleton.java | 151 - .../dataflow/util/NodeUtils.java | 56 - .../dataflow/util/PurityChecker.java | 491 -- .../dataflow/util/PurityUtils.java | 91 - third_party/checker_framework_javacutil/BUILD | 18 +- .../javacutil/AbstractTypeProcessor.java | 196 - .../javacutil/AnnotationProvider.java | 28 - .../javacutil/AnnotationUtils.java | 650 --- .../javacutil/BasicAnnotationProvider.java | 29 - .../javacutil/BasicTypeProcessor.java | 37 - .../javacutil/CollectionUtils.java | 26 - .../javacutil/ElementUtils.java | 492 -- .../javacutil/ErrorHandler.java | 17 - .../javacutil/ErrorReporter.java | 54 - .../javacutil/InternalUtils.java | 483 -- .../org/checkerframework/javacutil/Pair.java | 69 - .../checkerframework/javacutil/Resolver.java | 397 -- .../checkerframework/javacutil/TreeUtils.java | 1020 ---- .../javacutil/TypeAnnotationUtils.java | 397 -- .../javacutil/TypesUtils.java | 452 -- .../javacutil/dist/ManualTaglet.java | 124 - .../javacutil/trees/DetachedVarSymbol.java | 36 - .../javacutil/trees/TreeBuilder.java | 655 --- .../javacutil/trees/TreeParser.java | 141 - .../javacutil-2.2.2-sources.jar | Bin 0 -> 55437 bytes .../javacutil-2.2.2.jar | Bin 0 -> 91671 bytes tools/jdk/BUILD | 6 - 144 files changed, 13 insertions(+), 21364 deletions(-) create mode 100644 third_party/checker_framework_dataflow/dataflow-2.2.2-sources.jar create mode 100644 third_party/checker_framework_dataflow/dataflow-2.2.2.jar delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AbstractValue.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java delete mode 100644 third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java delete mode 100644 third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java create mode 100644 third_party/checker_framework_javacutil/javacutil-2.2.2-sources.jar create mode 100644 third_party/checker_framework_javacutil/javacutil-2.2.2.jar diff --git a/src/main/tools/jdk.BUILD b/src/main/tools/jdk.BUILD index 48df3b6e7ee23d..9a1a2770aca5e9 100644 --- a/src/main/tools/jdk.BUILD +++ b/src/main/tools/jdk.BUILD @@ -162,12 +162,6 @@ filegroup( srcs = ["lib/tools.jar"], ) -java_import( - name = "langtools-neverlink", - jars = ["lib/tools.jar"], - neverlink = 1, -) - config_setting( name = "windows", values = {"cpu": "x64_windows"}, diff --git a/third_party/BUILD b/third_party/BUILD index ae0051004992aa..3708ec52f9176a 100644 --- a/third_party/BUILD +++ b/third_party/BUILD @@ -23,8 +23,6 @@ filegroup( "//third_party/java/jdk/javabuilder:srcs", "//third_party/java/proguard:srcs", "//third_party/javascript/bootstrap:srcs", - "//third_party/checker_framework_dataflow:srcs", - "//third_party/checker_framework_javacutil:srcs", "//third_party/jformatstring:srcs", "//third_party/protobuf:srcs", "//third_party/py/abseil:srcs", @@ -385,7 +383,7 @@ filegroup( "jcip_annotations/jcip-annotations-1.0-1.jar", "jsr305/jsr-305.jar", "pcollections/pcollections-2.1.2.jar", - "//third_party/checker_framework_dataflow:bootstrap", + "//third_party/checker_framework_dataflow", "//third_party/jformatstring:bootstrap", ], ) diff --git a/third_party/checker_framework_dataflow/BUILD b/third_party/checker_framework_dataflow/BUILD index b1742550117e53..240c1ff755575c 100644 --- a/third_party/checker_framework_dataflow/BUILD +++ b/third_party/checker_framework_dataflow/BUILD @@ -4,23 +4,16 @@ licenses(["restricted"]) # GNU GPL v2 with Classpath exception filegroup( name = "srcs", - srcs = glob(["**"]), + srcs = ["dataflow-2.2.2-sources.jar"], ) -java_library( +java_import( name = "checker_framework_dataflow", - srcs = glob(["java/**"]), - javacopts = ["-Xep:MissingCasesInEnumSwitch:OFF"], + jars = [ + "dataflow-2.2.2.jar", + ], + srcjar = "dataflow-2.2.2-sources.jar", deps = [ "//third_party/checker_framework_javacutil", - "@local_jdk//:langtools-neverlink", ], ) - -load("//tools/build_rules:java_rules_skylark.bzl", "bootstrap_java_library") - -bootstrap_java_library( - name = "bootstrap", - srcs = glob(["java/**"]), - deps = ["//third_party/checker_framework_javacutil:bootstrap"], -) diff --git a/third_party/checker_framework_dataflow/dataflow-2.2.2-sources.jar b/third_party/checker_framework_dataflow/dataflow-2.2.2-sources.jar new file mode 100644 index 0000000000000000000000000000000000000000..4191b63c1cd9d8dafed6c53ef83bbf172a1daed2 GIT binary patch literal 160063 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

`1PaMFWkOGm3Sf8b@u?@hV4Tv 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

l=5k^MA$X@2lMbjdMs6j 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 { - - /** - * Compute the least upper bound of two stores. - * - *

Important: This method must fulfill the following contract: - * - *

    - *
  • Does not change {@code this}. - *
  • Does not change {@code other}. - *
  • Returns a fresh object which is not aliased yet. - *
  • Returns an object of the same (dynamic) type as {@code this}, even if the signature is - * more permissive. - *
  • Is commutative. - *
- */ - V leastUpperBound(V other); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java deleted file mode 100644 index 2e81b4af4ac353..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java +++ /dev/null @@ -1,767 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.LambdaExpressionTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.VariableTree; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.PriorityQueue; -import java.util.Set; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.cfg.ControlFlowGraph; -import org.checkerframework.dataflow.cfg.UnderlyingAST; -import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda; -import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod; -import org.checkerframework.dataflow.cfg.UnderlyingAST.Kind; -import org.checkerframework.dataflow.cfg.block.Block; -import org.checkerframework.dataflow.cfg.block.ConditionalBlock; -import org.checkerframework.dataflow.cfg.block.ExceptionBlock; -import org.checkerframework.dataflow.cfg.block.RegularBlock; -import org.checkerframework.dataflow.cfg.block.SpecialBlock; -import org.checkerframework.dataflow.cfg.node.AssignmentNode; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.ReturnNode; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.Pair; - -/** - * An implementation of an iterative algorithm to solve a org.checkerframework.dataflow problem, - * given a control flow graph and a transfer function. - * - * @author Stefan Heule - * @param the abstract value type to be tracked by the analysis - * @param the store type used in the analysis - * @param the transfer function type that is used to approximated runtime behavior - */ -public class Analysis< - A extends AbstractValue, S extends Store, T extends TransferFunction> { - - /** Is the analysis currently running? */ - protected boolean isRunning = false; - - /** The transfer function for regular nodes. */ - protected T transferFunction; - - /** The control flow graph to perform the analysis on. */ - protected ControlFlowGraph cfg; - - /** The associated processing environment */ - protected final ProcessingEnvironment env; - - /** Instance of the types utility. */ - protected final Types types; - - /** Then stores before every basic block (assumed to be 'no information' if not present). */ - protected IdentityHashMap thenStores; - - /** Else stores before every basic block (assumed to be 'no information' if not present). */ - protected IdentityHashMap elseStores; - - /** - * Number of times every block has been analyzed since the last time widening was applied. Null, - * if maxCountBeforeWidening is -1 which implies widening isn't used for this analysis. - */ - protected IdentityHashMap blockCount; - - /** - * Number of times a block can be analyzed before widening. -1 implies that widening shouldn't - * be used. - */ - protected final int maxCountBeforeWidening; - - /** - * The transfer inputs before every basic block (assumed to be 'no information' if not present). - */ - protected IdentityHashMap> inputs; - - /** The stores after every return statement. */ - protected IdentityHashMap> storesAtReturnStatements; - - /** The worklist used for the fix-point iteration. */ - protected Worklist worklist; - - /** Abstract values of nodes. */ - protected IdentityHashMap nodeValues; - - /** Map from (effectively final) local variable elements to their abstract value. */ - public HashMap finalLocalValues; - - /** - * The node that is currently handled in the analysis (if it is running). The following - * invariant holds: - * - *
-     *   !isRunning ⇒ (currentNode == null)
-     * 
- */ - protected Node currentNode; - - /** - * The tree that is currently being looked at. The transfer function can set this tree to make - * sure that calls to {@code getValue} will not return information for this given tree. - */ - protected Tree currentTree; - - /** The current transfer input when the analysis is running. */ - protected TransferInput currentInput; - - public Tree getCurrentTree() { - return currentTree; - } - - public void setCurrentTree(Tree currentTree) { - this.currentTree = currentTree; - } - - /** - * Construct an object that can perform a org.checkerframework.dataflow analysis over a control - * flow graph. The transfer function is set later using {@code setTransferFunction}. - */ - public Analysis(ProcessingEnvironment env) { - this(env, null, -1); - } - - /** - * Construct an object that can perform a org.checkerframework.dataflow analysis over a control - * flow graph, given a transfer function. - */ - public Analysis(ProcessingEnvironment env, T transfer) { - this(env, transfer, -1); - } - - /** - * Construct an object that can perform a org.checkerframework.dataflow analysis over a control - * flow graph, given a transfer function. - */ - public Analysis(ProcessingEnvironment env, T transfer, int maxCountBeforeWidening) { - this.env = env; - types = env.getTypeUtils(); - this.transferFunction = transfer; - this.maxCountBeforeWidening = maxCountBeforeWidening; - this.transferFunction = transfer; - } - - public void setTransferFunction(T transfer) { - this.transferFunction = transfer; - } - - public T getTransferFunction() { - return transferFunction; - } - - public Types getTypes() { - return types; - } - - public ProcessingEnvironment getEnv() { - return env; - } - - /** - * Perform the actual analysis. Should only be called once after the object has been created. - */ - public void performAnalysis(ControlFlowGraph cfg) { - assert isRunning == false; - isRunning = true; - - init(cfg); - - while (!worklist.isEmpty()) { - Block b = worklist.poll(); - - switch (b.getType()) { - case REGULAR_BLOCK: - { - RegularBlock rb = (RegularBlock) b; - - // apply transfer function to contents - TransferInput inputBefore = getInputBefore(rb); - currentInput = inputBefore.copy(); - TransferResult transferResult = null; - Node lastNode = null; - boolean addToWorklistAgain = false; - for (Node n : rb.getContents()) { - transferResult = callTransferFunction(n, currentInput); - addToWorklistAgain |= updateNodeValues(n, transferResult); - currentInput = new TransferInput<>(n, this, transferResult); - lastNode = n; - } - // loop will run at least one, making transferResult non-null - - // propagate store to successors - Block succ = rb.getSuccessor(); - assert succ != null - : "regular basic block without non-exceptional successor unexpected"; - propagateStoresTo( - succ, lastNode, currentInput, rb.getFlowRule(), addToWorklistAgain); - break; - } - - case EXCEPTION_BLOCK: - { - ExceptionBlock eb = (ExceptionBlock) b; - - // apply transfer function to content - TransferInput inputBefore = getInputBefore(eb); - currentInput = inputBefore.copy(); - Node node = eb.getNode(); - TransferResult transferResult = - callTransferFunction(node, currentInput); - boolean addToWorklistAgain = updateNodeValues(node, transferResult); - - // propagate store to successor - Block succ = eb.getSuccessor(); - if (succ != null) { - currentInput = new TransferInput<>(node, this, transferResult); - // TODO? Variable wasn't used. - // Store.FlowRule storeFlow = eb.getFlowRule(); - propagateStoresTo( - succ, node, currentInput, eb.getFlowRule(), addToWorklistAgain); - } - - // propagate store to exceptional successors - for (Entry> e : - eb.getExceptionalSuccessors().entrySet()) { - TypeMirror cause = e.getKey(); - S exceptionalStore = transferResult.getExceptionalStore(cause); - if (exceptionalStore != null) { - for (Block exceptionSucc : e.getValue()) { - addStoreBefore( - exceptionSucc, - node, - exceptionalStore, - Store.Kind.BOTH, - addToWorklistAgain); - } - } else { - for (Block exceptionSucc : e.getValue()) { - addStoreBefore( - exceptionSucc, - node, - inputBefore.copy().getRegularStore(), - Store.Kind.BOTH, - addToWorklistAgain); - } - } - } - break; - } - - case CONDITIONAL_BLOCK: - { - ConditionalBlock cb = (ConditionalBlock) b; - - // get store before - TransferInput inputBefore = getInputBefore(cb); - TransferInput input = inputBefore.copy(); - - // propagate store to successor - Block thenSucc = cb.getThenSuccessor(); - Block elseSucc = cb.getElseSuccessor(); - - propagateStoresTo(thenSucc, null, input, cb.getThenFlowRule(), false); - propagateStoresTo(elseSucc, null, input, cb.getElseFlowRule(), false); - break; - } - - case SPECIAL_BLOCK: - { - // special basic blocks are empty and cannot throw exceptions, - // thus there is no need to perform any analysis. - SpecialBlock sb = (SpecialBlock) b; - Block succ = sb.getSuccessor(); - if (succ != null) { - propagateStoresTo( - succ, null, getInputBefore(b), sb.getFlowRule(), false); - } - break; - } - - default: - assert false; - break; - } - } - - assert isRunning == true; - isRunning = false; - } - - /** - * Propagate the stores in currentInput to the successor block, succ, according to the flowRule. - */ - protected void propagateStoresTo( - Block succ, - Node node, - TransferInput currentInput, - Store.FlowRule flowRule, - boolean addToWorklistAgain) { - switch (flowRule) { - case EACH_TO_EACH: - if (currentInput.containsTwoStores()) { - addStoreBefore( - succ, - node, - currentInput.getThenStore(), - Store.Kind.THEN, - addToWorklistAgain); - addStoreBefore( - succ, - node, - currentInput.getElseStore(), - Store.Kind.ELSE, - addToWorklistAgain); - } else { - addStoreBefore( - succ, - node, - currentInput.getRegularStore(), - Store.Kind.BOTH, - addToWorklistAgain); - } - break; - case THEN_TO_BOTH: - addStoreBefore( - succ, - node, - currentInput.getThenStore(), - Store.Kind.BOTH, - addToWorklistAgain); - break; - case ELSE_TO_BOTH: - addStoreBefore( - succ, - node, - currentInput.getElseStore(), - Store.Kind.BOTH, - addToWorklistAgain); - break; - case THEN_TO_THEN: - addStoreBefore( - succ, - node, - currentInput.getThenStore(), - Store.Kind.THEN, - addToWorklistAgain); - break; - case ELSE_TO_ELSE: - addStoreBefore( - succ, - node, - currentInput.getElseStore(), - Store.Kind.ELSE, - addToWorklistAgain); - break; - } - } - - /** - * Updates the value of node {@code node} to the value of the {@code transferResult}. Returns - * true if the node's value changed, or a store was updated. - */ - protected boolean updateNodeValues(Node node, TransferResult transferResult) { - A newVal = transferResult.getResultValue(); - boolean nodeValueChanged = false; - - if (newVal != null) { - A oldVal = nodeValues.get(node); - nodeValues.put(node, newVal); - nodeValueChanged = !Objects.equals(oldVal, newVal); - } - - return nodeValueChanged || transferResult.storeChanged(); - } - - /** - * Call the transfer function for node {@code node}, and set that node as current node first. - */ - protected TransferResult callTransferFunction(Node node, TransferInput store) { - - if (node.isLValue()) { - // TODO: should the default behavior be to return either a regular - // transfer result or a conditional transfer result (depending on - // store.hasTwoStores()), or is the following correct? - return new RegularTransferResult(null, store.getRegularStore()); - } - store.node = node; - currentNode = node; - TransferResult transferResult = node.accept(transferFunction, store); - currentNode = null; - if (node instanceof ReturnNode) { - // save a copy of the store to later check if some property held at - // a given return statement - storesAtReturnStatements.put((ReturnNode) node, transferResult); - } - if (node instanceof AssignmentNode) { - // store the flow-refined value for effectively final local variables - AssignmentNode assignment = (AssignmentNode) node; - Node lhst = assignment.getTarget(); - if (lhst instanceof LocalVariableNode) { - LocalVariableNode lhs = (LocalVariableNode) lhst; - Element elem = lhs.getElement(); - if (ElementUtils.isEffectivelyFinal(elem)) { - finalLocalValues.put(elem, transferResult.getResultValue()); - } - } - } - return transferResult; - } - - /** Initialize the analysis with a new control flow graph. */ - protected void init(ControlFlowGraph cfg) { - this.cfg = cfg; - thenStores = new IdentityHashMap<>(); - elseStores = new IdentityHashMap<>(); - blockCount = maxCountBeforeWidening == -1 ? null : new IdentityHashMap(); - inputs = new IdentityHashMap<>(); - storesAtReturnStatements = new IdentityHashMap<>(); - worklist = new Worklist(cfg); - nodeValues = new IdentityHashMap<>(); - finalLocalValues = new HashMap<>(); - worklist.add(cfg.getEntryBlock()); - - List parameters = null; - UnderlyingAST underlyingAST = cfg.getUnderlyingAST(); - if (underlyingAST.getKind() == Kind.METHOD) { - MethodTree tree = ((CFGMethod) underlyingAST).getMethod(); - parameters = new ArrayList<>(); - for (VariableTree p : tree.getParameters()) { - LocalVariableNode var = new LocalVariableNode(p); - parameters.add(var); - // TODO: document that LocalVariableNode has no block that it - // belongs to - } - } else if (underlyingAST.getKind() == Kind.LAMBDA) { - LambdaExpressionTree lambda = ((CFGLambda) underlyingAST).getLambdaTree(); - parameters = new ArrayList<>(); - for (VariableTree p : lambda.getParameters()) { - LocalVariableNode var = new LocalVariableNode(p); - parameters.add(var); - // TODO: document that LocalVariableNode has no block that it - // belongs to - } - - } else { - // nothing to do - } - S initialStore = transferFunction.initialStore(underlyingAST, parameters); - Block entry = cfg.getEntryBlock(); - thenStores.put(entry, initialStore); - elseStores.put(entry, initialStore); - inputs.put(entry, new TransferInput<>(null, this, initialStore)); - } - - /** - * Add a basic block to the worklist. If {@code b} is already present, the method does nothing. - */ - protected void addToWorklist(Block b) { - // TODO: use a more efficient way to check if b is already present - if (!worklist.contains(b)) { - worklist.add(b); - } - } - - /** - * Add a store before the basic block {@code b} by merging with the existing stores for that - * location. - */ - protected void addStoreBefore( - Block b, Node node, S s, Store.Kind kind, boolean addBlockToWorklist) { - S thenStore = getStoreBefore(b, Store.Kind.THEN); - S elseStore = getStoreBefore(b, Store.Kind.ELSE); - boolean shouldWiden = false; - if (blockCount != null) { - Integer count = blockCount.get(b); - if (count == null) { - count = 0; - } - shouldWiden = count >= maxCountBeforeWidening; - if (shouldWiden) { - blockCount.put(b, 0); - } else { - blockCount.put(b, count + 1); - } - } - - switch (kind) { - case THEN: - { - // Update the then store - S newThenStore = mergeStores(s, thenStore, shouldWiden); - if (!newThenStore.equals(thenStore)) { - thenStores.put(b, newThenStore); - if (elseStore != null) { - inputs.put(b, new TransferInput<>(node, this, newThenStore, elseStore)); - addBlockToWorklist = true; - } - } - break; - } - case ELSE: - { - // Update the else store - S newElseStore = mergeStores(s, elseStore, shouldWiden); - if (!newElseStore.equals(elseStore)) { - elseStores.put(b, newElseStore); - if (thenStore != null) { - inputs.put(b, new TransferInput<>(node, this, thenStore, newElseStore)); - addBlockToWorklist = true; - } - } - break; - } - case BOTH: - if (thenStore == elseStore) { - // Currently there is only one regular store - S newStore = mergeStores(s, thenStore, shouldWiden); - if (!newStore.equals(thenStore)) { - thenStores.put(b, newStore); - elseStores.put(b, newStore); - inputs.put(b, new TransferInput<>(node, this, newStore)); - addBlockToWorklist = true; - } - } else { - boolean storeChanged = false; - - S newThenStore = mergeStores(s, thenStore, shouldWiden); - if (!newThenStore.equals(thenStore)) { - thenStores.put(b, newThenStore); - storeChanged = true; - } - - S newElseStore = mergeStores(s, elseStore, shouldWiden); - if (!newElseStore.equals(elseStore)) { - elseStores.put(b, newElseStore); - storeChanged = true; - } - - if (storeChanged) { - inputs.put(b, new TransferInput<>(node, this, newThenStore, newElseStore)); - addBlockToWorklist = true; - } - } - } - - if (addBlockToWorklist) { - addToWorklist(b); - } - } - - private S mergeStores(S newStore, S previousStore, boolean shouldWiden) { - if (previousStore == null) { - return newStore; - } else if (shouldWiden) { - return newStore.widenedUpperBound(previousStore); - } else { - return newStore.leastUpperBound(previousStore); - } - } - - /** - * A worklist is a priority queue of blocks in which the order is given by depth-first ordering - * to place non-loop predecessors ahead of successors. - */ - protected static class Worklist { - - /** Map all blocks in the CFG to their depth-first order. */ - protected IdentityHashMap depthFirstOrder; - - /** Comparator to allow priority queue to order blocks by their depth-first order. */ - public class DFOComparator implements Comparator { - @Override - public int compare(Block b1, Block b2) { - return depthFirstOrder.get(b1) - depthFirstOrder.get(b2); - } - } - - /** The backing priority queue. */ - protected PriorityQueue queue; - - public Worklist(ControlFlowGraph cfg) { - depthFirstOrder = new IdentityHashMap<>(); - int count = 1; - for (Block b : cfg.getDepthFirstOrderedBlocks()) { - depthFirstOrder.put(b, count++); - } - - queue = new PriorityQueue(11, new DFOComparator()); - } - - public boolean isEmpty() { - return queue.isEmpty(); - } - - public boolean contains(Block block) { - return queue.contains(block); - } - - public void add(Block block) { - queue.add(block); - } - - public Block poll() { - return queue.poll(); - } - - @Override - public String toString() { - return "Worklist(" + queue + ")"; - } - } - - /** - * Read the {@link TransferInput} for a particular basic block (or {@code null} if none exists - * yet). - */ - public /*@Nullable*/ TransferInput getInput(Block b) { - return getInputBefore(b); - } - - /** - * @return the transfer input corresponding to the location right before the basic block {@code - * b}. - */ - protected /*@Nullable*/ TransferInput getInputBefore(Block b) { - return inputs.get(b); - } - - /** @return the store corresponding to the location right before the basic block {@code b}. */ - protected /*@Nullable*/ S getStoreBefore(Block b, Store.Kind kind) { - switch (kind) { - case THEN: - return readFromStore(thenStores, b); - case ELSE: - return readFromStore(elseStores, b); - default: - assert false; - return null; - } - } - - /** - * Read the {@link Store} for a particular basic block from a map of stores (or {@code null} if - * none exists yet). - */ - protected static /*@Nullable*/ S readFromStore(Map stores, Block b) { - return stores.get(b); - } - - /** Is the analysis currently running? */ - public boolean isRunning() { - return isRunning; - } - - /** - * @return the abstract value for {@link Node} {@code n}, or {@code null} if no information is - * available. Note that if the analysis has not finished yet, this value might not represent - * the final value for this node. - */ - public /*@Nullable*/ A getValue(Node n) { - if (isRunning) { - // we do not yet have a org.checkerframework.dataflow fact about the current node - if (currentNode == null - || currentNode == n - || (currentTree != null && currentTree == n.getTree())) { - return null; - } - // check that 'n' is a subnode of 'node'. Check immediate operands - // first for efficiency. - assert !n.isLValue() : "Did not expect an lvalue, but got " + n; - if (!(currentNode != n - && (currentNode.getOperands().contains(n) - || currentNode.getTransitiveOperands().contains(n)))) { - return null; - } - return nodeValues.get(n); - } - return nodeValues.get(n); - } - - /** - * @return the abstract value for {@link Tree} {@code t}, or {@code null} if no information is - * available. Note that if the analysis has not finished yet, this value might not represent - * the final value for this node. - */ - public /*@Nullable*/ A getValue(Tree t) { - // we do not yet have a org.checkerframework.dataflow fact about the current node - if (t == currentTree) { - return null; - } - Node nodeCorrespondingToTree = getNodeForTree(t); - if (nodeCorrespondingToTree == null || nodeCorrespondingToTree.isLValue()) { - return null; - } - return getValue(nodeCorrespondingToTree); - } - - /** Get the {@link Node} for a given {@link Tree}. */ - public Node getNodeForTree(Tree t) { - return cfg.getNodeCorrespondingToTree(t); - } - - /** - * Get the {@link MethodTree} of the current CFG if the argument {@link Tree} maps to a {@link - * Node} in the CFG or null otherwise. - */ - public /*@Nullable*/ MethodTree getContainingMethod(Tree t) { - return cfg.getContainingMethod(t); - } - - /** - * Get the {@link ClassTree} of the current CFG if the argument {@link Tree} maps to a {@link - * Node} in the CFG or null otherwise. - */ - public /*@Nullable*/ ClassTree getContainingClass(Tree t) { - return cfg.getContainingClass(t); - } - - public List>> getReturnStatementStores() { - List>> result = new ArrayList<>(); - for (ReturnNode returnNode : cfg.getReturnNodes()) { - TransferResult store = storesAtReturnStatements.get(returnNode); - result.add(Pair.of(returnNode, store)); - } - return result; - } - - public AnalysisResult getResult() { - assert !isRunning; - IdentityHashMap treeLookup = cfg.getTreeLookup(); - return new AnalysisResult<>(nodeValues, inputs, treeLookup, finalLocalValues); - } - - /** - * @return the regular exit store, or {@code null}, if there is no such store (because the - * method cannot exit through the regular exit block). - */ - public /*@Nullable*/ S getRegularExitStore() { - SpecialBlock regularExitBlock = cfg.getRegularExitBlock(); - if (inputs.containsKey(regularExitBlock)) { - S regularExitStore = inputs.get(regularExitBlock).getRegularStore(); - return regularExitStore; - } else { - return null; - } - } - - public S getExceptionalExitStore() { - S exceptionalExitStore = inputs.get(cfg.getExceptionalExitBlock()).getRegularStore(); - return exceptionalExitStore; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java deleted file mode 100644 index 48f376dbea7e49..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java +++ /dev/null @@ -1,220 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.Tree; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Map.Entry; -import javax.lang.model.element.Element; -import org.checkerframework.dataflow.cfg.block.Block; -import org.checkerframework.dataflow.cfg.block.ExceptionBlock; -import org.checkerframework.dataflow.cfg.block.RegularBlock; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * An {@link AnalysisResult} represents the result of a org.checkerframework.dataflow analysis by - * providing the abstract values given a node or a tree. Note that it does not keep track of custom - * results computed by some analysis. - * - * @author Stefan Heule - * @param
type of the abstract value that is tracked - */ -public class AnalysisResult, S extends Store> { - - /** Abstract values of nodes. */ - protected final IdentityHashMap nodeValues; - - /** Map from AST {@link Tree}s to {@link Node}s. */ - protected final IdentityHashMap treeLookup; - - /** Map from (effectively final) local variable elements to their abstract value. */ - protected final HashMap finalLocalValues; - - /** The stores before every method call. */ - protected final IdentityHashMap> stores; - - /** Initialize with a given node-value mapping. */ - public AnalysisResult( - Map nodeValues, - IdentityHashMap> stores, - IdentityHashMap treeLookup, - HashMap finalLocalValues) { - this.nodeValues = new IdentityHashMap<>(nodeValues); - this.treeLookup = new IdentityHashMap<>(treeLookup); - this.stores = stores; - this.finalLocalValues = finalLocalValues; - } - - /** Initialize empty result. */ - public AnalysisResult() { - nodeValues = new IdentityHashMap<>(); - treeLookup = new IdentityHashMap<>(); - stores = new IdentityHashMap<>(); - finalLocalValues = new HashMap<>(); - } - - /** Combine with another analysis result. */ - public void combine(AnalysisResult other) { - for (Entry e : other.nodeValues.entrySet()) { - nodeValues.put(e.getKey(), e.getValue()); - } - for (Entry e : other.treeLookup.entrySet()) { - treeLookup.put(e.getKey(), e.getValue()); - } - for (Entry> e : other.stores.entrySet()) { - stores.put(e.getKey(), e.getValue()); - } - for (Entry e : other.finalLocalValues.entrySet()) { - finalLocalValues.put(e.getKey(), e.getValue()); - } - } - - /** @return the value of effectively final local variables */ - public HashMap getFinalLocalValues() { - return finalLocalValues; - } - - /** - * @return the abstract value for {@link Node} {@code n}, or {@code null} if no information is - * available. - */ - public /*@Nullable*/ A getValue(Node n) { - return nodeValues.get(n); - } - - /** - * @return the abstract value for {@link Tree} {@code t}, or {@code null} if no information is - * available. - */ - public /*@Nullable*/ A getValue(Tree t) { - A val = getValue(treeLookup.get(t)); - return val; - } - - /** @return the {@link Node} for a given {@link Tree}. */ - public /*@Nullable*/ Node getNodeForTree(Tree tree) { - return treeLookup.get(tree); - } - - /** @return the store immediately before a given {@link Tree}. */ - public S getStoreBefore(Tree tree) { - Node node = getNodeForTree(tree); - if (node == null) { - return null; - } - return getStoreBefore(node); - } - - /** @return the store immediately before a given {@link Node}. */ - public S getStoreBefore(Node node) { - return runAnalysisFor(node, true); - } - - /** @return the store immediately after a given {@link Tree}. */ - public S getStoreAfter(Tree tree) { - Node node = getNodeForTree(tree); - if (node == null) { - return null; - } - return getStoreAfter(node); - } - - /** @return the store immediately after a given {@link Node}. */ - public S getStoreAfter(Node node) { - return runAnalysisFor(node, false); - } - - /** - * Runs the analysis again within the block of {@code node} and returns the store at the - * location of {@code node}. If {@code before} is true, then the store immediately before the - * {@link Node} {@code node} is returned. Otherwise, the store after {@code node} is returned. - * - *

For the meaning of storeChanged, see {@link - * org.checkerframework.dataflow.analysis.TransferResult#storeChanged}. - * - *

Exceptions: If the corresponding {@link - * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then it is assumed that no - * special handling is necessary and the store before the corresponding {@link - * org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge. - * - *

Aliasing: {@code thenStore} and {@code elseStore} are not allowed to be used - * anywhere outside of this class (including use through aliases). Complete control over the - * objects is transfered to this class. - */ - public ConditionalTransferResult(A value, S thenStore, S elseStore, boolean storeChanged) { - super(value); - this.thenStore = thenStore; - this.elseStore = elseStore; - this.storeChanged = storeChanged; - } - - public ConditionalTransferResult(A value, S thenStore, S elseStore) { - this(value, thenStore, elseStore, false); - } - - /** - * Create a {@code ConditionalTransferResult} with {@code thenStore} as the resulting store if - * the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} evaluates to {@code - * true} and {@code elseStore} otherwise. - * - *

Exceptions: If the corresponding {@link - * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then the corresponding - * store in {@code exceptionalStores} is used. If no exception is found in {@code - * exceptionalStores}, then it is assumed that no special handling is necessary and the store - * before the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed - * along any exceptional edge. - * - *

Aliasing: {@code thenStore}, {@code elseStore}, and any store in {@code - * exceptionalStores} are not allowed to be used anywhere outside of this class (including use - * through aliases). Complete control over the objects is transfered to this class. - */ - public ConditionalTransferResult( - A value, - S thenStore, - S elseStore, - Map exceptionalStores, - boolean storeChanged) { - super(value); - this.exceptionalStores = exceptionalStores; - this.thenStore = thenStore; - this.elseStore = elseStore; - this.storeChanged = storeChanged; - } - - public ConditionalTransferResult( - A value, S thenStore, S elseStore, Map exceptionalStores) { - this(value, thenStore, elseStore, exceptionalStores, false); - } - - @Override - public S getRegularStore() { - return thenStore.leastUpperBound(elseStore); - } - - @Override - public S getThenStore() { - return thenStore; - } - - @Override - public S getElseStore() { - return elseStore; - } - - @Override - public boolean containsTwoStores() { - return true; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("RegularTransferResult("); - result.append(System.getProperty("line.separator")); - result.append("resultValue = " + resultValue); - result.append(System.getProperty("line.separator")); - result.append("thenStore = " + thenStore); - result.append("elseStore = " + elseStore); - result.append(System.getProperty("line.separator")); - result.append(")"); - return result.toString(); - } - - /** @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged() */ - @Override - public boolean storeChanged() { - return storeChanged; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java deleted file mode 100644 index 85ad7b4b00ecde..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java +++ /dev/null @@ -1,1143 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.VariableTree; -import com.sun.source.util.TreePath; -import com.sun.tools.javac.code.Symbol.VarSymbol; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.cfg.node.ArrayAccessNode; -import org.checkerframework.dataflow.cfg.node.ArrayCreationNode; -import org.checkerframework.dataflow.cfg.node.ClassNameNode; -import org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.FieldAccessNode; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; -import org.checkerframework.dataflow.cfg.node.NarrowingConversionNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.StringConversionNode; -import org.checkerframework.dataflow.cfg.node.SuperNode; -import org.checkerframework.dataflow.cfg.node.ThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.ValueLiteralNode; -import org.checkerframework.dataflow.cfg.node.WideningConversionNode; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.dataflow.util.PurityUtils; -import org.checkerframework.javacutil.AnnotationProvider; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.ErrorReporter; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; -import org.checkerframework.javacutil.TypeAnnotationUtils; -import org.checkerframework.javacutil.TypesUtils; - -/** - * Collection of classes and helper functions to represent Java expressions about which the - * org.checkerframework.dataflow analysis can possibly infer facts. Expressions include: - * - *

- * - * @author Stefan Heule - */ -public class FlowExpressions { - - /** - * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. - * Can contain {@link Unknown} as receiver. - */ - public static FieldAccess internalReprOfFieldAccess( - AnnotationProvider provider, FieldAccessNode node) { - Receiver receiver; - Node receiverNode = node.getReceiver(); - if (node.isStatic()) { - receiver = new ClassName(receiverNode.getType()); - } else { - receiver = internalReprOf(provider, receiverNode); - } - return new FieldAccess(receiver, node); - } - - /** - * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. - * Can contain {@link Unknown} as receiver. - */ - public static ArrayAccess internalReprOfArrayAccess( - AnnotationProvider provider, ArrayAccessNode node) { - Receiver receiver = internalReprOf(provider, node.getArray()); - Receiver index = internalReprOf(provider, node.getIndex()); - return new ArrayAccess(node.getType(), receiver, index); - } - - /** - * We ignore operations such as widening and narrowing when computing the internal - * representation. - * - * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain - * {@link Unknown}. - */ - public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode) { - return internalReprOf(provider, receiverNode, false); - } - - /** - * We ignore operations such as widening and narrowing when computing the internal - * representation. - * - * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain - * {@link Unknown}. - */ - public static Receiver internalReprOf( - AnnotationProvider provider, Node receiverNode, boolean allowNonDeterministic) { - Receiver receiver = null; - if (receiverNode instanceof FieldAccessNode) { - FieldAccessNode fan = (FieldAccessNode) receiverNode; - - if (fan.getFieldName().equals("this")) { - // For some reason, "className.this" is considered a field access. - // We right this wrong here. - receiver = new ThisReference(fan.getReceiver().getType()); - } else if (fan.getFieldName().equals("class")) { - // "className.class" is considered a field access. This makes sense, - // since .class is similar to a field access which is the equivalent - // of a call to getClass(). However for the purposes of dataflow - // analysis, and value stores, this is the equivalent of a ClassNameNode. - receiver = new ClassName(fan.getReceiver().getType()); - } else { - receiver = internalReprOfFieldAccess(provider, fan); - } - } else if (receiverNode instanceof ExplicitThisLiteralNode) { - receiver = new ThisReference(receiverNode.getType()); - } else if (receiverNode instanceof ThisLiteralNode) { - receiver = new ThisReference(receiverNode.getType()); - } else if (receiverNode instanceof SuperNode) { - receiver = new ThisReference(receiverNode.getType()); - } else if (receiverNode instanceof LocalVariableNode) { - LocalVariableNode lv = (LocalVariableNode) receiverNode; - receiver = new LocalVariable(lv); - } else if (receiverNode instanceof ArrayAccessNode) { - ArrayAccessNode a = (ArrayAccessNode) receiverNode; - receiver = internalReprOfArrayAccess(provider, a); - } else if (receiverNode instanceof StringConversionNode) { - // ignore string conversion - return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand()); - } else if (receiverNode instanceof WideningConversionNode) { - // ignore widening - return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand()); - } else if (receiverNode instanceof NarrowingConversionNode) { - // ignore narrowing - return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand()); - } else if (receiverNode instanceof ClassNameNode) { - ClassNameNode cn = (ClassNameNode) receiverNode; - receiver = new ClassName(cn.getType()); - } else if (receiverNode instanceof ValueLiteralNode) { - ValueLiteralNode vn = (ValueLiteralNode) receiverNode; - receiver = new ValueLiteral(vn.getType(), vn); - } else if (receiverNode instanceof ArrayCreationNode) { - ArrayCreationNode an = (ArrayCreationNode) receiverNode; - receiver = new ArrayCreation(an.getType(), an.getDimensions(), an.getInitializers()); - } else if (receiverNode instanceof MethodInvocationNode) { - MethodInvocationNode mn = (MethodInvocationNode) receiverNode; - ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree()); - - // check if this represents a boxing operation of a constant, in which - // case we treat the method call as deterministic, because there is no way - // to behave differently in two executions where two constants are being used. - boolean considerDeterministic = false; - if (invokedMethod.toString().equals("valueOf(long)") - && mn.getTarget().getReceiver().toString().equals("Long")) { - Node arg = mn.getArgument(0); - if (arg instanceof ValueLiteralNode) { - considerDeterministic = true; - } - } - - if (PurityUtils.isDeterministic(provider, invokedMethod) - || allowNonDeterministic - || considerDeterministic) { - List parameters = new ArrayList<>(); - for (Node p : mn.getArguments()) { - parameters.add(internalReprOf(provider, p)); - } - Receiver methodReceiver; - if (ElementUtils.isStatic(invokedMethod)) { - methodReceiver = new ClassName(mn.getTarget().getReceiver().getType()); - } else { - methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver()); - } - receiver = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters); - } - } - - if (receiver == null) { - receiver = new Unknown(receiverNode.getType()); - } - return receiver; - } - - /** - * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. - */ - public static Receiver internalReprOf( - AnnotationProvider provider, ExpressionTree receiverTree) { - return internalReprOf(provider, receiverTree, true); - } - /** - * We ignore operations such as widening and narrowing when computing the internal - * representation. - * - * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. - */ - public static Receiver internalReprOf( - AnnotationProvider provider, - ExpressionTree receiverTree, - boolean allowNonDeterministic) { - Receiver receiver; - switch (receiverTree.getKind()) { - case ARRAY_ACCESS: - ArrayAccessTree a = (ArrayAccessTree) receiverTree; - Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression()); - Receiver index = internalReprOf(provider, a.getIndex()); - receiver = new ArrayAccess(InternalUtils.typeOf(a), arrayAccessExpression, index); - break; - case BOOLEAN_LITERAL: - case CHAR_LITERAL: - case DOUBLE_LITERAL: - case FLOAT_LITERAL: - case INT_LITERAL: - case LONG_LITERAL: - case NULL_LITERAL: - case STRING_LITERAL: - LiteralTree vn = (LiteralTree) receiverTree; - receiver = new ValueLiteral(InternalUtils.typeOf(receiverTree), vn.getValue()); - break; - case NEW_ARRAY: - receiver = - new ArrayCreation( - InternalUtils.typeOf(receiverTree), - Collections.emptyList(), - Collections.emptyList()); - break; - case METHOD_INVOCATION: - MethodInvocationTree mn = (MethodInvocationTree) receiverTree; - ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn); - if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) { - List parameters = new ArrayList<>(); - for (ExpressionTree p : mn.getArguments()) { - parameters.add(internalReprOf(provider, p)); - } - Receiver methodReceiver; - if (ElementUtils.isStatic(invokedMethod)) { - methodReceiver = new ClassName(InternalUtils.typeOf(mn.getMethodSelect())); - } else { - methodReceiver = internalReprOf(provider, mn.getMethodSelect()); - } - TypeMirror type = InternalUtils.typeOf(mn); - receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters); - } else { - receiver = null; - } - break; - case MEMBER_SELECT: - receiver = internalRepOfMemberSelect(provider, (MemberSelectTree) receiverTree); - break; - case IDENTIFIER: - IdentifierTree identifierTree = (IdentifierTree) receiverTree; - TypeMirror typeOfId = InternalUtils.typeOf(identifierTree); - if (identifierTree.getName().contentEquals("this") - || identifierTree.getName().contentEquals("super")) { - receiver = new ThisReference(typeOfId); - break; - } - Element ele = TreeUtils.elementFromUse(identifierTree); - switch (ele.getKind()) { - case LOCAL_VARIABLE: - case RESOURCE_VARIABLE: - case EXCEPTION_PARAMETER: - case PARAMETER: - receiver = new LocalVariable(ele); - break; - case FIELD: - // Implicit access expression, such as "this" or a class name - Receiver fieldAccessExpression; - TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType(); - if (ElementUtils.isStatic(ele)) { - fieldAccessExpression = new ClassName(enclosingType); - } else { - fieldAccessExpression = new ThisReference(enclosingType); - } - receiver = - new FieldAccess( - fieldAccessExpression, typeOfId, (VariableElement) ele); - break; - case CLASS: - case ENUM: - case ANNOTATION_TYPE: - case INTERFACE: - receiver = new ClassName(ele.asType()); - break; - default: - receiver = null; - } - break; - default: - receiver = null; - } - - if (receiver == null) { - receiver = new Unknown(InternalUtils.typeOf(receiverTree)); - } - return receiver; - } - - /** - * Returns the implicit receiver of ele. - * - *

Returns either a new ClassName or a new ThisReference depending on whether ele is static - * or not. The passed element must be a field, method, or class. - * - * @param ele field, method, or class - * @return either a new ClassName or a new ThisReference depending on whether ele is static or - * not - */ - public static Receiver internalRepOfImplicitReceiver(Element ele) { - TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType(); - if (ElementUtils.isStatic(ele)) { - return new ClassName(enclosingType); - } else { - return new ThisReference(enclosingType); - } - } - - /** - * Returns either a new ClassName or ThisReference Receiver object for the enclosingType - * - *

The Tree should be an expression or a statement that does not have a receiver or an - * implicit receiver. For example, a local variable declaration. - * - * @param path TreePath to tree - * @param enclosingType type of the enclosing type - * @return a new ClassName or ThisReference that is a Receiver object for the enclosingType - */ - public static Receiver internalRepOfPseudoReceiver(TreePath path, TypeMirror enclosingType) { - if (TreeUtils.isTreeInStaticScope(path)) { - return new ClassName(enclosingType); - } else { - return new ThisReference(enclosingType); - } - } - - private static Receiver internalRepOfMemberSelect( - AnnotationProvider provider, MemberSelectTree memberSelectTree) { - TypeMirror expressionType = InternalUtils.typeOf(memberSelectTree.getExpression()); - if (TreeUtils.isClassLiteral(memberSelectTree)) { - return new ClassName(expressionType); - } - Element ele = TreeUtils.elementFromUse(memberSelectTree); - switch (ele.getKind()) { - case METHOD: - case CONSTRUCTOR: - return internalReprOf(provider, memberSelectTree.getExpression()); - case CLASS: // o instanceof MyClass.InnerClass - case ENUM: - case INTERFACE: // o instanceof MyClass.InnerInterface - case ANNOTATION_TYPE: - return new ClassName(expressionType); - case ENUM_CONSTANT: - case FIELD: - Receiver r = internalReprOf(provider, memberSelectTree.getExpression()); - return new FieldAccess(r, ElementUtils.getType(ele), (VariableElement) ele); - default: - ErrorReporter.errorAbort( - "Unexpected element kind: %s element: %s", ele.getKind(), ele); - return null; - } - } - - /** - * Returns Receiver objects for the formal parameters of the method in which path is enclosed. - * - * @param annotationProvider annotationProvider - * @param path TreePath that is enclosed by the method - * @return list of Receiver objects for the formal parameters of the method in which path is - * enclosed - */ - public static List getParametersOfEnclosingMethod( - AnnotationProvider annotationProvider, TreePath path) { - MethodTree methodTree = TreeUtils.enclosingMethod(path); - if (methodTree == null) { - return null; - } - List internalArguments = new ArrayList<>(); - for (VariableTree arg : methodTree.getParameters()) { - internalArguments.add(internalReprOf(annotationProvider, new LocalVariableNode(arg))); - } - return internalArguments; - } - - public abstract static class Receiver { - protected final TypeMirror type; - - public Receiver(TypeMirror type) { - assert type != null; - this.type = type; - } - - public TypeMirror getType() { - return type; - } - - public abstract boolean containsOfClass(Class clazz); - - public boolean containsUnknown() { - return containsOfClass(Unknown.class); - } - - /** - * Returns true if and only if the value this expression stands for cannot be changed by a - * method call. This is the case for local variables, the self reference as well as final - * field accesses for whose receiver {@link #isUnmodifiableByOtherCode} is true. - */ - public abstract boolean isUnmodifiableByOtherCode(); - - /** @return true if and only if the two receiver are syntactically identical */ - public boolean syntacticEquals(Receiver other) { - return other == this; - } - - /** - * @return true if and only if this receiver contains a receiver that is syntactically equal - * to {@code other}. - */ - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - /** - * Returns true if and only if {@code other} appears anywhere in this receiver or an - * expression appears in this receiver such that {@code other} might alias this expression, - * and that expression is modifiable. - * - *

Exceptions: If the corresponding {@link - * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then it is assumed that no - * special handling is necessary and the store before the corresponding {@link - * org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge. - * - *

Aliasing: {@code resultStore} is not allowed to be used anywhere outside of this - * class (including use through aliases). Complete control over the object is transfered to this - * class. - */ - public RegularTransferResult(A value, S resultStore, boolean storeChanged) { - super(value); - this.store = resultStore; - this.storeChanged = storeChanged; - } - - public RegularTransferResult(A value, S resultStore) { - this(value, resultStore, false); - } - - /** - * Create a {@code TransferResult} with {@code resultStore} as the resulting store. If the - * corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then - * {@code resultStore} is used for both the 'then' and 'else' edge. - * - *

For the meaning of storeChanged, see {@link - * org.checkerframework.dataflow.analysis.TransferResult#storeChanged}. - * - *

Exceptions: If the corresponding {@link - * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then the corresponding - * store in {@code exceptionalStores} is used. If no exception is found in {@code - * exceptionalStores}, then it is assumed that no special handling is necessary and the store - * before the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed - * along any exceptional edge. - * - *

Aliasing: {@code resultStore} and any store in {@code exceptionalStores} are not - * allowed to be used anywhere outside of this class (including use through aliases). Complete - * control over the objects is transfered to this class. - */ - public RegularTransferResult( - A value, S resultStore, Map exceptionalStores, boolean storeChanged) { - super(value); - this.store = resultStore; - this.storeChanged = storeChanged; - this.exceptionalStores = exceptionalStores; - } - - public RegularTransferResult(A value, S resultStore, Map exceptionalStores) { - this(value, resultStore, exceptionalStores, false); - } - - @Override - public S getRegularStore() { - return store; - } - - @Override - public S getThenStore() { - return store; - } - - @Override - public S getElseStore() { - // copy the store such that it is the same as the result of getThenStore - // (that is, identical according to equals), but two different objects. - return store.copy(); - } - - @Override - public boolean containsTwoStores() { - return false; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("RegularTransferResult("); - result.append(System.getProperty("line.separator")); - result.append("resultValue = " + resultValue); - result.append(System.getProperty("line.separator")); - result.append("store = " + store); - result.append(System.getProperty("line.separator")); - result.append(")"); - return result.toString(); - } - - /** @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged() */ - @Override - public boolean storeChanged() { - return storeChanged; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java deleted file mode 100644 index 5d714da889f3a0..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -import org.checkerframework.dataflow.cfg.CFGVisualizer; - -/** - * A store is used to keep track of the information that the org.checkerframework.dataflow analysis - * has accumulated at any given point in time. - * - * @author Stefan Heule - * @param the type of the store returned by {@code copy} and that is used in {@code - * leastUpperBound}. Usually it is the implementing class itself, e.g. in {@code T extends - * Store}. - */ -public interface Store> { - - // We maintain a then store and an else store before each basic block. - // When they are identical (by reference equality), they can be treated - // as a regular unconditional store. - // Once we have some information for both the then and else store, we - // create a TransferInput for the block and allow it to be analyzed. - public static enum Kind { - THEN, - ELSE, - BOTH - } - - /** A flow rule describes how stores flow along one edge between basic blocks. */ - public static enum FlowRule { - EACH_TO_EACH, // The normal case, then store flows to the then store - // and else store flows to the else store. - THEN_TO_BOTH, // Then store flows to both then and else of successor. - ELSE_TO_BOTH, // Else store flows to both then and else of successor. - THEN_TO_THEN, // Then store flows to the then of successor. Else store is ignored. - ELSE_TO_ELSE, // Else store flows to the else of successor. Then store is ignored. - } - - /** @return an exact copy of this store. */ - S copy(); - - /** - * Compute the least upper bound of two stores. - * - *

Important: This method must fulfill the following contract: - * - *

- */ - S leastUpperBound(S other); - - /** - * Compute an upper bound of two stores that is wider than the least upper bound of the two - * stores. Used to jump to a higher abstraction to allow faster termination of the fixed point - * computations in {@link Analysis}. {@code previous} must be the previous store. - * - *

A particular analysis might not require widening and should implement this method by - * calling leastUpperBound. - * - *

Important: This method must fulfill the following contract: - * - *

    - *
  • Does not change {@code this}. - *
  • Does not change {@code previous}. - *
  • Returns a fresh object which is not aliased yet. - *
  • Returns an object of the same (dynamic) type as {@code this}, even if the signature is - * more permissive. - *
  • Is commutative. - *
- * - * @param previous must be the previous store - */ - S widenedUpperBound(S previous); - - /** - * Can the objects {@code a} and {@code b} be aliases? Returns a conservative answer (i.e., - * returns {@code true} if not enough information is available to determine aliasing). - */ - boolean canAlias(FlowExpressions.Receiver a, FlowExpressions.Receiver b); - - /** - * Delegate visualization responsibility to a visualizer. - * - * @param viz the visualizer to visualize this store - */ - void visualize(CFGVisualizer viz); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java deleted file mode 100644 index a10a766b334660..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import java.util.List; -import org.checkerframework.dataflow.cfg.UnderlyingAST; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.NodeVisitor; - -/** - * Interface of a transfer function for the abstract interpretation used for the flow analysis. - * - *

A transfer function consists of the following components: - * - *

    - *
  • A method {@code initialStore} that determines which initial store should be used in the - * org.checkerframework.dataflow analysis. - *
  • A function for every {@link Node} type that determines the behavior of the - * org.checkerframework.dataflow analysis in that case. This method takes a {@link Node} and - * an incoming store, and produces a {@link RegularTransferResult}. - *
- * - *

Important: The individual transfer functions ( {@code visit*}) are allowed to use - * (and modify) the stores contained in the argument passed; the ownership is transfered from the - * caller to that function. - * - * @author Stefan Heule - * @param the {@link Store} used to keep track of intermediate results - */ -public interface TransferFunction, S extends Store> - extends NodeVisitor, TransferInput> { - - /** - * @return the initial store to be used by the org.checkerframework.dataflow analysis. {@code - * parameters} is only set if the underlying AST is a method. - */ - S initialStore(UnderlyingAST underlyingAST, /*@Nullable*/ List parameters); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java deleted file mode 100644 index f827ad302d21f2..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java +++ /dev/null @@ -1,250 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * {@code TransferInput} is used as the input type of the individual transfer functions of a {@link - * TransferFunction}. It also contains a reference to the node for which the transfer function will - * be applied. - * - *

A {@code TransferInput} contains one or two stores. If two stores are present, one belongs to - * 'then', and the other to 'else'. - * - * @author Stefan Heule - * @param the {@link Store} used to keep track of intermediate results - */ -public class TransferInput, S extends Store> { - - /** The corresponding node. */ - protected Node node; - - /** - * The regular result store (or {@code null} if none is present). The following invariant is - * maintained: - * - *

{@code
-     * store == null ⇔ thenStore != null && elseStore != null
-     * }
- */ - protected final /*@Nullable*/ S store; - - /** - * The 'then' result store (or {@code null} if none is present). The following invariant is - * maintained: - * - *
{@code
-     * store == null ⇔ thenStore != null && elseStore != null
-     * }
- */ - protected final /*@Nullable*/ S thenStore; - - /** - * The 'else' result store (or {@code null} if none is present). The following invariant is - * maintained: - * - *
{@code
-     * store == null ⇔ thenStore != null && elseStore != null
-     * }
- */ - protected final /*@Nullable*/ S elseStore; - - /** The corresponding analysis class to get intermediate flow results. */ - protected final Analysis analysis; - - /** - * Create a {@link TransferInput}, given a {@link TransferResult} and a node-value mapping. - * - *

Aliasing: The stores returned by any methods of {@code to} will be stored - * internally and are not allowed to be used elsewhere. Full control of them is transfered to - * this object. - * - *

The node-value mapping {@code nodeValues} is provided by the analysis and is only read - * from within this {@link TransferInput}. - */ - public TransferInput(Node n, Analysis analysis, TransferResult to) { - node = n; - this.analysis = analysis; - if (to.containsTwoStores()) { - thenStore = to.getThenStore(); - elseStore = to.getElseStore(); - store = null; - } else { - store = to.getRegularStore(); - thenStore = elseStore = null; - } - } - - /** - * Create a {@link TransferInput}, given a store and a node-value mapping. - * - *

Aliasing: The store {@code s} will be stored internally and is not allowed to be - * used elsewhere. Full control over {@code s} is transfered to this object. - * - *

The node-value mapping {@code nodeValues} is provided by the analysis and is only read - * from within this {@link TransferInput}. - */ - public TransferInput(Node n, Analysis analysis, S s) { - node = n; - this.analysis = analysis; - store = s; - thenStore = elseStore = null; - } - - /** - * Create a {@link TransferInput}, given two stores and a node-value mapping. - * - *

Aliasing: The two stores {@code s1} and {@code s2} will be stored internally and - * are not allowed to be used elsewhere. Full control of them is transfered to this object. - */ - public TransferInput(Node n, Analysis analysis, S s1, S s2) { - node = n; - this.analysis = analysis; - thenStore = s1; - elseStore = s2; - store = null; - } - - /** Copy constructor. */ - protected TransferInput(TransferInput from) { - this.node = from.node; - this.analysis = from.analysis; - if (from.store == null) { - thenStore = from.thenStore.copy(); - elseStore = from.elseStore.copy(); - store = null; - } else { - store = from.store.copy(); - thenStore = elseStore = null; - } - } - - /** @return the {@link Node} for this {@link TransferInput}. */ - public Node getNode() { - return node; - } - - /** - * @return the abstract value of {@link Node} {@code n}, which is required to be a 'sub-node' - * (that is, a direct or indirect child) of the node this transfer input is associated with. - * Furthermore, {@code n} cannot be a l-value node. Returns {@code null} if no value if - * available. - */ - public /*@Nullable*/ A getValueOfSubNode(Node n) { - return analysis.getValue(n); - } - - /** - * @return the regular result store produced if no exception is thrown by the {@link Node} - * corresponding to this transfer function result - */ - public S getRegularStore() { - if (store == null) { - return thenStore.leastUpperBound(elseStore); - } else { - return store; - } - } - - /** - * @return the result store produced if the {@link Node} this result belongs to evaluates to - * {@code true}. - */ - public S getThenStore() { - if (store == null) { - return thenStore; - } - return store; - } - - /** - * @return the result store produced if the {@link Node} this result belongs to evaluates to - * {@code false}. - */ - public S getElseStore() { - if (store == null) { - return elseStore; - } - // copy the store such that it is the same as the result of getThenStore - // (that is, identical according to equals), but two different objects. - return store.copy(); - } - - /** - * @return {@code true} if and only if this transfer input contains two stores that are - * potentially not equal. Note that the result {@code true} does not imply that {@code - * getRegularStore} cannot be called (or vice versa for {@code false}). Rather, it indicates - * that {@code getThenStore} or {@code getElseStore} can be used to give more precise - * results. Otherwise, if the result is {@code false}, then all three methods {@code - * getRegularStore}, {@code getThenStore}, and {@code getElseStore} return equivalent - * stores. - */ - public boolean containsTwoStores() { - return (thenStore != null && elseStore != null); - } - - /** @return an exact copy of this store. */ - public TransferInput copy() { - return new TransferInput<>(this); - } - - /** - * Compute the least upper bound of two stores. - * - *

Important: This method must fulfill the same contract as {@code leastUpperBound} - * of {@link Store}. - */ - public TransferInput leastUpperBound(TransferInput other) { - if (store == null) { - S newThenStore = thenStore.leastUpperBound(other.getThenStore()); - S newElseStore = elseStore.leastUpperBound(other.getElseStore()); - return new TransferInput<>(node, analysis, newThenStore, newElseStore); - } else { - if (other.store == null) { - // make sure we do not lose precision and keep two stores if at - // least one of the two TransferInput's has two stores. - return other.leastUpperBound(this); - } - return new TransferInput<>( - node, analysis, store.leastUpperBound(other.getRegularStore())); - } - } - - @Override - public boolean equals(Object o) { - if (o != null && o instanceof TransferInput) { - @SuppressWarnings("unchecked") - TransferInput other = (TransferInput) o; - if (containsTwoStores()) { - if (other.containsTwoStores()) { - return getThenStore().equals(other.getThenStore()) - && getElseStore().equals(other.getElseStore()); - } - } else { - if (!other.containsTwoStores()) { - return getRegularStore().equals(other.getRegularStore()); - } - } - } - return false; - } - - @Override - public int hashCode() { - return HashCodeUtils.hash( - this.analysis, this.node, this.store, this.thenStore, this.elseStore); - } - - @Override - public String toString() { - if (store == null) { - return "[then=" + thenStore + ", else=" + elseStore + "]"; - } else { - return "[" + store + "]"; - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java deleted file mode 100644 index 7c178a13fc3e0c..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import java.util.Map; -import javax.lang.model.type.TypeMirror; - -/** - * {@code TransferResult} is used as the result type of the individual transfer functions of a - * {@link TransferFunction}. It always belongs to the result of the individual transfer function for - * a particular {@link org.checkerframework.dataflow.cfg.node.Node}, even though that {@code - * org.checkerframework.dataflow.cfg.node.Node} is not explicitly store in {@code TransferResult}. - * - *

A {@code TransferResult} contains one or two stores (for 'then' and 'else'), and zero or more - * stores with a cause ({@link TypeMirror}). - * - * @author Stefan Heule - * @param the {@link Store} used to keep track of intermediate results - */ -public abstract class TransferResult, S extends Store> { - - /** - * The stores in case the basic block throws an exception (or {@code null} if the corresponding - * {@link org.checkerframework.dataflow.cfg.node.Node} does not throw any exceptions). Does not - * necessarily contain a store for every exception, in which case the in-store will be used. - */ - protected /*@Nullable*/ Map exceptionalStores; - - /** - * The abstract value of the {@link org.checkerframework.dataflow.cfg.node.Node} associated with - * this {@link TransferResult}, or {@code null} if no value has been produced. - */ - protected /*@Nullable*/ A resultValue; - - public TransferResult(/*@Nullable*/ A resultValue) { - this.resultValue = resultValue; - } - - /** @return the abstract value produced by the transfer function */ - public A getResultValue() { - return resultValue; - } - - public void setResultValue(A resultValue) { - this.resultValue = resultValue; - } - - /** - * @return the regular result store produced if no exception is thrown by the {@link - * org.checkerframework.dataflow.cfg.node.Node} corresponding to this transfer function - * result. - */ - public abstract S getRegularStore(); - - /** - * @return the result store produced if the {@link org.checkerframework.dataflow.cfg.node.Node} - * this result belongs to evaluates to {@code true}. - */ - public abstract S getThenStore(); - - /** - * @return the result store produced if the {@link org.checkerframework.dataflow.cfg.node.Node} - * this result belongs to evaluates to {@code false}. - */ - public abstract S getElseStore(); - - /** - * @return the store that flows along the outgoing exceptional edge labeled with {@code - * exception} (or {@code null} if no special handling is required for exceptional edges). - */ - public /*@Nullable*/ S getExceptionalStore(TypeMirror exception) { - if (exceptionalStores == null) { - return null; - } - return exceptionalStores.get(exception); - } - - /** - * @return a Map of {@link TypeMirror} to {@link Store} - * @see TransferResult#getExceptionalStore(TypeMirror) - */ - public Map getExceptionalStores() { - return exceptionalStores; - } - - /** - * @return {@code true} if and only if this transfer result contains two stores that are - * potentially not equal. Note that the result {@code true} does not imply that {@code - * getRegularStore} cannot be called (or vice versa for {@code false}). Rather, it indicates - * that {@code getThenStore} or {@code getElseStore} can be used to give more precise - * results. Otherwise, if the result is {@code false}, then all three methods {@code - * getRegularStore}, {@code getThenStore}, and {@code getElseStore} return equivalent - * stores. - */ - public abstract boolean containsTwoStores(); - - /** - * @return {@code true} if and only if the transfer function returning this transfer result - * changed the regularStore, elseStore, or thenStore. - */ - public abstract boolean storeChanged(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java deleted file mode 100644 index 55daff24ff14ae..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java +++ /dev/null @@ -1,4491 +0,0 @@ -package org.checkerframework.dataflow.cfg; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.AnnotatedTypeTree; -import com.sun.source.tree.AnnotationTree; -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.ArrayTypeTree; -import com.sun.source.tree.AssertTree; -import com.sun.source.tree.AssignmentTree; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.BlockTree; -import com.sun.source.tree.BreakTree; -import com.sun.source.tree.CaseTree; -import com.sun.source.tree.CatchTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.CompoundAssignmentTree; -import com.sun.source.tree.ConditionalExpressionTree; -import com.sun.source.tree.ContinueTree; -import com.sun.source.tree.DoWhileLoopTree; -import com.sun.source.tree.EmptyStatementTree; -import com.sun.source.tree.EnhancedForLoopTree; -import com.sun.source.tree.ErroneousTree; -import com.sun.source.tree.ExpressionStatementTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.ForLoopTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.IfTree; -import com.sun.source.tree.ImportTree; -import com.sun.source.tree.InstanceOfTree; -import com.sun.source.tree.LabeledStatementTree; -import com.sun.source.tree.LambdaExpressionTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberReferenceTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.ModifiersTree; -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.ParameterizedTypeTree; -import com.sun.source.tree.ParenthesizedTree; -import com.sun.source.tree.PrimitiveTypeTree; -import com.sun.source.tree.ReturnTree; -import com.sun.source.tree.StatementTree; -import com.sun.source.tree.SwitchTree; -import com.sun.source.tree.SynchronizedTree; -import com.sun.source.tree.ThrowTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.TryTree; -import com.sun.source.tree.TypeCastTree; -import com.sun.source.tree.TypeParameterTree; -import com.sun.source.tree.UnaryTree; -import com.sun.source.tree.UnionTypeTree; -import com.sun.source.tree.VariableTree; -import com.sun.source.tree.WhileLoopTree; -import com.sun.source.tree.WildcardTree; -import com.sun.source.util.TreePath; -import com.sun.source.util.TreePathScanner; -import com.sun.source.util.Trees; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.util.Context; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.PrimitiveType; -import javax.lang.model.type.ReferenceType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.UnionType; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.analysis.Store; -import org.checkerframework.dataflow.cfg.CFGBuilder.ExtendedNode.ExtendedNodeType; -import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod; -import org.checkerframework.dataflow.cfg.block.Block; -import org.checkerframework.dataflow.cfg.block.Block.BlockType; -import org.checkerframework.dataflow.cfg.block.BlockImpl; -import org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl; -import org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl; -import org.checkerframework.dataflow.cfg.block.RegularBlockImpl; -import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl; -import org.checkerframework.dataflow.cfg.block.SpecialBlock.SpecialBlockType; -import org.checkerframework.dataflow.cfg.block.SpecialBlockImpl; -import org.checkerframework.dataflow.cfg.node.ArrayAccessNode; -import org.checkerframework.dataflow.cfg.node.ArrayCreationNode; -import org.checkerframework.dataflow.cfg.node.ArrayTypeNode; -import org.checkerframework.dataflow.cfg.node.AssertionErrorNode; -import org.checkerframework.dataflow.cfg.node.AssignmentNode; -import org.checkerframework.dataflow.cfg.node.BitwiseAndNode; -import org.checkerframework.dataflow.cfg.node.BitwiseComplementNode; -import org.checkerframework.dataflow.cfg.node.BitwiseOrNode; -import org.checkerframework.dataflow.cfg.node.BitwiseXorNode; -import org.checkerframework.dataflow.cfg.node.BooleanLiteralNode; -import org.checkerframework.dataflow.cfg.node.CaseNode; -import org.checkerframework.dataflow.cfg.node.CharacterLiteralNode; -import org.checkerframework.dataflow.cfg.node.ClassNameNode; -import org.checkerframework.dataflow.cfg.node.ConditionalAndNode; -import org.checkerframework.dataflow.cfg.node.ConditionalNotNode; -import org.checkerframework.dataflow.cfg.node.ConditionalOrNode; -import org.checkerframework.dataflow.cfg.node.DoubleLiteralNode; -import org.checkerframework.dataflow.cfg.node.EqualToNode; -import org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.FieldAccessNode; -import org.checkerframework.dataflow.cfg.node.FloatLiteralNode; -import org.checkerframework.dataflow.cfg.node.FloatingDivisionNode; -import org.checkerframework.dataflow.cfg.node.FloatingRemainderNode; -import org.checkerframework.dataflow.cfg.node.FunctionalInterfaceNode; -import org.checkerframework.dataflow.cfg.node.GreaterThanNode; -import org.checkerframework.dataflow.cfg.node.GreaterThanOrEqualNode; -import org.checkerframework.dataflow.cfg.node.ImplicitThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.InstanceOfNode; -import org.checkerframework.dataflow.cfg.node.IntegerDivisionNode; -import org.checkerframework.dataflow.cfg.node.IntegerLiteralNode; -import org.checkerframework.dataflow.cfg.node.IntegerRemainderNode; -import org.checkerframework.dataflow.cfg.node.LeftShiftNode; -import org.checkerframework.dataflow.cfg.node.LessThanNode; -import org.checkerframework.dataflow.cfg.node.LessThanOrEqualNode; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.LongLiteralNode; -import org.checkerframework.dataflow.cfg.node.MarkerNode; -import org.checkerframework.dataflow.cfg.node.MethodAccessNode; -import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; -import org.checkerframework.dataflow.cfg.node.NarrowingConversionNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.NotEqualNode; -import org.checkerframework.dataflow.cfg.node.NullChkNode; -import org.checkerframework.dataflow.cfg.node.NullLiteralNode; -import org.checkerframework.dataflow.cfg.node.NumericalAdditionNode; -import org.checkerframework.dataflow.cfg.node.NumericalMinusNode; -import org.checkerframework.dataflow.cfg.node.NumericalMultiplicationNode; -import org.checkerframework.dataflow.cfg.node.NumericalPlusNode; -import org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode; -import org.checkerframework.dataflow.cfg.node.ObjectCreationNode; -import org.checkerframework.dataflow.cfg.node.PackageNameNode; -import org.checkerframework.dataflow.cfg.node.ParameterizedTypeNode; -import org.checkerframework.dataflow.cfg.node.PrimitiveTypeNode; -import org.checkerframework.dataflow.cfg.node.ReturnNode; -import org.checkerframework.dataflow.cfg.node.SignedRightShiftNode; -import org.checkerframework.dataflow.cfg.node.StringConcatenateAssignmentNode; -import org.checkerframework.dataflow.cfg.node.StringConcatenateNode; -import org.checkerframework.dataflow.cfg.node.StringConversionNode; -import org.checkerframework.dataflow.cfg.node.StringLiteralNode; -import org.checkerframework.dataflow.cfg.node.SuperNode; -import org.checkerframework.dataflow.cfg.node.SynchronizedNode; -import org.checkerframework.dataflow.cfg.node.TernaryExpressionNode; -import org.checkerframework.dataflow.cfg.node.ThisLiteralNode; -import org.checkerframework.dataflow.cfg.node.ThrowNode; -import org.checkerframework.dataflow.cfg.node.TypeCastNode; -import org.checkerframework.dataflow.cfg.node.UnsignedRightShiftNode; -import org.checkerframework.dataflow.cfg.node.ValueLiteralNode; -import org.checkerframework.dataflow.cfg.node.VariableDeclarationNode; -import org.checkerframework.dataflow.cfg.node.WideningConversionNode; -import org.checkerframework.dataflow.qual.TerminatesExecution; -import org.checkerframework.dataflow.util.MostlySingleton; -import org.checkerframework.javacutil.AnnotationProvider; -import org.checkerframework.javacutil.BasicAnnotationProvider; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.Pair; -import org.checkerframework.javacutil.TreeUtils; -import org.checkerframework.javacutil.TypesUtils; -import org.checkerframework.javacutil.trees.TreeBuilder; - -/** - * Builds the control flow graph of some Java code (either a method, or an arbitrary statement). - * - *

The translation of the AST to the CFG is split into three phases: - * - *

    - *
  1. Phase one. In the first phase, the AST is translated into a sequence of {@link - * org.checkerframework.dataflow.cfg.CFGBuilder.ExtendedNode}s. An extended node can either be - * a {@link Node}, or one of several meta elements such as a conditional or unconditional jump - * or a node with additional information about exceptions. Some of the extended nodes contain - * labels (e.g., for the jump target), and phase one additionally creates a mapping from - * labels to extended nodes. Finally, the list of leaders is computed: A leader is an extended - * node which will give rise to a basic block in phase two. - *
  2. Phase two. In this phase, the sequence of extended nodes is translated to a graph - * of control flow blocks that contain nodes. The meta elements from phase one are translated - * into the correct edges. - *
  3. Phase three. The control flow graph generated in phase two can contain degenerate - * basic blocks such as empty regular basic blocks or conditional basic blocks that have the - * same block as both 'then' and 'else' successor. This phase removes these cases while - * preserving the control flow structure. - *
- * - * @author Stefan Heule - */ -public class CFGBuilder { - - /** Can assertions be assumed to be disabled? */ - protected final boolean assumeAssertionsDisabled; - - /** Can assertions be assumed to be enabled? */ - protected final boolean assumeAssertionsEnabled; - - public CFGBuilder(boolean assumeAssertionsEnabled, boolean assumeAssertionsDisabled) { - assert !(assumeAssertionsDisabled && assumeAssertionsEnabled); - this.assumeAssertionsEnabled = assumeAssertionsEnabled; - this.assumeAssertionsDisabled = assumeAssertionsDisabled; - } - - /** - * Class declarations that have been encountered when building the control-flow graph for a - * method. - */ - protected final List declaredClasses = new LinkedList<>(); - - public List getDeclaredClasses() { - return declaredClasses; - } - - /** - * Lambdas encountered when building the control-flow graph for a method, variable initializer, - * or initializer. - */ - protected final List declaredLambdas = new LinkedList<>(); - - public List getDeclaredLambdas() { - return declaredLambdas; - } - - /** Build the control flow graph of some code. */ - public static ControlFlowGraph build( - CompilationUnitTree root, - ProcessingEnvironment env, - UnderlyingAST underlyingAST, - boolean assumeAssertionsEnabled, - boolean assumeAssertionsDisabled) { - return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled) - .run(root, env, underlyingAST); - } - - /** - * Build the control flow graph of some code (method, initializer block, ...). bodyPath is the - * TreePath to the body of that code. - */ - public static ControlFlowGraph build( - TreePath bodyPath, - ProcessingEnvironment env, - UnderlyingAST underlyingAST, - boolean assumeAssertionsEnabled, - boolean assumeAssertionsDisabled) { - return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled) - .run(bodyPath, env, underlyingAST); - } - - /** Build the control flow graph of a method. */ - public static ControlFlowGraph build( - CompilationUnitTree root, - ProcessingEnvironment env, - MethodTree tree, - ClassTree classTree, - boolean assumeAssertionsEnabled, - boolean assumeAssertionsDisabled) { - return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled) - .run(root, env, tree, classTree); - } - - /** Build the control flow graph of some code. */ - public static ControlFlowGraph build( - CompilationUnitTree root, ProcessingEnvironment env, UnderlyingAST underlyingAST) { - return new CFGBuilder(false, false).run(root, env, underlyingAST); - } - - /** Build the control flow graph of a method. */ - public static ControlFlowGraph build( - CompilationUnitTree root, - ProcessingEnvironment env, - MethodTree tree, - ClassTree classTree) { - return new CFGBuilder(false, false).run(root, env, tree, classTree); - } - - /** Build the control flow graph of some code. */ - public ControlFlowGraph run( - CompilationUnitTree root, ProcessingEnvironment env, UnderlyingAST underlyingAST) { - declaredClasses.clear(); - declaredLambdas.clear(); - - TreeBuilder builder = new TreeBuilder(env); - AnnotationProvider annotationProvider = new BasicAnnotationProvider(); - PhaseOneResult phase1result = - new CFGTranslationPhaseOne() - .process( - root, - env, - underlyingAST, - exceptionalExitLabel, - builder, - annotationProvider); - ControlFlowGraph phase2result = new CFGTranslationPhaseTwo().process(phase1result); - ControlFlowGraph phase3result = CFGTranslationPhaseThree.process(phase2result); - return phase3result; - } - - /** - * Build the control flow graph of some code (method, initializer block, ...). bodyPath is the - * TreePath to the body of that code. - */ - public ControlFlowGraph run( - TreePath bodyPath, ProcessingEnvironment env, UnderlyingAST underlyingAST) { - declaredClasses.clear(); - TreeBuilder builder = new TreeBuilder(env); - AnnotationProvider annotationProvider = new BasicAnnotationProvider(); - PhaseOneResult phase1result = - new CFGTranslationPhaseOne() - .process( - bodyPath, - env, - underlyingAST, - exceptionalExitLabel, - builder, - annotationProvider); - ControlFlowGraph phase2result = new CFGTranslationPhaseTwo().process(phase1result); - ControlFlowGraph phase3result = CFGTranslationPhaseThree.process(phase2result); - return phase3result; - } - - /** Build the control flow graph of a method. */ - public ControlFlowGraph run( - CompilationUnitTree root, - ProcessingEnvironment env, - MethodTree tree, - ClassTree classTree) { - UnderlyingAST underlyingAST = new CFGMethod(tree, classTree); - return run(root, env, underlyingAST); - } - - /* --------------------------------------------------------- */ - /* Extended Node Types and Labels */ - /* --------------------------------------------------------- */ - - /** Special label to identify the exceptional exit. */ - protected final Label exceptionalExitLabel = new Label(); - - /** Special label to identify the regular exit. */ - protected final Label regularExitLabel = new Label(); - - /** - * An extended node can be one of several things (depending on its {@code type}): - * - *
    - *
  • NODE. An extended node of this type is just a wrapper for a {@link Node} (that - * cannot throw exceptions). - *
  • EXCEPTION_NODE. A wrapper for a {@link Node} which can throw exceptions. It - * contains a label for every possible exception type the node might throw. - *
  • UNCONDITIONAL_JUMP. An unconditional jump to a label. - *
  • TWO_TARGET_CONDITIONAL_JUMP. A conditional jump with two targets for both the - * 'then' and 'else' branch. - *
- */ - protected abstract static class ExtendedNode { - - /** The basic block this extended node belongs to (as determined in phase two). */ - protected BlockImpl block; - - /** Type of this node. */ - protected ExtendedNodeType type; - - /** Does this node terminate the execution? (e.g., "System.exit()") */ - protected boolean terminatesExecution = false; - - public ExtendedNode(ExtendedNodeType type) { - this.type = type; - } - - /** Extended node types (description see above). */ - public enum ExtendedNodeType { - NODE, - EXCEPTION_NODE, - UNCONDITIONAL_JUMP, - CONDITIONAL_JUMP - } - - public ExtendedNodeType getType() { - return type; - } - - public boolean getTerminatesExecution() { - return terminatesExecution; - } - - public void setTerminatesExecution(boolean terminatesExecution) { - this.terminatesExecution = terminatesExecution; - } - - /** - * @return the node contained in this extended node (only applicable if the type is {@code - * NODE} or {@code EXCEPTION_NODE}). - */ - public Node getNode() { - assert false; - return null; - } - - /** - * @return the label associated with this extended node (only applicable if type is {@link - * ExtendedNodeType#CONDITIONAL_JUMP} or {@link ExtendedNodeType#UNCONDITIONAL_JUMP}). - */ - public Label getLabel() { - assert false; - return null; - } - - public BlockImpl getBlock() { - return block; - } - - public void setBlock(BlockImpl b) { - this.block = b; - } - - @Override - public String toString() { - return "ExtendedNode(" + type + ")"; - } - } - - /** An extended node of type {@code NODE}. */ - protected static class NodeHolder extends ExtendedNode { - - protected Node node; - - public NodeHolder(Node node) { - super(ExtendedNodeType.NODE); - this.node = node; - } - - @Override - public Node getNode() { - return node; - } - - @Override - public String toString() { - return "NodeHolder(" + node + ")"; - } - } - - /** An extended node of type {@code EXCEPTION_NODE}. */ - protected static class NodeWithExceptionsHolder extends ExtendedNode { - - protected Node node; - /** - * Map from exception type to labels of successors that may be reached as a result of that - * exception. - */ - protected Map> exceptions; - - public NodeWithExceptionsHolder(Node node, Map> exceptions) { - super(ExtendedNodeType.EXCEPTION_NODE); - this.node = node; - this.exceptions = exceptions; - } - - public Map> getExceptions() { - return exceptions; - } - - @Override - public Node getNode() { - return node; - } - - @Override - public String toString() { - return "NodeWithExceptionsHolder(" + node + ")"; - } - } - - /** - * An extended node of type {@link ExtendedNodeType#CONDITIONAL_JUMP}. - * - *

Important: In the list of extended nodes, there should not be any labels that - * point to a conditional jump. Furthermore, the node directly ahead of any conditional jump has - * to be a {@link NodeWithExceptionsHolder} or {@link NodeHolder}, and the node held by that - * extended node is required to be of boolean type. - */ - protected static class ConditionalJump extends ExtendedNode { - - protected Label trueSucc; - protected Label falseSucc; - - protected Store.FlowRule trueFlowRule; - protected Store.FlowRule falseFlowRule; - - public ConditionalJump(Label trueSucc, Label falseSucc) { - super(ExtendedNodeType.CONDITIONAL_JUMP); - this.trueSucc = trueSucc; - this.falseSucc = falseSucc; - } - - public Label getThenLabel() { - return trueSucc; - } - - public Label getElseLabel() { - return falseSucc; - } - - public Store.FlowRule getTrueFlowRule() { - return trueFlowRule; - } - - public Store.FlowRule getFalseFlowRule() { - return falseFlowRule; - } - - public void setTrueFlowRule(Store.FlowRule rule) { - trueFlowRule = rule; - } - - public void setFalseFlowRule(Store.FlowRule rule) { - falseFlowRule = rule; - } - - @Override - public String toString() { - return "TwoTargetConditionalJump(" + getThenLabel() + "," + getElseLabel() + ")"; - } - } - - /** An extended node of type {@link ExtendedNodeType#UNCONDITIONAL_JUMP}. */ - protected static class UnconditionalJump extends ExtendedNode { - - protected Label jumpTarget; - - public UnconditionalJump(Label jumpTarget) { - super(ExtendedNodeType.UNCONDITIONAL_JUMP); - this.jumpTarget = jumpTarget; - } - - @Override - public Label getLabel() { - return jumpTarget; - } - - @Override - public String toString() { - return "JumpMarker(" + getLabel() + ")"; - } - } - - /** - * A label is used to refer to other extended nodes using a mapping from labels to extended - * nodes. Labels get their names either from labeled statements in the source code or from - * internally generated unique names. - */ - protected static class Label { - private static int uid = 0; - - protected String name; - - public Label(String name) { - this.name = name; - } - - public Label() { - this.name = uniqueName(); - } - - @Override - public String toString() { - return name; - } - - /** - * Return a new unique label name that cannot be confused with a Java source code label. - * - * @return a new unique label name - */ - private static String uniqueName() { - return "%L" + uid++; - } - } - - /** - * A TryFrame takes a thrown exception type and maps it to a set of possible control-flow - * successors. - */ - protected static interface TryFrame { - /** - * Given a type of thrown exception, add the set of possible control flow successor {@link - * Label}s to the argument set. Return true if the exception is known to be caught by one of - * those labels and false if it may propagate still further. - */ - public boolean possibleLabels(TypeMirror thrown, Set

    - *
  1. Empty regular basic blocks: These blocks will be removed and their predecessors linked - * directly to the successor. - *
  2. Conditional basic blocks that have the same basic block as the 'then' and 'else' - * successor: The conditional basic block will be removed in this case. - *
  3. Two consecutive, non-empty, regular basic blocks where the second block has exactly one - * predecessor (namely the other of the two blocks): In this case, the two blocks are - * merged. - *
  4. Some basic blocks might not be reachable from the entryBlock. These basic blocks are - * removed, and the list of predecessors (in the doubly-linked structure of basic blocks) - * are adapted correctly. - *
- * - * Eliminating the second type of degenerate cases might introduce cases of the third problem. - * These are also removed. - */ - public static class CFGTranslationPhaseThree { - - /** - * A simple wrapper object that holds a basic block and allows to set one of its successors. - */ - protected interface PredecessorHolder { - void setSuccessor(BlockImpl b); - - BlockImpl getBlock(); - } - - /** - * Perform phase three on the control flow graph {@code cfg}. - * - * @param cfg the control flow graph. Ownership is transfered to this method and the caller - * is not allowed to read or modify {@code cfg} after the call to {@code process} any - * more. - * @return the resulting control flow graph - */ - public static ControlFlowGraph process(ControlFlowGraph cfg) { - Set worklist = cfg.getAllBlocks(); - Set dontVisit = new HashSet<>(); - - // note: this method has to be careful when relinking basic blocks - // to not forget to adjust the predecessors, too - - // fix predecessor lists by removing any unreachable predecessors - for (Block c : worklist) { - BlockImpl cur = (BlockImpl) c; - for (BlockImpl pred : new HashSet<>(cur.getPredecessors())) { - if (!worklist.contains(pred)) { - cur.removePredecessor(pred); - } - } - } - - // remove empty blocks - for (Block cur : worklist) { - if (dontVisit.contains(cur)) { - continue; - } - - if (cur.getType() == BlockType.REGULAR_BLOCK) { - RegularBlockImpl b = (RegularBlockImpl) cur; - if (b.isEmpty()) { - Set empty = new HashSet<>(); - Set predecessors = new HashSet<>(); - BlockImpl succ = computeNeighborhoodOfEmptyBlock(b, empty, predecessors); - for (RegularBlockImpl e : empty) { - succ.removePredecessor(e); - dontVisit.add(e); - } - for (PredecessorHolder p : predecessors) { - BlockImpl block = p.getBlock(); - dontVisit.add(block); - succ.removePredecessor(block); - p.setSuccessor(succ); - } - } - } - } - - // remove useless conditional blocks - worklist = cfg.getAllBlocks(); - for (Block c : worklist) { - BlockImpl cur = (BlockImpl) c; - - if (cur.getType() == BlockType.CONDITIONAL_BLOCK) { - ConditionalBlockImpl cb = (ConditionalBlockImpl) cur; - assert cb.getPredecessors().size() == 1; - if (cb.getThenSuccessor() == cb.getElseSuccessor()) { - BlockImpl pred = cb.getPredecessors().iterator().next(); - PredecessorHolder predecessorHolder = getPredecessorHolder(pred, cb); - BlockImpl succ = (BlockImpl) cb.getThenSuccessor(); - succ.removePredecessor(cb); - predecessorHolder.setSuccessor(succ); - } - } - } - - // merge consecutive basic blocks if possible - worklist = cfg.getAllBlocks(); - for (Block cur : worklist) { - if (cur.getType() == BlockType.REGULAR_BLOCK) { - RegularBlockImpl b = (RegularBlockImpl) cur; - Block succ = b.getRegularSuccessor(); - if (succ.getType() == BlockType.REGULAR_BLOCK) { - RegularBlockImpl rs = (RegularBlockImpl) succ; - if (rs.getPredecessors().size() == 1) { - b.setSuccessor(rs.getRegularSuccessor()); - b.addNodes(rs.getContents()); - rs.getRegularSuccessor().removePredecessor(rs); - } - } - } - } - - return cfg; - } - - /** - * Compute the set of empty regular basic blocks {@code empty}, starting at {@code start} - * and going both forward and backwards. Furthermore, compute the predecessors of these - * empty blocks ({@code predecessors} ), and their single successor (return value). - * - * @param start the starting point of the search (an empty, regular basic block) - * @param empty an empty set to be filled by this method with all empty basic blocks found - * (including {@code start}). - * @param predecessors an empty set to be filled by this method with all predecessors - * @return the single successor of the set of the empty basic blocks - */ - protected static BlockImpl computeNeighborhoodOfEmptyBlock( - RegularBlockImpl start, - Set empty, - Set predecessors) { - - // get empty neighborhood that come before 'start' - computeNeighborhoodOfEmptyBlockBackwards(start, empty, predecessors); - - // go forward - BlockImpl succ = (BlockImpl) start.getSuccessor(); - while (succ.getType() == BlockType.REGULAR_BLOCK) { - RegularBlockImpl cur = (RegularBlockImpl) succ; - if (cur.isEmpty()) { - computeNeighborhoodOfEmptyBlockBackwards(cur, empty, predecessors); - assert empty.contains(cur) : "cur ought to be in empty"; - succ = (BlockImpl) cur.getSuccessor(); - if (succ == cur) { - // An infinite loop, making exit block unreachable - break; - } - } else { - break; - } - } - return succ; - } - - /** - * Compute the set of empty regular basic blocks {@code empty}, starting at {@code start} - * and looking only backwards in the control flow graph. Furthermore, compute the - * predecessors of these empty blocks ( {@code predecessors}). - * - * @param start the starting point of the search (an empty, regular basic block) - * @param empty a set to be filled by this method with all empty basic blocks found - * (including {@code start}). - * @param predecessors a set to be filled by this method with all predecessors - */ - protected static void computeNeighborhoodOfEmptyBlockBackwards( - RegularBlockImpl start, - Set empty, - Set predecessors) { - - RegularBlockImpl cur = start; - empty.add(cur); - for (final BlockImpl pred : cur.getPredecessors()) { - switch (pred.getType()) { - case SPECIAL_BLOCK: - // add pred correctly to predecessor list - predecessors.add(getPredecessorHolder(pred, cur)); - break; - case CONDITIONAL_BLOCK: - // add pred correctly to predecessor list - predecessors.add(getPredecessorHolder(pred, cur)); - break; - case EXCEPTION_BLOCK: - // add pred correctly to predecessor list - predecessors.add(getPredecessorHolder(pred, cur)); - break; - case REGULAR_BLOCK: - RegularBlockImpl r = (RegularBlockImpl) pred; - if (r.isEmpty()) { - // recursively look backwards - if (!empty.contains(r)) { - computeNeighborhoodOfEmptyBlockBackwards(r, empty, predecessors); - } - } else { - // add pred correctly to predecessor list - predecessors.add(getPredecessorHolder(pred, cur)); - } - break; - } - } - } - - /** - * Return a predecessor holder that can be used to set the successor of {@code pred} in the - * place where previously the edge pointed to {@code cur}. Additionally, the predecessor - * holder also takes care of unlinking (i.e., removing the {@code pred} from {@code cur's} - * predecessors). - */ - protected static PredecessorHolder getPredecessorHolder( - final BlockImpl pred, final BlockImpl cur) { - switch (pred.getType()) { - case SPECIAL_BLOCK: - SingleSuccessorBlockImpl s = (SingleSuccessorBlockImpl) pred; - return singleSuccessorHolder(s, cur); - case CONDITIONAL_BLOCK: - // add pred correctly to predecessor list - final ConditionalBlockImpl c = (ConditionalBlockImpl) pred; - if (c.getThenSuccessor() == cur) { - return new PredecessorHolder() { - @Override - public void setSuccessor(BlockImpl b) { - c.setThenSuccessor(b); - cur.removePredecessor(pred); - } - - @Override - public BlockImpl getBlock() { - return c; - } - }; - } else { - assert c.getElseSuccessor() == cur; - return new PredecessorHolder() { - @Override - public void setSuccessor(BlockImpl b) { - c.setElseSuccessor(b); - cur.removePredecessor(pred); - } - - @Override - public BlockImpl getBlock() { - return c; - } - }; - } - case EXCEPTION_BLOCK: - // add pred correctly to predecessor list - final ExceptionBlockImpl e = (ExceptionBlockImpl) pred; - if (e.getSuccessor() == cur) { - return singleSuccessorHolder(e, cur); - } else { - Set>> entrySet = - e.getExceptionalSuccessors().entrySet(); - for (final Entry> entry : entrySet) { - if (entry.getValue().contains(cur)) { - return new PredecessorHolder() { - @Override - public void setSuccessor(BlockImpl b) { - e.addExceptionalSuccessor(b, entry.getKey()); - cur.removePredecessor(pred); - } - - @Override - public BlockImpl getBlock() { - return e; - } - }; - } - } - } - assert false; - break; - case REGULAR_BLOCK: - RegularBlockImpl r = (RegularBlockImpl) pred; - return singleSuccessorHolder(r, cur); - } - return null; - } - - /** - * @return a {@link PredecessorHolder} that sets the successor of a single successor block - * {@code s}. - */ - protected static PredecessorHolder singleSuccessorHolder( - final SingleSuccessorBlockImpl s, final BlockImpl old) { - return new PredecessorHolder() { - @Override - public void setSuccessor(BlockImpl b) { - s.setSuccessor(b); - old.removePredecessor(s); - } - - @Override - public BlockImpl getBlock() { - return s; - } - }; - } - } - - /* --------------------------------------------------------- */ - /* Phase Two */ - /* --------------------------------------------------------- */ - - /** Tuple class with up to three members. */ - protected static class Tuple { - public A a; - public B b; - public C c; - - public Tuple(A a, B b) { - this.a = a; - this.b = b; - } - - public Tuple(A a, B b, C c) { - this.a = a; - this.b = b; - this.c = c; - } - } - - /** Class that performs phase two of the translation process. */ - public class CFGTranslationPhaseTwo { - - public CFGTranslationPhaseTwo() {} - - /** - * Perform phase two of the translation. - * - * @param in the result of phase one - * @return a control flow graph that might still contain degenerate basic block (such as - * empty regular basic blocks or conditional blocks with the same block as 'then' and - * 'else' sucessor) - */ - public ControlFlowGraph process(PhaseOneResult in) { - - Map bindings = in.bindings; - ArrayList nodeList = in.nodeList; - Set leaders = in.leaders; - - assert in.nodeList.size() > 0; - - // exit blocks - SpecialBlockImpl regularExitBlock = new SpecialBlockImpl(SpecialBlockType.EXIT); - SpecialBlockImpl exceptionalExitBlock = - new SpecialBlockImpl(SpecialBlockType.EXCEPTIONAL_EXIT); - - // record missing edges that will be added later - Set> missingEdges = - new MostlySingleton<>(); - - // missing exceptional edges - Set> missingExceptionalEdges = - new HashSet<>(); - - // create start block - SpecialBlockImpl startBlock = new SpecialBlockImpl(SpecialBlockType.ENTRY); - missingEdges.add(new Tuple<>(startBlock, 0)); - - // loop through all 'leaders' (while dynamically detecting the - // leaders) - RegularBlockImpl block = new RegularBlockImpl(); - int i = 0; - for (ExtendedNode node : nodeList) { - switch (node.getType()) { - case NODE: - if (leaders.contains(i)) { - RegularBlockImpl b = new RegularBlockImpl(); - block.setSuccessor(b); - block = b; - } - block.addNode(node.getNode()); - node.setBlock(block); - - // does this node end the execution (modeled as an edge to - // the exceptional exit block) - boolean terminatesExecution = node.getTerminatesExecution(); - if (terminatesExecution) { - block.setSuccessor(exceptionalExitBlock); - block = new RegularBlockImpl(); - } - break; - case CONDITIONAL_JUMP: - { - ConditionalJump cj = (ConditionalJump) node; - // Exception nodes may fall through to conditional jumps, - // so we set the block which is required for the insertion - // of missing edges. - node.setBlock(block); - assert block != null; - final ConditionalBlockImpl cb = new ConditionalBlockImpl(); - if (cj.getTrueFlowRule() != null) { - cb.setThenFlowRule(cj.getTrueFlowRule()); - } - if (cj.getFalseFlowRule() != null) { - cb.setElseFlowRule(cj.getFalseFlowRule()); - } - block.setSuccessor(cb); - block = new RegularBlockImpl(); - // use two anonymous SingleSuccessorBlockImpl that set the - // 'then' and 'else' successor of the conditional block - final Label thenLabel = cj.getThenLabel(); - final Label elseLabel = cj.getElseLabel(); - missingEdges.add( - new Tuple<>( - new SingleSuccessorBlockImpl() { - @Override - public void setSuccessor(BlockImpl successor) { - cb.setThenSuccessor(successor); - } - }, - bindings.get(thenLabel))); - missingEdges.add( - new Tuple<>( - new SingleSuccessorBlockImpl() { - @Override - public void setSuccessor(BlockImpl successor) { - cb.setElseSuccessor(successor); - } - }, - bindings.get(elseLabel))); - break; - } - case UNCONDITIONAL_JUMP: - if (leaders.contains(i)) { - RegularBlockImpl b = new RegularBlockImpl(); - block.setSuccessor(b); - block = b; - } - node.setBlock(block); - if (node.getLabel() == regularExitLabel) { - block.setSuccessor(regularExitBlock); - } else if (node.getLabel() == exceptionalExitLabel) { - block.setSuccessor(exceptionalExitBlock); - } else { - missingEdges.add(new Tuple<>(block, bindings.get(node.getLabel()))); - } - block = new RegularBlockImpl(); - break; - case EXCEPTION_NODE: - NodeWithExceptionsHolder en = (NodeWithExceptionsHolder) node; - // create new exception block and link with previous block - ExceptionBlockImpl e = new ExceptionBlockImpl(); - Node nn = en.getNode(); - e.setNode(nn); - node.setBlock(e); - block.setSuccessor(e); - block = new RegularBlockImpl(); - - // ensure linking between e and next block (normal edge) - // Note: do not link to the next block for throw statements - // (these throw exceptions for sure) - if (!node.getTerminatesExecution()) { - missingEdges.add(new Tuple<>(e, i + 1)); - } - - // exceptional edges - for (Entry> entry : en.getExceptions().entrySet()) { - TypeMirror cause = entry.getKey(); - for (Label label : entry.getValue()) { - Integer target = bindings.get(label); - missingExceptionalEdges.add( - new Tuple( - e, target, cause)); - } - } - break; - } - i++; - } - - // add missing edges - for (Tuple p : missingEdges) { - Integer index = p.b; - ExtendedNode extendedNode = nodeList.get(index); - BlockImpl target = extendedNode.getBlock(); - SingleSuccessorBlockImpl source = p.a; - source.setSuccessor(target); - } - - // add missing exceptional edges - for (Tuple p : missingExceptionalEdges) { - Integer index = p.b; - TypeMirror cause = (TypeMirror) p.c; - ExceptionBlockImpl source = p.a; - if (index == null) { - // edge to exceptional exit - source.addExceptionalSuccessor(exceptionalExitBlock, cause); - } else { - // edge to specific target - ExtendedNode extendedNode = nodeList.get(index); - BlockImpl target = extendedNode.getBlock(); - source.addExceptionalSuccessor(target, cause); - } - } - - return new ControlFlowGraph( - startBlock, - regularExitBlock, - exceptionalExitBlock, - in.underlyingAST, - in.treeLookupMap, - in.convertedTreeLookupMap, - in.returnNodes); - } - } - - /* --------------------------------------------------------- */ - /* Phase One */ - /* --------------------------------------------------------- */ - - /** - * A wrapper object to pass around the result of phase one. For a documentation of the fields - * see {@link CFGTranslationPhaseOne}. - */ - protected static class PhaseOneResult { - - private final IdentityHashMap treeLookupMap; - private final IdentityHashMap convertedTreeLookupMap; - private final UnderlyingAST underlyingAST; - private final Map bindings; - private final ArrayList nodeList; - private final Set leaders; - private final List returnNodes; - - public PhaseOneResult( - UnderlyingAST underlyingAST, - IdentityHashMap treeLookupMap, - IdentityHashMap convertedTreeLookupMap, - ArrayList nodeList, - Map bindings, - Set leaders, - List returnNodes) { - this.underlyingAST = underlyingAST; - this.treeLookupMap = treeLookupMap; - this.convertedTreeLookupMap = convertedTreeLookupMap; - this.nodeList = nodeList; - this.bindings = bindings; - this.leaders = leaders; - this.returnNodes = returnNodes; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - for (ExtendedNode n : nodeList) { - sb.append(nodeToString(n)); - sb.append("\n"); - } - return sb.toString(); - } - - protected String nodeToString(ExtendedNode n) { - if (n.getType() == ExtendedNodeType.CONDITIONAL_JUMP) { - ConditionalJump t = (ConditionalJump) n; - return "TwoTargetConditionalJump(" - + resolveLabel(t.getThenLabel()) - + "," - + resolveLabel(t.getElseLabel()) - + ")"; - } else if (n.getType() == ExtendedNodeType.UNCONDITIONAL_JUMP) { - return "UnconditionalJump(" + resolveLabel(n.getLabel()) + ")"; - } else { - return n.toString(); - } - } - - private String resolveLabel(Label label) { - Integer index = bindings.get(label); - if (index == null) { - return "null"; - } - return nodeToString(nodeList.get(index)); - } - } - - /** - * Class that performs phase one of the translation process. It generates the following - * information: - * - *
    - *
  • A sequence of extended nodes. - *
  • A set of bindings from {@link Label}s to positions in the node sequence. - *
  • A set of leader nodes that give rise to basic blocks in phase two. - *
  • A lookup map that gives the mapping from AST tree nodes to {@link Node}s. - *
- * - *

The return type of this scanner is {@link Node}. For expressions, the corresponding node - * is returned to allow linking between different nodes. - * - *

However, for statements there is usually no single {@link Node} that is created, and thus - * no node is returned (rather, null is returned). - * - *

Every {@code visit*} method is assumed to add at least one extended node to the list of - * nodes (which might only be a jump). - */ - public class CFGTranslationPhaseOne extends TreePathScanner { - - public CFGTranslationPhaseOne() {} - - /** Annotation processing environment and its associated type and tree utilities. */ - protected ProcessingEnvironment env; - - protected Elements elements; - protected Types types; - protected Trees trees; - protected TreeBuilder treeBuilder; - protected AnnotationProvider annotationProvider; - - /** - * Current {@link Label} to which a break statement with no label should jump, or null if - * there is no valid destination. - */ - protected /*@Nullable*/ Label breakTargetL; - - /** - * Map from AST label Names to CFG {@link Label}s for breaks. Each labeled statement creates - * two CFG {@link Label}s, one for break and one for continue. - */ - protected Map breakLabels; - - /** - * Current {@link Label} to which a continue statement with no label should jump, or null if - * there is no valid destination. - */ - protected /*@Nullable*/ Label continueTargetL; - - /** - * Map from AST label Names to CFG {@link Label}s for continues. Each labeled statement - * creates two CFG {@link Label}s, one for break and one for continue. - */ - protected Map continueLabels; - - /** - * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces a value will have - * at least one corresponding Node. Trees that undergo conversions, such as boxing or - * unboxing, can map to two distinct Nodes. The Node for the pre-conversion value is stored - * in the treeLookupMap, while the Node for the post-conversion value is stored in the - * convertedTreeLookupMap. - */ - protected IdentityHashMap treeLookupMap; - - /** Map from AST {@link Tree}s to post-conversion {@link Node}s. */ - protected IdentityHashMap convertedTreeLookupMap; - - /** The list of extended nodes. */ - protected ArrayList nodeList; - - /** The bindings of labels to positions (i.e., indices) in the {@code nodeList}. */ - protected Map bindings; - - /** The set of leaders (represented as indices into {@code nodeList}). */ - protected Set leaders; - - /** - * All return nodes (if any) encountered. Only includes return statements that actually - * return something - */ - private List returnNodes; - - /** Nested scopes of try-catch blocks in force at the current program point. */ - private TryStack tryStack; - - /** - * Performs the actual work of phase one. - * - * @param bodyPath path to the body of the underlying AST's method - * @param env annotation processing environment containing type utilities - * @param underlyingAST the AST for which the CFG is to be built - * @param exceptionalExitLabel the label for exceptional exits from the CFG - * @param treeBuilder builder for new AST nodes - * @param annotationProvider extracts annotations from AST nodes - * @return the result of phase one - */ - public PhaseOneResult process( - TreePath bodyPath, - ProcessingEnvironment env, - UnderlyingAST underlyingAST, - Label exceptionalExitLabel, - TreeBuilder treeBuilder, - AnnotationProvider annotationProvider) { - this.env = env; - this.tryStack = new TryStack(exceptionalExitLabel); - this.treeBuilder = treeBuilder; - this.annotationProvider = annotationProvider; - elements = env.getElementUtils(); - types = env.getTypeUtils(); - - // initialize lists and maps - treeLookupMap = new IdentityHashMap<>(); - convertedTreeLookupMap = new IdentityHashMap<>(); - nodeList = new ArrayList<>(); - bindings = new HashMap<>(); - leaders = new HashSet<>(); - breakLabels = new HashMap<>(); - continueLabels = new HashMap<>(); - returnNodes = new ArrayList<>(); - - // traverse AST of the method body - scan(bodyPath, null); - - // add marker to indicate that the next block will be the exit block - // Note: if there is a return statement earlier in the method (which - // is always the case for non-void methods), then this is not - // strictly necessary. However, it is also not a problem, as it will - // just generate a degenerated control graph case that will be - // removed in a later phase. - nodeList.add(new UnconditionalJump(regularExitLabel)); - - return new PhaseOneResult( - underlyingAST, - treeLookupMap, - convertedTreeLookupMap, - nodeList, - bindings, - leaders, - returnNodes); - } - - public PhaseOneResult process( - CompilationUnitTree root, - ProcessingEnvironment env, - UnderlyingAST underlyingAST, - Label exceptionalExitLabel, - TreeBuilder treeBuilder, - AnnotationProvider annotationProvider) { - trees = Trees.instance(env); - TreePath bodyPath = trees.getPath(root, underlyingAST.getCode()); - return process( - bodyPath, - env, - underlyingAST, - exceptionalExitLabel, - treeBuilder, - annotationProvider); - } - - /** - * Perform any actions required when CFG translation creates a new Tree that is not part of - * the original AST. - * - * @param tree the newly created Tree - */ - public void handleArtificialTree(Tree tree) {} - - /* --------------------------------------------------------- */ - /* Nodes and Labels Management */ - /* --------------------------------------------------------- */ - - /** - * Add a node to the lookup map if it not already present. - * - * @param node the node to add to the lookup map - */ - protected void addToLookupMap(Node node) { - Tree tree = node.getTree(); - if (tree == null) { - return; - } - if (!treeLookupMap.containsKey(tree)) { - treeLookupMap.put(tree, node); - } - - Tree enclosingParens = parenMapping.get(tree); - while (enclosingParens != null) { - treeLookupMap.put(enclosingParens, node); - enclosingParens = parenMapping.get(enclosingParens); - } - } - - /** - * Add a node in the post-conversion lookup map. The node should refer to a Tree and that - * Tree should already be in the pre-conversion lookup map. This method is used to update - * the Tree-Node mapping with conversion nodes. - * - * @param node the node to add to the lookup map - */ - protected void addToConvertedLookupMap(Node node) { - Tree tree = node.getTree(); - addToConvertedLookupMap(tree, node); - } - - /** - * Add a node in the post-conversion lookup map. The tree argument should already be in the - * pre-conversion lookup map. This method is used to update the Tree-Node mapping with - * conversion nodes. - * - * @param tree the tree used as a key in the map - * @param node the node to add to the lookup map - */ - protected void addToConvertedLookupMap(Tree tree, Node node) { - assert tree != null; - assert treeLookupMap.containsKey(tree); - convertedTreeLookupMap.put(tree, node); - } - - /** - * Extend the list of extended nodes with a node. - * - * @param node the node to add - * @return the same node (for convenience) - */ - protected T extendWithNode(T node) { - addToLookupMap(node); - extendWithExtendedNode(new NodeHolder(node)); - return node; - } - - /** - * Extend the list of extended nodes with a node, where {@code node} might throw the - * exception {@code cause}. - * - * @param node the node to add - * @param cause an exception that the node might throw - * @return the node holder - */ - protected NodeWithExceptionsHolder extendWithNodeWithException( - Node node, TypeMirror cause) { - addToLookupMap(node); - return extendWithNodeWithExceptions(node, Collections.singleton(cause)); - } - - /** - * Extend the list of extended nodes with a node, where {@code node} might throw any of the - * exception in {@code causes}. - * - * @param node the node to add - * @param causes set of exceptions that the node might throw - * @return the node holder - */ - protected NodeWithExceptionsHolder extendWithNodeWithExceptions( - Node node, Set causes) { - addToLookupMap(node); - Map> exceptions = new HashMap<>(); - for (TypeMirror cause : causes) { - exceptions.put(cause, tryStack.possibleLabels(cause)); - } - NodeWithExceptionsHolder exNode = new NodeWithExceptionsHolder(node, exceptions); - extendWithExtendedNode(exNode); - return exNode; - } - - /** - * Insert {@code node} after {@code pred} in the list of extended nodes, or append to the - * list if {@code pred} is not present. - * - * @param node the node to add - * @param pred the desired predecessor of node - * @return the node holder - */ - protected T insertNodeAfter(T node, Node pred) { - addToLookupMap(node); - insertExtendedNodeAfter(new NodeHolder(node), pred); - return node; - } - - /** - * Insert a {@code node} that might throw the exception {@code cause} after {@code pred} in - * the list of extended nodes, or append to the list if {@code pred} is not present. - * - * @param node the node to add - * @param causes set of exceptions that the node might throw - * @param pred the desired predecessor of node - * @return the node holder - */ - protected NodeWithExceptionsHolder insertNodeWithExceptionsAfter( - Node node, Set causes, Node pred) { - addToLookupMap(node); - Map> exceptions = new HashMap<>(); - for (TypeMirror cause : causes) { - exceptions.put(cause, tryStack.possibleLabels(cause)); - } - NodeWithExceptionsHolder exNode = new NodeWithExceptionsHolder(node, exceptions); - insertExtendedNodeAfter(exNode, pred); - return exNode; - } - - /** - * Extend the list of extended nodes with an extended node. - * - * @param n the extended node - */ - protected void extendWithExtendedNode(ExtendedNode n) { - nodeList.add(n); - } - - /** - * Insert {@code n} after the node {@code pred} in the list of extended nodes, or append - * {@code n} if {@code pred} is not present. - * - * @param n the extended node - * @param pred the desired predecessor - */ - protected void insertExtendedNodeAfter(ExtendedNode n, Node pred) { - int index = -1; - for (int i = 0; i < nodeList.size(); i++) { - ExtendedNode inList = nodeList.get(i); - if (inList instanceof NodeHolder || inList instanceof NodeWithExceptionsHolder) { - if (inList.getNode() == pred) { - index = i; - break; - } - } - } - if (index != -1) { - nodeList.add(index + 1, n); - // update bindings - for (Entry e : bindings.entrySet()) { - if (e.getValue() >= index + 1) { - bindings.put(e.getKey(), e.getValue() + 1); - } - } - // update leaders - Set newLeaders = new HashSet<>(); - for (Integer l : leaders) { - if (l >= index + 1) { - newLeaders.add(l + 1); - } else { - newLeaders.add(l); - } - } - leaders = newLeaders; - } else { - nodeList.add(n); - } - } - - /** - * Add the label {@code l} to the extended node that will be placed next in the sequence. - */ - protected void addLabelForNextNode(Label l) { - leaders.add(nodeList.size()); - bindings.put(l, nodeList.size()); - } - - /* --------------------------------------------------------- */ - /* Utility Methods */ - /* --------------------------------------------------------- */ - - protected long uid = 0; - - protected String uniqueName(String prefix) { - return prefix + "#num" + uid++; - } - - /** - * If the input node is an unboxed primitive type, insert a call to the appropriate valueOf - * method, otherwise leave it alone. - * - * @param node in input node - * @return a Node representing the boxed version of the input, which may simply be the input - * node - */ - protected Node box(Node node) { - // For boxing conversion, see JLS 5.1.7 - if (TypesUtils.isPrimitive(node.getType())) { - PrimitiveType primitive = types.getPrimitiveType(node.getType().getKind()); - TypeMirror boxedType = types.getDeclaredType(types.boxedClass(primitive)); - - TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement(); - IdentifierTree classTree = treeBuilder.buildClassUse(boxedElement); - handleArtificialTree(classTree); - ClassNameNode className = new ClassNameNode(classTree); - className.setInSource(false); - insertNodeAfter(className, node); - - MemberSelectTree valueOfSelect = treeBuilder.buildValueOfMethodAccess(classTree); - handleArtificialTree(valueOfSelect); - MethodAccessNode valueOfAccess = new MethodAccessNode(valueOfSelect, className); - valueOfAccess.setInSource(false); - insertNodeAfter(valueOfAccess, className); - - MethodInvocationTree valueOfCall = - treeBuilder.buildMethodInvocation( - valueOfSelect, (ExpressionTree) node.getTree()); - handleArtificialTree(valueOfCall); - Node boxed = - new MethodInvocationNode( - valueOfCall, - valueOfAccess, - Collections.singletonList(node), - getCurrentPath()); - boxed.setInSource(false); - // Add Throwable to account for unchecked exceptions - TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable"); - addToConvertedLookupMap(node.getTree(), boxed); - insertNodeWithExceptionsAfter( - boxed, Collections.singleton(throwableElement.asType()), valueOfAccess); - return boxed; - } else { - return node; - } - } - - /** - * If the input node is a boxed type, unbox it, otherwise leave it alone. - * - * @param node in input node - * @return a Node representing the unboxed version of the input, which may simply be the - * input node - */ - protected Node unbox(Node node) { - if (TypesUtils.isBoxedPrimitive(node.getType())) { - - MemberSelectTree primValueSelect = - treeBuilder.buildPrimValueMethodAccess(node.getTree()); - handleArtificialTree(primValueSelect); - MethodAccessNode primValueAccess = new MethodAccessNode(primValueSelect, node); - primValueAccess.setInSource(false); - // Method access may throw NullPointerException - TypeElement npeElement = elements.getTypeElement("java.lang.NullPointerException"); - insertNodeWithExceptionsAfter( - primValueAccess, Collections.singleton(npeElement.asType()), node); - - MethodInvocationTree primValueCall = - treeBuilder.buildMethodInvocation(primValueSelect); - handleArtificialTree(primValueCall); - Node unboxed = - new MethodInvocationNode( - primValueCall, - primValueAccess, - Collections.emptyList(), - getCurrentPath()); - unboxed.setInSource(false); - - // Add Throwable to account for unchecked exceptions - TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable"); - addToConvertedLookupMap(node.getTree(), unboxed); - insertNodeWithExceptionsAfter( - unboxed, Collections.singleton(throwableElement.asType()), primValueAccess); - return unboxed; - } else { - return node; - } - } - - private TreeInfo getTreeInfo(Tree tree) { - final TypeMirror type = InternalUtils.typeOf(tree); - final boolean boxed = TypesUtils.isBoxedPrimitive(type); - final TypeMirror unboxedType = boxed ? types.unboxedType(type) : type; - - final boolean bool = TypesUtils.isBooleanType(type); - final boolean numeric = TypesUtils.isNumeric(unboxedType); - - return new TreeInfo() { - @Override - public boolean isNumeric() { - return numeric; - } - - @Override - public boolean isBoxed() { - return boxed; - } - - @Override - public boolean isBoolean() { - return bool; - } - - @Override - public TypeMirror unboxedType() { - return unboxedType; - } - }; - } - - /** @return the unboxed tree if necessary, as described in JLS 5.1.8 */ - private Node unboxAsNeeded(Node node, boolean boxed) { - return boxed ? unbox(node) : node; - } - - /** - * Convert the input node to String type, if it isn't already. - * - * @param node an input node - * @return a Node with the value promoted to String, which may be the input node - */ - protected Node stringConversion(Node node) { - // For string conversion, see JLS 5.1.11 - TypeElement stringElement = elements.getTypeElement("java.lang.String"); - if (!TypesUtils.isString(node.getType())) { - Node converted = - new StringConversionNode(node.getTree(), node, stringElement.asType()); - addToConvertedLookupMap(converted); - insertNodeAfter(converted, node); - return converted; - } else { - return node; - } - } - - /** - * Perform unary numeric promotion on the input node. - * - * @param node a node producing a value of numeric primitive or boxed type - * @return a Node with the value promoted to the int, long float or double, which may be the - * input node - */ - protected Node unaryNumericPromotion(Node node) { - // For unary numeric promotion, see JLS 5.6.1 - node = unbox(node); - - switch (node.getType().getKind()) { - case BYTE: - case CHAR: - case SHORT: - { - TypeMirror intType = types.getPrimitiveType(TypeKind.INT); - Node widened = new WideningConversionNode(node.getTree(), node, intType); - addToConvertedLookupMap(widened); - insertNodeAfter(widened, node); - return widened; - } - default: - // Nothing to do. - break; - } - - return node; - } - - /** - * Returns true if the argument type is a numeric primitive or a boxed numeric primitive and - * false otherwise. - */ - protected boolean isNumericOrBoxed(TypeMirror type) { - if (TypesUtils.isBoxedPrimitive(type)) { - type = types.unboxedType(type); - } - return TypesUtils.isNumeric(type); - } - - /** - * Compute the type to which two numeric types must be promoted before performing a binary - * numeric operation on them. The input types must both be numeric and the output type is - * primitive. - * - * @param left the type of the left operand - * @param right the type of the right operand - * @return a TypeMirror representing the binary numeric promoted type - */ - protected TypeMirror binaryPromotedType(TypeMirror left, TypeMirror right) { - if (TypesUtils.isBoxedPrimitive(left)) { - left = types.unboxedType(left); - } - if (TypesUtils.isBoxedPrimitive(right)) { - right = types.unboxedType(right); - } - TypeKind promotedTypeKind = TypesUtils.widenedNumericType(left, right); - return types.getPrimitiveType(promotedTypeKind); - } - - /** - * Perform binary numeric promotion on the input node to make it match the expression type. - * - * @param node a node producing a value of numeric primitive or boxed type - * @param exprType the type to promote the value to - * @return a Node with the value promoted to the exprType, which may be the input node - */ - protected Node binaryNumericPromotion(Node node, TypeMirror exprType) { - // For binary numeric promotion, see JLS 5.6.2 - node = unbox(node); - - if (!types.isSameType(node.getType(), exprType)) { - Node widened = new WideningConversionNode(node.getTree(), node, exprType); - addToConvertedLookupMap(widened); - insertNodeAfter(widened, node); - return widened; - } else { - return node; - } - } - - /** - * Perform widening primitive conversion on the input node to make it match the destination - * type. - * - * @param node a node producing a value of numeric primitive type - * @param destType the type to widen the value to - * @return a Node with the value widened to the exprType, which may be the input node - */ - protected Node widen(Node node, TypeMirror destType) { - // For widening conversion, see JLS 5.1.2 - assert TypesUtils.isPrimitive(node.getType()) && TypesUtils.isPrimitive(destType) - : "widening must be applied to primitive types"; - if (types.isSubtype(node.getType(), destType) - && !types.isSameType(node.getType(), destType)) { - Node widened = new WideningConversionNode(node.getTree(), node, destType); - addToConvertedLookupMap(widened); - insertNodeAfter(widened, node); - return widened; - } else { - return node; - } - } - - /** - * Perform narrowing conversion on the input node to make it match the destination type. - * - * @param node a node producing a value of numeric primitive type - * @param destType the type to narrow the value to - * @return a Node with the value narrowed to the exprType, which may be the input node - */ - protected Node narrow(Node node, TypeMirror destType) { - // For narrowing conversion, see JLS 5.1.3 - assert TypesUtils.isPrimitive(node.getType()) && TypesUtils.isPrimitive(destType) - : "narrowing must be applied to primitive types"; - if (types.isSubtype(destType, node.getType()) - && !types.isSameType(destType, node.getType())) { - Node narrowed = new NarrowingConversionNode(node.getTree(), node, destType); - addToConvertedLookupMap(narrowed); - insertNodeAfter(narrowed, node); - return narrowed; - } else { - return node; - } - } - - /** - * Perform narrowing conversion and optionally boxing conversion on the input node to make - * it match the destination type. - * - * @param node a node producing a value of numeric primitive type - * @param destType the type to narrow the value to (possibly boxed) - * @return a Node with the value narrowed and boxed to the destType, which may be the input - * node - */ - protected Node narrowAndBox(Node node, TypeMirror destType) { - if (TypesUtils.isBoxedPrimitive(destType)) { - return box(narrow(node, types.unboxedType(destType))); - } else { - return narrow(node, destType); - } - } - - /** - * Return whether a conversion from the type of the node to varType requires narrowing. - * - * @param varType the type of a variable (or general LHS) to be converted to - * @param node a node whose value is being converted - * @return whether this conversion requires narrowing to succeed - */ - protected boolean conversionRequiresNarrowing(TypeMirror varType, Node node) { - // Narrowing is restricted to cases where the left hand side - // is byte, char, short or Byte, Char, Short and the right - // hand side is a constant. - TypeMirror unboxedVarType = - TypesUtils.isBoxedPrimitive(varType) ? types.unboxedType(varType) : varType; - TypeKind unboxedVarKind = unboxedVarType.getKind(); - boolean isLeftNarrowableTo = - unboxedVarKind == TypeKind.BYTE - || unboxedVarKind == TypeKind.SHORT - || unboxedVarKind == TypeKind.CHAR; - boolean isRightConstant = node instanceof ValueLiteralNode; - return isLeftNarrowableTo && isRightConstant; - } - - /** - * Assignment conversion and method invocation conversion are almost identical, except that - * assignment conversion allows narrowing. We factor out the common logic here. - * - * @param node a Node producing a value - * @param varType the type of a variable - * @param contextAllowsNarrowing whether to allow narrowing (for assignment conversion) or - * not (for method invocation conversion) - * @return a Node with the value converted to the type of the variable, which may be the - * input node itself - */ - protected Node commonConvert( - Node node, TypeMirror varType, boolean contextAllowsNarrowing) { - // For assignment conversion, see JLS 5.2 - // For method invocation conversion, see JLS 5.3 - - // Check for identical types or "identity conversion" - TypeMirror nodeType = node.getType(); - boolean isSameType = types.isSameType(nodeType, varType); - if (isSameType) { - return node; - } - - boolean isRightNumeric = TypesUtils.isNumeric(nodeType); - boolean isRightPrimitive = TypesUtils.isPrimitive(nodeType); - boolean isRightBoxed = TypesUtils.isBoxedPrimitive(nodeType); - boolean isRightReference = nodeType instanceof ReferenceType; - boolean isLeftNumeric = TypesUtils.isNumeric(varType); - boolean isLeftPrimitive = TypesUtils.isPrimitive(varType); - // boolean isLeftBoxed = TypesUtils.isBoxedPrimitive(varType); - boolean isLeftReference = varType instanceof ReferenceType; - boolean isSubtype = types.isSubtype(nodeType, varType); - - if (isRightNumeric && isLeftNumeric && isSubtype) { - node = widen(node, varType); - nodeType = node.getType(); - } else if (isRightReference && isLeftReference && isSubtype) { - // widening reference conversion is a no-op, but if it - // applies, then later conversions do not. - } else if (isRightPrimitive && isLeftReference) { - if (contextAllowsNarrowing && conversionRequiresNarrowing(varType, node)) { - node = narrowAndBox(node, varType); - nodeType = node.getType(); - } else { - node = box(node); - nodeType = node.getType(); - } - } else if (isRightBoxed && isLeftPrimitive) { - node = unbox(node); - nodeType = node.getType(); - - if (types.isSubtype(nodeType, varType) && !types.isSameType(nodeType, varType)) { - node = widen(node, varType); - nodeType = node.getType(); - } - } else if (isRightPrimitive && isLeftPrimitive) { - if (contextAllowsNarrowing && conversionRequiresNarrowing(varType, node)) { - node = narrow(node, varType); - nodeType = node.getType(); - } - } - - // TODO: if checkers need to know about null references of - // a particular type, add logic for them here. - - return node; - } - - /** - * Perform assignment conversion so that it can be assigned to a variable of the given type. - * - * @param node a Node producing a value - * @param varType the type of a variable - * @return a Node with the value converted to the type of the variable, which may be the - * input node itself - */ - protected Node assignConvert(Node node, TypeMirror varType) { - return commonConvert(node, varType, true); - } - - /** - * Perform method invocation conversion so that the node can be passed as a formal parameter - * of the given type. - * - * @param node a Node producing a value - * @param formalType the type of a formal parameter - * @return a Node with the value converted to the type of the formal, which may be the input - * node itself - */ - protected Node methodInvocationConvert(Node node, TypeMirror formalType) { - return commonConvert(node, formalType, false); - } - - /** - * Given a method element and as list of argument expressions, return a list of {@link - * Node}s representing the arguments converted for a call of the method. This method applies - * to both method invocations and constructor calls. - * - * @param method an ExecutableElement representing a method to be called - * @param actualExprs a List of argument expressions to a call - * @return a List of {@link Node}s representing arguments after conversions required by a - * call to this method - */ - protected List convertCallArguments( - ExecutableElement method, List actualExprs) { - // NOTE: It is important to convert one method argument before - // generating CFG nodes for the next argument, since label binding - // expects nodes to be generated in execution order. Therefore, - // this method first determines which conversions need to be applied - // and then iterates over the actual arguments. - List formals = method.getParameters(); - - ArrayList convertedNodes = new ArrayList(); - - int numFormals = formals.size(); - int numActuals = actualExprs.size(); - if (method.isVarArgs()) { - // Create a new array argument if the actuals outnumber - // the formals, or if the last actual is not assignable - // to the last formal. - int lastArgIndex = numFormals - 1; - TypeMirror lastParamType = formals.get(lastArgIndex).asType(); - List dimensions = new ArrayList<>(); - List initializers = new ArrayList<>(); - - if (numActuals == numFormals - 1) { - // Apply method invocation conversion to all actual - // arguments, then create and append an empty array - for (int i = 0; i < numActuals; i++) { - Node actualVal = scan(actualExprs.get(i), null); - convertedNodes.add( - methodInvocationConvert(actualVal, formals.get(i).asType())); - } - - Node lastArgument = - new ArrayCreationNode(null, lastParamType, dimensions, initializers); - extendWithNode(lastArgument); - - convertedNodes.add(lastArgument); - } else { - TypeMirror actualType = InternalUtils.typeOf(actualExprs.get(lastArgIndex)); - if (numActuals == numFormals && types.isAssignable(actualType, lastParamType)) { - // Normal call with no array creation, apply method - // invocation conversion to all arguments. - for (int i = 0; i < numActuals; i++) { - Node actualVal = scan(actualExprs.get(i), null); - convertedNodes.add( - methodInvocationConvert(actualVal, formals.get(i).asType())); - } - } else { - assert lastParamType instanceof ArrayType - : "variable argument formal must be an array"; - // Apply method invocation conversion to lastArgIndex - // arguments and use the remaining ones to initialize - // an array. - for (int i = 0; i < lastArgIndex; i++) { - Node actualVal = scan(actualExprs.get(i), null); - convertedNodes.add( - methodInvocationConvert(actualVal, formals.get(i).asType())); - } - - TypeMirror elemType = ((ArrayType) lastParamType).getComponentType(); - for (int i = lastArgIndex; i < numActuals; i++) { - Node actualVal = scan(actualExprs.get(i), null); - initializers.add(assignConvert(actualVal, elemType)); - } - - Node lastArgument = - new ArrayCreationNode( - null, lastParamType, dimensions, initializers); - extendWithNode(lastArgument); - convertedNodes.add(lastArgument); - } - } - } else { - for (int i = 0; i < numActuals; i++) { - Node actualVal = scan(actualExprs.get(i), null); - convertedNodes.add(methodInvocationConvert(actualVal, formals.get(i).asType())); - } - } - - return convertedNodes; - } - - /** - * Convert an operand of a conditional expression to the type of the whole expression. - * - * @param node a node occurring as the second or third operand of a conditional expression - * @param destType the type to promote the value to - * @return a Node with the value promoted to the destType, which may be the input node - */ - protected Node conditionalExprPromotion(Node node, TypeMirror destType) { - // For rules on converting operands of conditional expressions, - // JLS 15.25 - TypeMirror nodeType = node.getType(); - - // If the operand is already the same type as the whole - // expression, then do nothing. - if (types.isSameType(nodeType, destType)) { - return node; - } - - // If the operand is a primitive and the whole expression is - // boxed, then apply boxing. - if (TypesUtils.isPrimitive(nodeType) && TypesUtils.isBoxedPrimitive(destType)) { - return box(node); - } - - // If the operand is byte or Byte and the whole expression is - // short, then convert to short. - boolean isBoxedPrimitive = TypesUtils.isBoxedPrimitive(nodeType); - TypeMirror unboxedNodeType = isBoxedPrimitive ? types.unboxedType(nodeType) : nodeType; - TypeMirror unboxedDestType = - TypesUtils.isBoxedPrimitive(destType) ? types.unboxedType(destType) : destType; - if (TypesUtils.isNumeric(unboxedNodeType) && TypesUtils.isNumeric(unboxedDestType)) { - if (unboxedNodeType.getKind() == TypeKind.BYTE - && destType.getKind() == TypeKind.SHORT) { - if (isBoxedPrimitive) { - node = unbox(node); - } - return widen(node, destType); - } - - // If the operand is Byte, Short or Character and the whole expression - // is the unboxed version of it, then apply unboxing. - TypeKind destKind = destType.getKind(); - if (destKind == TypeKind.BYTE - || destKind == TypeKind.CHAR - || destKind == TypeKind.SHORT) { - if (isBoxedPrimitive) { - return unbox(node); - } else if (nodeType.getKind() == TypeKind.INT) { - return narrow(node, destType); - } - } - - return binaryNumericPromotion(node, destType); - } - - // For the final case in JLS 15.25, apply boxing but not lub. - if (TypesUtils.isPrimitive(nodeType) - && (destType.getKind() == TypeKind.DECLARED - || destType.getKind() == TypeKind.UNION - || destType.getKind() == TypeKind.INTERSECTION)) { - return box(node); - } - - return node; - } - - /** - * Returns the label {@link Name} of the leaf in the argument path, or null if the leaf is - * not a labeled statement. - */ - protected /*@Nullable*/ Name getLabel(TreePath path) { - if (path.getParentPath() != null) { - Tree parent = path.getParentPath().getLeaf(); - if (parent.getKind() == Tree.Kind.LABELED_STATEMENT) { - return ((LabeledStatementTree) parent).getLabel(); - } - } - return null; - } - - /* --------------------------------------------------------- */ - /* Visitor Methods */ - /* --------------------------------------------------------- */ - - @Override - public Node visitAnnotatedType(AnnotatedTypeTree tree, Void p) { - return scan(tree.getUnderlyingType(), p); - } - - @Override - public Node visitAnnotation(AnnotationTree tree, Void p) { - assert false : "AnnotationTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public MethodInvocationNode visitMethodInvocation(MethodInvocationTree tree, Void p) { - - // see JLS 15.12.4 - - // First, compute the receiver, if any (15.12.4.1) - // Second, evaluate the actual arguments, left to right and - // possibly some arguments are stored into an array for variable - // arguments calls (15.12.4.2) - // Third, test the receiver, if any, for nullness (15.12.4.4) - // Fourth, convert the arguments to the type of the formal - // parameters (15.12.4.5) - // Fifth, if the method is synchronized, lock the receiving - // object or class (15.12.4.5) - ExecutableElement method = TreeUtils.elementFromUse(tree); - if (method == null) { - // The method wasn't found, e.g. because of a compilation error. - return null; - } - - // TODO? Variable wasn't used. - // boolean isBooleanMethod = TypesUtils.isBooleanType(method.getReturnType()); - - ExpressionTree methodSelect = tree.getMethodSelect(); - assert TreeUtils.isMethodAccess(methodSelect) - : "Expected a method access, but got: " + methodSelect; - - List actualExprs = tree.getArguments(); - - // Look up method to invoke and possibly throw NullPointerException - Node receiver = getReceiver(methodSelect, TreeUtils.enclosingClass(getCurrentPath())); - - MethodAccessNode target = new MethodAccessNode(methodSelect, receiver); - - ExecutableElement element = TreeUtils.elementFromUse(tree); - if (ElementUtils.isStatic(element) || receiver instanceof ThisLiteralNode) { - // No NullPointerException can be thrown, use normal node - extendWithNode(target); - } else { - TypeElement npeElement = elements.getTypeElement("java.lang.NullPointerException"); - extendWithNodeWithException(target, npeElement.asType()); - } - - List arguments = new ArrayList<>(); - - // Don't convert arguments for enum super calls. The AST contains - // no actual arguments, while the method element expects two arguments, - // leading to an exception in convertCallArguments. Since no actual - // arguments are present in the AST that is being checked, it shouldn't - // cause any harm to omit the conversions. - // See also BaseTypeVisitor.visitMethodInvocation and - // QualifierPolymorphism.annotate - if (!TreeUtils.isEnumSuper(tree)) { - arguments = convertCallArguments(method, actualExprs); - } - - // TODO: lock the receiver for synchronized methods - - MethodInvocationNode node = - new MethodInvocationNode(tree, target, arguments, getCurrentPath()); - - Set thrownSet = new HashSet<>(); - // Add exceptions explicitly mentioned in the throws clause. - List thrownTypes = element.getThrownTypes(); - thrownSet.addAll(thrownTypes); - // Add Throwable to account for unchecked exceptions - TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable"); - thrownSet.add(throwableElement.asType()); - - ExtendedNode extendedNode = extendWithNodeWithExceptions(node, thrownSet); - - /* Check for the TerminatesExecution annotation. */ - Element methodElement = InternalUtils.symbol(tree); - boolean terminatesExecution = - annotationProvider.getDeclAnnotation(methodElement, TerminatesExecution.class) - != null; - if (terminatesExecution) { - extendedNode.setTerminatesExecution(true); - } - - return node; - } - - @Override - public Node visitAssert(AssertTree tree, Void p) { - - // see JLS 14.10 - - // If assertions are enabled, then we can just translate the - // assertion. - if (assumeAssertionsEnabled || assumeAssertionsEnabledFor(tree)) { - translateAssertWithAssertionsEnabled(tree); - return null; - } - - // If assertions are disabled, then nothing is executed. - if (assumeAssertionsDisabled) { - return null; - } - - // Otherwise, we don't know if assertions are enabled, so we use a - // variable "ea" and case-split on it. One branch does execute the - // assertion, while the other assumes assertions are disabled. - VariableTree ea = getAssertionsEnabledVariable(); - - // all necessary labels - Label assertionEnabled = new Label(); - Label assertionDisabled = new Label(); - - extendWithNode(new LocalVariableNode(ea)); - extendWithExtendedNode(new ConditionalJump(assertionEnabled, assertionDisabled)); - - // 'then' branch (i.e. check the assertion) - addLabelForNextNode(assertionEnabled); - - translateAssertWithAssertionsEnabled(tree); - - // 'else' branch - addLabelForNextNode(assertionDisabled); - - return null; - } - - /** - * Should assertions be assumed to be executed for a given {@link AssertTree}? False by - * default. - */ - protected boolean assumeAssertionsEnabledFor(AssertTree tree) { - return false; - } - - /** The {@link VariableTree} that indicates whether assertions are enabled or not. */ - protected VariableTree ea = null; - - /** - * Get a synthetic {@link VariableTree} that indicates whether assertions are enabled or - * not. - */ - protected VariableTree getAssertionsEnabledVariable() { - if (ea == null) { - String name = uniqueName("assertionsEnabled"); - MethodTree enclosingMethod = TreeUtils.enclosingMethod(getCurrentPath()); - Element owner; - if (enclosingMethod != null) { - owner = TreeUtils.elementFromDeclaration(enclosingMethod); - } else { - ClassTree enclosingClass = TreeUtils.enclosingClass(getCurrentPath()); - owner = TreeUtils.elementFromDeclaration(enclosingClass); - } - ExpressionTree initializer = null; - ea = - treeBuilder.buildVariableDecl( - types.getPrimitiveType(TypeKind.BOOLEAN), name, owner, initializer); - } - return ea; - } - - /** - * Translates an assertion statement to the correct CFG nodes. The translation assumes that - * assertions are enabled. - */ - protected void translateAssertWithAssertionsEnabled(AssertTree tree) { - - // all necessary labels - Label assertEnd = new Label(); - Label elseEntry = new Label(); - - // basic block for the condition - Node condition = unbox(scan(tree.getCondition(), null)); - ConditionalJump cjump = new ConditionalJump(assertEnd, elseEntry); - extendWithExtendedNode(cjump); - - // else branch - Node detail = null; - addLabelForNextNode(elseEntry); - if (tree.getDetail() != null) { - detail = scan(tree.getDetail(), null); - } - TypeElement assertException = elements.getTypeElement("java.lang.AssertionError"); - AssertionErrorNode assertNode = - new AssertionErrorNode(tree, condition, detail, assertException.asType()); - extendWithNode(assertNode); - NodeWithExceptionsHolder exNode = - extendWithNodeWithException( - new ThrowNode(null, assertNode, env.getTypeUtils()), - assertException.asType()); - exNode.setTerminatesExecution(true); - - // then branch (nothing happens) - addLabelForNextNode(assertEnd); - } - - @Override - public Node visitAssignment(AssignmentTree tree, Void p) { - - // see JLS 15.26.1 - - AssignmentNode assignmentNode; - ExpressionTree variable = tree.getVariable(); - TypeMirror varType = InternalUtils.typeOf(variable); - - // case 1: field access - if (TreeUtils.isFieldAccess(variable)) { - // visit receiver - Node receiver = getReceiver(variable, TreeUtils.enclosingClass(getCurrentPath())); - - // visit expression - Node expression = scan(tree.getExpression(), p); - expression = assignConvert(expression, varType); - - // visit field access (throws null-pointer exception) - FieldAccessNode target = new FieldAccessNode(variable, receiver); - target.setLValue(); - - Element element = TreeUtils.elementFromUse(variable); - if (ElementUtils.isStatic(element) || receiver instanceof ThisLiteralNode) { - // No NullPointerException can be thrown, use normal node - extendWithNode(target); - } else { - TypeElement npeElement = - elements.getTypeElement("java.lang.NullPointerException"); - extendWithNodeWithException(target, npeElement.asType()); - } - - // add assignment node - assignmentNode = new AssignmentNode(tree, target, expression); - extendWithNode(assignmentNode); - } - - // case 2: other cases - else { - Node target = scan(variable, p); - target.setLValue(); - - assignmentNode = translateAssignment(tree, target, tree.getExpression()); - } - - return assignmentNode; - } - - /** Translate an assignment. */ - protected AssignmentNode translateAssignment(Tree tree, Node target, ExpressionTree rhs) { - Node expression = scan(rhs, null); - return translateAssignment(tree, target, expression); - } - - /** Translate an assignment where the RHS has already been scanned. */ - protected AssignmentNode translateAssignment(Tree tree, Node target, Node expression) { - assert tree instanceof AssignmentTree || tree instanceof VariableTree; - target.setLValue(); - expression = assignConvert(expression, target.getType()); - AssignmentNode assignmentNode = new AssignmentNode(tree, target, expression); - extendWithNode(assignmentNode); - return assignmentNode; - } - - /** - * Note 1: Requires {@code tree} to be a field or method access tree. - * - *

Note 2: Visits the receiver and adds all necessary blocks to the CFG. - * - * @param tree the field access tree containing the receiver - * @param classTree the ClassTree enclosing the field access - * @return the receiver of the field access - */ - private Node getReceiver(ExpressionTree tree, ClassTree classTree) { - assert TreeUtils.isFieldAccess(tree) || TreeUtils.isMethodAccess(tree); - if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) { - MemberSelectTree mtree = (MemberSelectTree) tree; - return scan(mtree.getExpression(), null); - } else { - Element ele = TreeUtils.elementFromUse(tree); - TypeElement declaringClass = ElementUtils.enclosingClass(ele); - TypeMirror type = ElementUtils.getType(declaringClass); - if (ElementUtils.isStatic(ele)) { - Node node = new ClassNameNode(type, declaringClass); - extendWithNode(node); - return node; - } else { - Node node = new ImplicitThisLiteralNode(type); - extendWithNode(node); - return node; - } - } - } - - /** - * Map an operation with assignment to the corresponding operation without assignment. - * - * @param kind a Tree.Kind representing an operation with assignment - * @return the Tree.Kind for the same operation without assignment - */ - protected Tree.Kind withoutAssignment(Tree.Kind kind) { - switch (kind) { - case DIVIDE_ASSIGNMENT: - return Tree.Kind.DIVIDE; - case MULTIPLY_ASSIGNMENT: - return Tree.Kind.MULTIPLY; - case REMAINDER_ASSIGNMENT: - return Tree.Kind.REMAINDER; - case MINUS_ASSIGNMENT: - return Tree.Kind.MINUS; - case PLUS_ASSIGNMENT: - return Tree.Kind.PLUS; - case LEFT_SHIFT_ASSIGNMENT: - return Tree.Kind.LEFT_SHIFT; - case RIGHT_SHIFT_ASSIGNMENT: - return Tree.Kind.RIGHT_SHIFT; - case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: - return Tree.Kind.UNSIGNED_RIGHT_SHIFT; - case AND_ASSIGNMENT: - return Tree.Kind.AND; - case OR_ASSIGNMENT: - return Tree.Kind.OR; - case XOR_ASSIGNMENT: - return Tree.Kind.XOR; - default: - return Tree.Kind.ERRONEOUS; - } - } - - @Override - public Node visitCompoundAssignment(CompoundAssignmentTree tree, Void p) { - // According the JLS 15.26.2, E1 op= E2 is equivalent to - // E1 = (T) ((E1) op (E2)), where T is the type of E1, - // except that E1 is evaluated only once. - // - - Tree.Kind kind = tree.getKind(); - switch (kind) { - case DIVIDE_ASSIGNMENT: - case MULTIPLY_ASSIGNMENT: - case REMAINDER_ASSIGNMENT: - { - // see JLS 15.17 and 15.26.2 - Node targetLHS = scan(tree.getVariable(), p); - Node value = scan(tree.getExpression(), p); - - TypeMirror exprType = InternalUtils.typeOf(tree); - TypeMirror leftType = InternalUtils.typeOf(tree.getVariable()); - TypeMirror rightType = InternalUtils.typeOf(tree.getExpression()); - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - Node targetRHS = binaryNumericPromotion(targetLHS, promotedType); - value = binaryNumericPromotion(value, promotedType); - - BinaryTree operTree = - treeBuilder.buildBinary( - promotedType, - withoutAssignment(kind), - tree.getVariable(), - tree.getExpression()); - handleArtificialTree(operTree); - Node operNode; - if (kind == Tree.Kind.MULTIPLY_ASSIGNMENT) { - operNode = new NumericalMultiplicationNode(operTree, targetRHS, value); - } else if (kind == Tree.Kind.DIVIDE_ASSIGNMENT) { - if (TypesUtils.isIntegral(exprType)) { - operNode = new IntegerDivisionNode(operTree, targetRHS, value); - } else { - operNode = new FloatingDivisionNode(operTree, targetRHS, value); - } - } else { - assert kind == Kind.REMAINDER_ASSIGNMENT; - if (TypesUtils.isIntegral(exprType)) { - operNode = new IntegerRemainderNode(operTree, targetRHS, value); - } else { - operNode = new FloatingRemainderNode(operTree, targetRHS, value); - } - } - extendWithNode(operNode); - - TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree); - handleArtificialTree(castTree); - TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType); - castNode.setInSource(false); - extendWithNode(castNode); - - AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode); - extendWithNode(assignNode); - return assignNode; - } - - case MINUS_ASSIGNMENT: - case PLUS_ASSIGNMENT: - { - // see JLS 15.18 and 15.26.2 - - Node targetLHS = scan(tree.getVariable(), p); - Node value = scan(tree.getExpression(), p); - - TypeMirror leftType = InternalUtils.typeOf(tree.getVariable()); - TypeMirror rightType = InternalUtils.typeOf(tree.getExpression()); - - if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) { - assert (kind == Tree.Kind.PLUS_ASSIGNMENT); - Node targetRHS = stringConversion(targetLHS); - value = stringConversion(value); - Node r = new StringConcatenateAssignmentNode(tree, targetRHS, value); - extendWithNode(r); - return r; - } else { - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - Node targetRHS = binaryNumericPromotion(targetLHS, promotedType); - value = binaryNumericPromotion(value, promotedType); - - BinaryTree operTree = - treeBuilder.buildBinary( - promotedType, - withoutAssignment(kind), - tree.getVariable(), - tree.getExpression()); - handleArtificialTree(operTree); - Node operNode; - if (kind == Tree.Kind.PLUS_ASSIGNMENT) { - operNode = new NumericalAdditionNode(operTree, targetRHS, value); - } else { - assert kind == Kind.MINUS_ASSIGNMENT; - operNode = new NumericalSubtractionNode(operTree, targetRHS, value); - } - extendWithNode(operNode); - - TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree); - handleArtificialTree(castTree); - TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType); - castNode.setInSource(false); - extendWithNode(castNode); - - // Map the compound assignment tree to an assignment node, which - // will have the correct type. - AssignmentNode assignNode = - new AssignmentNode(tree, targetLHS, castNode); - extendWithNode(assignNode); - return assignNode; - } - } - - case LEFT_SHIFT_ASSIGNMENT: - case RIGHT_SHIFT_ASSIGNMENT: - case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: - { - // see JLS 15.19 and 15.26.2 - Node targetLHS = scan(tree.getVariable(), p); - Node value = scan(tree.getExpression(), p); - - TypeMirror leftType = InternalUtils.typeOf(tree.getVariable()); - - Node targetRHS = unaryNumericPromotion(targetLHS); - value = unaryNumericPromotion(value); - - BinaryTree operTree = - treeBuilder.buildBinary( - leftType, - withoutAssignment(kind), - tree.getVariable(), - tree.getExpression()); - handleArtificialTree(operTree); - Node operNode; - if (kind == Tree.Kind.LEFT_SHIFT_ASSIGNMENT) { - operNode = new LeftShiftNode(operTree, targetRHS, value); - } else if (kind == Tree.Kind.RIGHT_SHIFT_ASSIGNMENT) { - operNode = new SignedRightShiftNode(operTree, targetRHS, value); - } else { - assert kind == Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT; - operNode = new UnsignedRightShiftNode(operTree, targetRHS, value); - } - extendWithNode(operNode); - - TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree); - handleArtificialTree(castTree); - TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType); - castNode.setInSource(false); - extendWithNode(castNode); - - AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode); - extendWithNode(assignNode); - return assignNode; - } - - case AND_ASSIGNMENT: - case OR_ASSIGNMENT: - case XOR_ASSIGNMENT: - // see JLS 15.22 - Node targetLHS = scan(tree.getVariable(), p); - Node value = scan(tree.getExpression(), p); - - TypeMirror leftType = InternalUtils.typeOf(tree.getVariable()); - TypeMirror rightType = InternalUtils.typeOf(tree.getExpression()); - - Node targetRHS = null; - if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) { - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - targetRHS = binaryNumericPromotion(targetLHS, promotedType); - value = binaryNumericPromotion(value, promotedType); - } else if (TypesUtils.isBooleanType(leftType) - && TypesUtils.isBooleanType(rightType)) { - targetRHS = unbox(targetLHS); - value = unbox(value); - } else { - assert false - : "Both argument to logical operation must be numeric or boolean"; - } - - BinaryTree operTree = - treeBuilder.buildBinary( - leftType, - withoutAssignment(kind), - tree.getVariable(), - tree.getExpression()); - handleArtificialTree(operTree); - Node operNode; - if (kind == Tree.Kind.AND_ASSIGNMENT) { - operNode = new BitwiseAndNode(operTree, targetRHS, value); - } else if (kind == Tree.Kind.OR_ASSIGNMENT) { - operNode = new BitwiseOrNode(operTree, targetRHS, value); - } else { - assert kind == Kind.XOR_ASSIGNMENT; - operNode = new BitwiseXorNode(operTree, targetRHS, value); - } - extendWithNode(operNode); - - TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree); - handleArtificialTree(castTree); - TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType); - castNode.setInSource(false); - extendWithNode(castNode); - - AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode); - extendWithNode(assignNode); - return assignNode; - default: - assert false : "unexpected compound assignment type"; - break; - } - assert false : "unexpected compound assignment type"; - return null; - } - - @Override - public Node visitBinary(BinaryTree tree, Void p) { - // Note that for binary operations it is important to perform any required - // promotion on the left operand before generating any Nodes for the right - // operand, because labels must be inserted AFTER ALL preceding Nodes and - // BEFORE ALL following Nodes. - Node r = null; - Tree leftTree = tree.getLeftOperand(); - Tree rightTree = tree.getRightOperand(); - - Tree.Kind kind = tree.getKind(); - switch (kind) { - case DIVIDE: - case MULTIPLY: - case REMAINDER: - { - // see JLS 15.17 - - TypeMirror exprType = InternalUtils.typeOf(tree); - TypeMirror leftType = InternalUtils.typeOf(leftTree); - TypeMirror rightType = InternalUtils.typeOf(rightTree); - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - - Node left = binaryNumericPromotion(scan(leftTree, p), promotedType); - Node right = binaryNumericPromotion(scan(rightTree, p), promotedType); - - if (kind == Tree.Kind.MULTIPLY) { - r = new NumericalMultiplicationNode(tree, left, right); - } else if (kind == Tree.Kind.DIVIDE) { - if (TypesUtils.isIntegral(exprType)) { - r = new IntegerDivisionNode(tree, left, right); - } else { - r = new FloatingDivisionNode(tree, left, right); - } - } else { - assert kind == Kind.REMAINDER; - if (TypesUtils.isIntegral(exprType)) { - r = new IntegerRemainderNode(tree, left, right); - } else { - r = new FloatingRemainderNode(tree, left, right); - } - } - break; - } - - case MINUS: - case PLUS: - { - // see JLS 15.18 - - // TypeMirror exprType = InternalUtils.typeOf(tree); - TypeMirror leftType = InternalUtils.typeOf(leftTree); - TypeMirror rightType = InternalUtils.typeOf(rightTree); - - if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) { - assert (kind == Tree.Kind.PLUS); - Node left = stringConversion(scan(leftTree, p)); - Node right = stringConversion(scan(rightTree, p)); - r = new StringConcatenateNode(tree, left, right); - } else { - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - Node left = binaryNumericPromotion(scan(leftTree, p), promotedType); - Node right = binaryNumericPromotion(scan(rightTree, p), promotedType); - - // TODO: Decide whether to deal with floating-point value - // set conversion. - if (kind == Tree.Kind.PLUS) { - r = new NumericalAdditionNode(tree, left, right); - } else { - assert kind == Kind.MINUS; - r = new NumericalSubtractionNode(tree, left, right); - } - } - break; - } - - case LEFT_SHIFT: - case RIGHT_SHIFT: - case UNSIGNED_RIGHT_SHIFT: - { - // see JLS 15.19 - - Node left = unaryNumericPromotion(scan(leftTree, p)); - Node right = unaryNumericPromotion(scan(rightTree, p)); - - if (kind == Tree.Kind.LEFT_SHIFT) { - r = new LeftShiftNode(tree, left, right); - } else if (kind == Tree.Kind.RIGHT_SHIFT) { - r = new SignedRightShiftNode(tree, left, right); - } else { - assert kind == Kind.UNSIGNED_RIGHT_SHIFT; - r = new UnsignedRightShiftNode(tree, left, right); - } - break; - } - - case GREATER_THAN: - case GREATER_THAN_EQUAL: - case LESS_THAN: - case LESS_THAN_EQUAL: - { - // see JLS 15.20.1 - TypeMirror leftType = InternalUtils.typeOf(leftTree); - if (TypesUtils.isBoxedPrimitive(leftType)) { - leftType = types.unboxedType(leftType); - } - - TypeMirror rightType = InternalUtils.typeOf(rightTree); - if (TypesUtils.isBoxedPrimitive(rightType)) { - rightType = types.unboxedType(rightType); - } - - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - Node left = binaryNumericPromotion(scan(leftTree, p), promotedType); - Node right = binaryNumericPromotion(scan(rightTree, p), promotedType); - - Node node; - if (kind == Tree.Kind.GREATER_THAN) { - node = new GreaterThanNode(tree, left, right); - } else if (kind == Tree.Kind.GREATER_THAN_EQUAL) { - node = new GreaterThanOrEqualNode(tree, left, right); - } else if (kind == Tree.Kind.LESS_THAN) { - node = new LessThanNode(tree, left, right); - } else { - assert kind == Tree.Kind.LESS_THAN_EQUAL; - node = new LessThanOrEqualNode(tree, left, right); - } - - extendWithNode(node); - - return node; - } - - case EQUAL_TO: - case NOT_EQUAL_TO: - { - // see JLS 15.21 - TreeInfo leftInfo = getTreeInfo(leftTree); - TreeInfo rightInfo = getTreeInfo(rightTree); - Node left = scan(leftTree, p); - Node right = scan(rightTree, p); - - if (leftInfo.isNumeric() - && rightInfo.isNumeric() - && !(leftInfo.isBoxed() && rightInfo.isBoxed())) { - // JLS 15.21.1 numerical equality - TypeMirror promotedType = - binaryPromotedType( - leftInfo.unboxedType(), rightInfo.unboxedType()); - left = binaryNumericPromotion(left, promotedType); - right = binaryNumericPromotion(right, promotedType); - } else if (leftInfo.isBoolean() - && rightInfo.isBoolean() - && !(leftInfo.isBoxed() && rightInfo.isBoxed())) { - // JSL 15.21.2 boolean equality - left = unboxAsNeeded(left, leftInfo.isBoxed()); - right = unboxAsNeeded(right, rightInfo.isBoxed()); - } - - Node node; - if (kind == Tree.Kind.EQUAL_TO) { - node = new EqualToNode(tree, left, right); - } else { - assert kind == Kind.NOT_EQUAL_TO; - node = new NotEqualNode(tree, left, right); - } - extendWithNode(node); - - return node; - } - - case AND: - case OR: - case XOR: - { - // see JLS 15.22 - TypeMirror leftType = InternalUtils.typeOf(leftTree); - TypeMirror rightType = InternalUtils.typeOf(rightTree); - boolean isBooleanOp = - TypesUtils.isBooleanType(leftType) - && TypesUtils.isBooleanType(rightType); - - Node left; - Node right; - - if (isBooleanOp) { - left = unbox(scan(leftTree, p)); - right = unbox(scan(rightTree, p)); - } else if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) { - TypeMirror promotedType = binaryPromotedType(leftType, rightType); - left = binaryNumericPromotion(scan(leftTree, p), promotedType); - right = binaryNumericPromotion(scan(rightTree, p), promotedType); - } else { - left = unbox(scan(leftTree, p)); - right = unbox(scan(rightTree, p)); - } - - Node node; - if (kind == Tree.Kind.AND) { - node = new BitwiseAndNode(tree, left, right); - } else if (kind == Tree.Kind.OR) { - node = new BitwiseOrNode(tree, left, right); - } else { - assert kind == Kind.XOR; - node = new BitwiseXorNode(tree, left, right); - } - - extendWithNode(node); - - return node; - } - - case CONDITIONAL_AND: - case CONDITIONAL_OR: - { - // see JLS 15.23 and 15.24 - - // all necessary labels - Label rightStartL = new Label(); - Label shortCircuitL = new Label(); - - // left-hand side - Node left = scan(leftTree, p); - - ConditionalJump cjump; - if (kind == Tree.Kind.CONDITIONAL_AND) { - cjump = new ConditionalJump(rightStartL, shortCircuitL); - cjump.setFalseFlowRule(Store.FlowRule.ELSE_TO_ELSE); - } else { - cjump = new ConditionalJump(shortCircuitL, rightStartL); - cjump.setTrueFlowRule(Store.FlowRule.THEN_TO_THEN); - } - extendWithExtendedNode(cjump); - - // right-hand side - addLabelForNextNode(rightStartL); - Node right = scan(rightTree, p); - - // conditional expression itself - addLabelForNextNode(shortCircuitL); - Node node; - if (kind == Tree.Kind.CONDITIONAL_AND) { - node = new ConditionalAndNode(tree, left, right); - } else { - node = new ConditionalOrNode(tree, left, right); - } - extendWithNode(node); - return node; - } - default: - assert false : "unexpected binary tree: " + kind; - break; - } - assert r != null : "unexpected binary tree"; - return extendWithNode(r); - } - - @Override - public Node visitBlock(BlockTree tree, Void p) { - for (StatementTree n : tree.getStatements()) { - scan(n, null); - } - return null; - } - - @Override - public Node visitBreak(BreakTree tree, Void p) { - Name label = tree.getLabel(); - if (label == null) { - assert breakTargetL != null : "no target for break statement"; - - extendWithExtendedNode(new UnconditionalJump(breakTargetL)); - } else { - assert breakLabels.containsKey(label); - - extendWithExtendedNode(new UnconditionalJump(breakLabels.get(label))); - } - - return null; - } - - @Override - public Node visitSwitch(SwitchTree tree, Void p) { - SwitchBuilder builder = new SwitchBuilder(tree, p); - builder.build(); - return null; - } - - private class SwitchBuilder { - private final SwitchTree switchTree; - private final Label[] caseBodyLabels; - private final Void p; - private Node switchExpr; - - private SwitchBuilder(SwitchTree tree, Void p) { - this.switchTree = tree; - this.caseBodyLabels = new Label[switchTree.getCases().size() + 1]; - this.p = p; - } - - public void build() { - Label oldBreakTargetL = breakTargetL; - breakTargetL = new Label(); - int cases = caseBodyLabels.length - 1; - for (int i = 0; i < cases; ++i) { - caseBodyLabels[i] = new Label(); - } - caseBodyLabels[cases] = breakTargetL; - - switchExpr = unbox(scan(switchTree.getExpression(), p)); - extendWithNode( - new MarkerNode( - switchTree, "start of switch statement", env.getTypeUtils())); - - Integer defaultIndex = null; - for (int i = 0; i < cases; ++i) { - CaseTree caseTree = switchTree.getCases().get(i); - if (caseTree.getExpression() == null) { - defaultIndex = i; - } else { - buildCase(caseTree, i); - } - } - if (defaultIndex != null) { - // the checks of all cases must happen before the default case, - // therefore we build the default case last. - // fallthrough is still handled correctly with the caseBodyLabels. - buildCase(switchTree.getCases().get(defaultIndex), defaultIndex); - } - - addLabelForNextNode(breakTargetL); - breakTargetL = oldBreakTargetL; - } - - private void buildCase(CaseTree tree, int index) { - final Label thisBodyL = caseBodyLabels[index]; - final Label nextBodyL = caseBodyLabels[index + 1]; - final Label nextCaseL = new Label(); - - ExpressionTree exprTree = tree.getExpression(); - if (exprTree != null) { - Node expr = scan(exprTree, p); - CaseNode test = new CaseNode(tree, switchExpr, expr, env.getTypeUtils()); - extendWithNode(test); - extendWithExtendedNode(new ConditionalJump(thisBodyL, nextCaseL)); - } - addLabelForNextNode(thisBodyL); - for (StatementTree stmt : tree.getStatements()) { - scan(stmt, p); - } - extendWithExtendedNode(new UnconditionalJump(nextBodyL)); - addLabelForNextNode(nextCaseL); - } - } - - @Override - public Node visitCase(CaseTree tree, Void p) { - throw new AssertionError("case visitor is implemented in SwitchBuilder"); - } - - @Override - public Node visitCatch(CatchTree tree, Void p) { - scan(tree.getParameter(), p); - scan(tree.getBlock(), p); - return null; - } - - @Override - public Node visitClass(ClassTree tree, Void p) { - declaredClasses.add(tree); - return null; - } - - @Override - public Node visitConditionalExpression(ConditionalExpressionTree tree, Void p) { - // see JLS 15.25 - TypeMirror exprType = InternalUtils.typeOf(tree); - - Label trueStart = new Label(); - Label falseStart = new Label(); - Label merge = new Label(); - - Node condition = unbox(scan(tree.getCondition(), p)); - ConditionalJump cjump = new ConditionalJump(trueStart, falseStart); - extendWithExtendedNode(cjump); - - addLabelForNextNode(trueStart); - Node trueExpr = scan(tree.getTrueExpression(), p); - trueExpr = conditionalExprPromotion(trueExpr, exprType); - extendWithExtendedNode(new UnconditionalJump(merge)); - - addLabelForNextNode(falseStart); - Node falseExpr = scan(tree.getFalseExpression(), p); - falseExpr = conditionalExprPromotion(falseExpr, exprType); - - addLabelForNextNode(merge); - Node node = new TernaryExpressionNode(tree, condition, trueExpr, falseExpr); - extendWithNode(node); - - return node; - } - - @Override - public Node visitContinue(ContinueTree tree, Void p) { - Name label = tree.getLabel(); - if (label == null) { - assert continueTargetL != null : "no target for continue statement"; - - extendWithExtendedNode(new UnconditionalJump(continueTargetL)); - } else { - assert continueLabels.containsKey(label); - - extendWithExtendedNode(new UnconditionalJump(continueLabels.get(label))); - } - - return null; - } - - @Override - public Node visitDoWhileLoop(DoWhileLoopTree tree, Void p) { - Name parentLabel = getLabel(getCurrentPath()); - - Label loopEntry = new Label(); - Label loopExit = new Label(); - - // If the loop is a labeled statement, then its continue - // target is identical for continues with no label and - // continues with the loop's label. - Label conditionStart; - if (parentLabel != null) { - conditionStart = continueLabels.get(parentLabel); - } else { - conditionStart = new Label(); - } - - Label oldBreakTargetL = breakTargetL; - breakTargetL = loopExit; - - Label oldContinueTargetL = continueTargetL; - continueTargetL = conditionStart; - - // Loop body - addLabelForNextNode(loopEntry); - if (tree.getStatement() != null) { - scan(tree.getStatement(), p); - } - - // Condition - addLabelForNextNode(conditionStart); - if (tree.getCondition() != null) { - unbox(scan(tree.getCondition(), p)); - ConditionalJump cjump = new ConditionalJump(loopEntry, loopExit); - extendWithExtendedNode(cjump); - } - - // Loop exit - addLabelForNextNode(loopExit); - - breakTargetL = oldBreakTargetL; - continueTargetL = oldContinueTargetL; - - return null; - } - - @Override - public Node visitErroneous(ErroneousTree tree, Void p) { - assert false : "ErroneousTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitExpressionStatement(ExpressionStatementTree tree, Void p) { - return scan(tree.getExpression(), p); - } - - @Override - public Node visitEnhancedForLoop(EnhancedForLoopTree tree, Void p) { - // see JLS 14.14.2 - Name parentLabel = getLabel(getCurrentPath()); - - Label conditionStart = new Label(); - Label loopEntry = new Label(); - Label loopExit = new Label(); - - // If the loop is a labeled statement, then its continue - // target is identical for continues with no label and - // continues with the loop's label. - Label updateStart; - if (parentLabel != null) { - updateStart = continueLabels.get(parentLabel); - } else { - updateStart = new Label(); - } - - Label oldBreakTargetL = breakTargetL; - breakTargetL = loopExit; - - Label oldContinueTargetL = continueTargetL; - continueTargetL = updateStart; - - // Distinguish loops over Iterables from loops over arrays. - - TypeElement iterableElement = elements.getTypeElement("java.lang.Iterable"); - TypeMirror iterableType = types.erasure(iterableElement.asType()); - - VariableTree variable = tree.getVariable(); - VariableElement variableElement = TreeUtils.elementFromDeclaration(variable); - ExpressionTree expression = tree.getExpression(); - StatementTree statement = tree.getStatement(); - - TypeMirror exprType = InternalUtils.typeOf(expression); - - if (types.isSubtype(exprType, iterableType)) { - // Take the upper bound of a type variable or wildcard - exprType = TypesUtils.upperBound(exprType); - - assert (exprType instanceof DeclaredType) : "an Iterable must be a DeclaredType"; - DeclaredType declaredExprType = (DeclaredType) exprType; - declaredExprType.getTypeArguments(); - - MemberSelectTree iteratorSelect = treeBuilder.buildIteratorMethodAccess(expression); - handleArtificialTree(iteratorSelect); - - MethodInvocationTree iteratorCall = - treeBuilder.buildMethodInvocation(iteratorSelect); - handleArtificialTree(iteratorCall); - - VariableTree iteratorVariable = - createEnhancedForLoopIteratorVariable(iteratorCall, variableElement); - handleArtificialTree(iteratorVariable); - - VariableDeclarationNode iteratorVariableDecl = - new VariableDeclarationNode(iteratorVariable); - iteratorVariableDecl.setInSource(false); - - extendWithNode(iteratorVariableDecl); - - Node expressionNode = scan(expression, p); - - MethodAccessNode iteratorAccessNode = - new MethodAccessNode(iteratorSelect, expressionNode); - iteratorAccessNode.setInSource(false); - extendWithNode(iteratorAccessNode); - MethodInvocationNode iteratorCallNode = - new MethodInvocationNode( - iteratorCall, - iteratorAccessNode, - Collections.emptyList(), - getCurrentPath()); - iteratorCallNode.setInSource(false); - extendWithNode(iteratorCallNode); - - translateAssignment( - iteratorVariable, - new LocalVariableNode(iteratorVariable), - iteratorCallNode); - - // Test the loop ending condition - addLabelForNextNode(conditionStart); - IdentifierTree iteratorUse1 = treeBuilder.buildVariableUse(iteratorVariable); - handleArtificialTree(iteratorUse1); - - LocalVariableNode iteratorReceiverNode = new LocalVariableNode(iteratorUse1); - iteratorReceiverNode.setInSource(false); - extendWithNode(iteratorReceiverNode); - - MemberSelectTree hasNextSelect = treeBuilder.buildHasNextMethodAccess(iteratorUse1); - handleArtificialTree(hasNextSelect); - - MethodAccessNode hasNextAccessNode = - new MethodAccessNode(hasNextSelect, iteratorReceiverNode); - hasNextAccessNode.setInSource(false); - extendWithNode(hasNextAccessNode); - - MethodInvocationTree hasNextCall = treeBuilder.buildMethodInvocation(hasNextSelect); - handleArtificialTree(hasNextCall); - - MethodInvocationNode hasNextCallNode = - new MethodInvocationNode( - hasNextCall, - hasNextAccessNode, - Collections.emptyList(), - getCurrentPath()); - hasNextCallNode.setInSource(false); - extendWithNode(hasNextCallNode); - extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit)); - - // Loop body, starting with declaration of the loop iteration variable - addLabelForNextNode(loopEntry); - extendWithNode(new VariableDeclarationNode(variable)); - - IdentifierTree iteratorUse2 = treeBuilder.buildVariableUse(iteratorVariable); - handleArtificialTree(iteratorUse2); - - LocalVariableNode iteratorReceiverNode2 = new LocalVariableNode(iteratorUse2); - iteratorReceiverNode2.setInSource(false); - extendWithNode(iteratorReceiverNode2); - - MemberSelectTree nextSelect = treeBuilder.buildNextMethodAccess(iteratorUse2); - handleArtificialTree(nextSelect); - - MethodAccessNode nextAccessNode = - new MethodAccessNode(nextSelect, iteratorReceiverNode2); - nextAccessNode.setInSource(false); - extendWithNode(nextAccessNode); - - MethodInvocationTree nextCall = treeBuilder.buildMethodInvocation(nextSelect); - handleArtificialTree(nextCall); - - MethodInvocationNode nextCallNode = - new MethodInvocationNode( - nextCall, - nextAccessNode, - Collections.emptyList(), - getCurrentPath()); - nextCallNode.setInSource(false); - extendWithNode(nextCallNode); - - translateAssignment(variable, new LocalVariableNode(variable), nextCall); - - if (statement != null) { - scan(statement, p); - } - - // Loop back edge - addLabelForNextNode(updateStart); - extendWithExtendedNode(new UnconditionalJump(conditionStart)); - - } else { - // TODO: Shift any labels after the initialization of the - // temporary array variable. - - VariableTree arrayVariable = - createEnhancedForLoopArrayVariable(expression, variableElement); - handleArtificialTree(arrayVariable); - - VariableDeclarationNode arrayVariableNode = - new VariableDeclarationNode(arrayVariable); - arrayVariableNode.setInSource(false); - extendWithNode(arrayVariableNode); - Node expressionNode = scan(expression, p); - - translateAssignment( - arrayVariable, new LocalVariableNode(arrayVariable), expressionNode); - - // Declare and initialize the loop index variable - TypeMirror intType = types.getPrimitiveType(TypeKind.INT); - - LiteralTree zero = treeBuilder.buildLiteral(Integer.valueOf(0)); - handleArtificialTree(zero); - - VariableTree indexVariable = - treeBuilder.buildVariableDecl( - intType, - uniqueName("index"), - variableElement.getEnclosingElement(), - zero); - handleArtificialTree(indexVariable); - VariableDeclarationNode indexVariableNode = - new VariableDeclarationNode(indexVariable); - indexVariableNode.setInSource(false); - extendWithNode(indexVariableNode); - IntegerLiteralNode zeroNode = extendWithNode(new IntegerLiteralNode(zero)); - - translateAssignment(indexVariable, new LocalVariableNode(indexVariable), zeroNode); - - // Compare index to array length - addLabelForNextNode(conditionStart); - IdentifierTree indexUse1 = treeBuilder.buildVariableUse(indexVariable); - handleArtificialTree(indexUse1); - LocalVariableNode indexNode1 = new LocalVariableNode(indexUse1); - indexNode1.setInSource(false); - extendWithNode(indexNode1); - - IdentifierTree arrayUse1 = treeBuilder.buildVariableUse(arrayVariable); - handleArtificialTree(arrayUse1); - LocalVariableNode arrayNode1 = extendWithNode(new LocalVariableNode(arrayUse1)); - - MemberSelectTree lengthSelect = treeBuilder.buildArrayLengthAccess(arrayUse1); - handleArtificialTree(lengthSelect); - FieldAccessNode lengthAccessNode = new FieldAccessNode(lengthSelect, arrayNode1); - lengthAccessNode.setInSource(false); - extendWithNode(lengthAccessNode); - - BinaryTree lessThan = treeBuilder.buildLessThan(indexUse1, lengthSelect); - handleArtificialTree(lessThan); - - LessThanNode lessThanNode = - new LessThanNode(lessThan, indexNode1, lengthAccessNode); - lessThanNode.setInSource(false); - extendWithNode(lessThanNode); - extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit)); - - // Loop body, starting with declaration of the loop iteration variable - addLabelForNextNode(loopEntry); - extendWithNode(new VariableDeclarationNode(variable)); - - IdentifierTree arrayUse2 = treeBuilder.buildVariableUse(arrayVariable); - handleArtificialTree(arrayUse2); - LocalVariableNode arrayNode2 = new LocalVariableNode(arrayUse2); - arrayNode2.setInSource(false); - extendWithNode(arrayNode2); - - IdentifierTree indexUse2 = treeBuilder.buildVariableUse(indexVariable); - handleArtificialTree(indexUse2); - LocalVariableNode indexNode2 = new LocalVariableNode(indexUse2); - indexNode2.setInSource(false); - extendWithNode(indexNode2); - - ArrayAccessTree arrayAccess = treeBuilder.buildArrayAccess(arrayUse2, indexUse2); - handleArtificialTree(arrayAccess); - ArrayAccessNode arrayAccessNode = - new ArrayAccessNode(arrayAccess, arrayNode2, indexNode2); - arrayAccessNode.setInSource(false); - extendWithNode(arrayAccessNode); - translateAssignment(variable, new LocalVariableNode(variable), arrayAccessNode); - - if (statement != null) { - scan(statement, p); - } - - // Loop back edge - addLabelForNextNode(updateStart); - - IdentifierTree indexUse3 = treeBuilder.buildVariableUse(indexVariable); - handleArtificialTree(indexUse3); - LocalVariableNode indexNode3 = new LocalVariableNode(indexUse3); - indexNode3.setInSource(false); - extendWithNode(indexNode3); - - LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1)); - handleArtificialTree(oneTree); - Node one = new IntegerLiteralNode(oneTree); - one.setInSource(false); - extendWithNode(one); - - BinaryTree addOneTree = - treeBuilder.buildBinary(intType, Tree.Kind.PLUS, indexUse3, oneTree); - handleArtificialTree(addOneTree); - Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one); - addOneNode.setInSource(false); - extendWithNode(addOneNode); - - AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree); - handleArtificialTree(assignTree); - Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode); - assignNode.setInSource(false); - extendWithNode(assignNode); - - extendWithExtendedNode(new UnconditionalJump(conditionStart)); - } - - // Loop exit - addLabelForNextNode(loopExit); - - breakTargetL = oldBreakTargetL; - continueTargetL = oldContinueTargetL; - - return null; - } - - protected VariableTree createEnhancedForLoopIteratorVariable( - MethodInvocationTree iteratorCall, VariableElement variableElement) { - TypeMirror iteratorType = InternalUtils.typeOf(iteratorCall); - - // Declare and initialize a new, unique iterator variable - VariableTree iteratorVariable = - treeBuilder.buildVariableDecl( - iteratorType, // annotatedIteratorTypeTree, - uniqueName("iter"), - variableElement.getEnclosingElement(), - iteratorCall); - return iteratorVariable; - } - - protected VariableTree createEnhancedForLoopArrayVariable( - ExpressionTree expression, VariableElement variableElement) { - TypeMirror arrayType = InternalUtils.typeOf(expression); - - // Declare and initialize a temporary array variable - VariableTree arrayVariable = - treeBuilder.buildVariableDecl( - arrayType, - uniqueName("array"), - variableElement.getEnclosingElement(), - expression); - return arrayVariable; - } - - @Override - public Node visitForLoop(ForLoopTree tree, Void p) { - Name parentLabel = getLabel(getCurrentPath()); - - Label conditionStart = new Label(); - Label loopEntry = new Label(); - Label loopExit = new Label(); - - // If the loop is a labeled statement, then its continue - // target is identical for continues with no label and - // continues with the loop's label. - Label updateStart; - if (parentLabel != null) { - updateStart = continueLabels.get(parentLabel); - } else { - updateStart = new Label(); - } - - Label oldBreakTargetL = breakTargetL; - breakTargetL = loopExit; - - Label oldContinueTargetL = continueTargetL; - continueTargetL = updateStart; - - // Initializer - for (StatementTree init : tree.getInitializer()) { - scan(init, p); - } - - // Condition - addLabelForNextNode(conditionStart); - if (tree.getCondition() != null) { - unbox(scan(tree.getCondition(), p)); - ConditionalJump cjump = new ConditionalJump(loopEntry, loopExit); - extendWithExtendedNode(cjump); - } - - // Loop body - addLabelForNextNode(loopEntry); - if (tree.getStatement() != null) { - scan(tree.getStatement(), p); - } - - // Update - addLabelForNextNode(updateStart); - for (ExpressionStatementTree update : tree.getUpdate()) { - scan(update, p); - } - - extendWithExtendedNode(new UnconditionalJump(conditionStart)); - - // Loop exit - addLabelForNextNode(loopExit); - - breakTargetL = oldBreakTargetL; - continueTargetL = oldContinueTargetL; - - return null; - } - - @Override - public Node visitIdentifier(IdentifierTree tree, Void p) { - Node node; - if (TreeUtils.isFieldAccess(tree)) { - Node receiver = getReceiver(tree, TreeUtils.enclosingClass(getCurrentPath())); - node = new FieldAccessNode(tree, receiver); - } else { - Element element = TreeUtils.elementFromUse(tree); - switch (element.getKind()) { - case ANNOTATION_TYPE: - case CLASS: - case ENUM: - case INTERFACE: - case TYPE_PARAMETER: - node = new ClassNameNode(tree); - break; - case FIELD: - // Note that "this"/"super" is a field, but not a field access. - if (element.getSimpleName().contentEquals("this")) { - node = new ExplicitThisLiteralNode(tree); - } else { - node = new SuperNode(tree); - } - break; - case EXCEPTION_PARAMETER: - case LOCAL_VARIABLE: - case RESOURCE_VARIABLE: - case PARAMETER: - node = new LocalVariableNode(tree); - break; - case PACKAGE: - node = new PackageNameNode(tree); - break; - default: - throw new IllegalArgumentException( - "unexpected element kind : " + element.getKind()); - } - } - extendWithNode(node); - return node; - } - - @Override - public Node visitIf(IfTree tree, Void p) { - // all necessary labels - Label thenEntry = new Label(); - Label elseEntry = new Label(); - Label endIf = new Label(); - - // basic block for the condition - unbox(scan(tree.getCondition(), p)); - - ConditionalJump cjump = new ConditionalJump(thenEntry, elseEntry); - extendWithExtendedNode(cjump); - - // then branch - addLabelForNextNode(thenEntry); - StatementTree thenStatement = tree.getThenStatement(); - scan(thenStatement, p); - extendWithExtendedNode(new UnconditionalJump(endIf)); - - // else branch - addLabelForNextNode(elseEntry); - StatementTree elseStatement = tree.getElseStatement(); - if (elseStatement != null) { - scan(elseStatement, p); - } - - // label the end of the if statement - addLabelForNextNode(endIf); - - return null; - } - - @Override - public Node visitImport(ImportTree tree, Void p) { - assert false : "ImportTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitArrayAccess(ArrayAccessTree tree, Void p) { - Node array = scan(tree.getExpression(), p); - Node index = unaryNumericPromotion(scan(tree.getIndex(), p)); - return extendWithNode(new ArrayAccessNode(tree, array, index)); - } - - @Override - public Node visitLabeledStatement(LabeledStatementTree tree, Void p) { - // This method can set the break target after generating all Nodes - // in the contained statement, but it can't set the continue target, - // which may be in the middle of a sequence of nodes. Labeled loops - // must look up and use the continue Labels. - Name labelName = tree.getLabel(); - - Label breakL = new Label(labelName + "_break"); - Label continueL = new Label(labelName + "_continue"); - - breakLabels.put(labelName, breakL); - continueLabels.put(labelName, continueL); - - scan(tree.getStatement(), p); - - addLabelForNextNode(breakL); - - breakLabels.remove(labelName); - continueLabels.remove(labelName); - - return null; - } - - @Override - public Node visitLiteral(LiteralTree tree, Void p) { - Node r = null; - switch (tree.getKind()) { - case BOOLEAN_LITERAL: - r = new BooleanLiteralNode(tree); - break; - case CHAR_LITERAL: - r = new CharacterLiteralNode(tree); - break; - case DOUBLE_LITERAL: - r = new DoubleLiteralNode(tree); - break; - case FLOAT_LITERAL: - r = new FloatLiteralNode(tree); - break; - case INT_LITERAL: - r = new IntegerLiteralNode(tree); - break; - case LONG_LITERAL: - r = new LongLiteralNode(tree); - break; - case NULL_LITERAL: - r = new NullLiteralNode(tree); - break; - case STRING_LITERAL: - r = new StringLiteralNode(tree); - break; - default: - assert false : "unexpected literal tree"; - break; - } - assert r != null : "unexpected literal tree"; - Node result = extendWithNode(r); - return result; - } - - @Override - public Node visitMethod(MethodTree tree, Void p) { - assert false : "MethodTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitModifiers(ModifiersTree tree, Void p) { - assert false : "ModifiersTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitNewArray(NewArrayTree tree, Void p) { - // see JLS 15.10 - - ArrayType type = (ArrayType) InternalUtils.typeOf(tree); - TypeMirror elemType = type.getComponentType(); - - List dimensions = tree.getDimensions(); - List initializers = tree.getInitializers(); - - List dimensionNodes = new ArrayList(); - if (dimensions != null) { - for (ExpressionTree dim : dimensions) { - dimensionNodes.add(unaryNumericPromotion(scan(dim, p))); - } - } - - List initializerNodes = new ArrayList(); - if (initializers != null) { - for (ExpressionTree init : initializers) { - initializerNodes.add(assignConvert(scan(init, p), elemType)); - } - } - - Node node = new ArrayCreationNode(tree, type, dimensionNodes, initializerNodes); - return extendWithNode(node); - } - - @Override - public Node visitNewClass(NewClassTree tree, Void p) { - // see JLS 15.9 - - Tree enclosingExpr = tree.getEnclosingExpression(); - if (enclosingExpr != null) { - scan(enclosingExpr, p); - } - - // We ignore any class body because its methods should - // be visited separately. - // TODO: For anonymous classes we want to propagate the current store - // to the anonymous class. - // See Issues 266, 811. - - // Convert constructor arguments - ExecutableElement constructor = TreeUtils.elementFromUse(tree); - - List actualExprs = tree.getArguments(); - - List arguments = convertCallArguments(constructor, actualExprs); - - // TODO: for anonymous classes, don't use the identifier alone. - // See Issue 890. - Node constructorNode = scan(tree.getIdentifier(), p); - - Node node = new ObjectCreationNode(tree, constructorNode, arguments); - - Set thrownSet = new HashSet<>(); - // Add exceptions explicitly mentioned in the throws clause. - List thrownTypes = constructor.getThrownTypes(); - thrownSet.addAll(thrownTypes); - // Add Throwable to account for unchecked exceptions - TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable"); - thrownSet.add(throwableElement.asType()); - - extendWithNodeWithExceptions(node, thrownSet); - - return node; - } - - /** - * Maps a {@code Tree} its directly enclosing {@code ParenthesizedTree} if one exists. - * - *

An invocation {@code visualize(cfg, entry, null);} does not output stores at the beginning - * of basic blocks. - * - * @param cfg the CFG to visualize - * @param entry the entry node of the control flow graph to be represented - * @param analysis an analysis containing information about the program represented by the CFG. - * The information includes {@link Store}s that are valid at the beginning of basic blocks - * reachable from {@code entry} and per-node information for value producing {@link Node}s. - * Can also be {@code null} to indicate that this information should not be output. - * @return possible analysis results, e.g. generated file names. - */ - /*@Nullable*/ Map visualize( - ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis analysis); - - /** - * Delegate the visualization responsibility to the passed {@link Store} instance, which will - * call back to this visualizer instance for sub-components. - * - * @param store the store to visualize - */ - void visualizeStore(S store); - - /** - * Called by a {@code CFAbstractStore} to visualize the class name before calling the {@code - * CFAbstractStore#internalVisualize()} method. - * - * @param classCanonicalName the canonical name of the class - */ - void visualizeStoreHeader(String classCanonicalName); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize a local variable. - * - * @param localVar the local variable - * @param value the value of the local variable - */ - void visualizeStoreLocalVar(FlowExpressions.LocalVariable localVar, A value); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of the current - * object {@code this} in this Store. - * - * @param value the value of the current object this - */ - void visualizeStoreThisVal(A value); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of fields - * collected by this Store. - * - * @param fieldAccess the field - * @param value the value of the field - */ - void visualizeStoreFieldVals(FlowExpressions.FieldAccess fieldAccess, A value); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of arrays - * collected by this Store. - * - * @param arrayValue the array - * @param value the value of the array - */ - void visualizeStoreArrayVal(FlowExpressions.ArrayAccess arrayValue, A value); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of pure method - * calls collected by this Store. - * - * @param methodCall the pure method call - * @param value the value of the pure method call - */ - void visualizeStoreMethodVals(FlowExpressions.MethodCall methodCall, A value); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of class names - * collected by this Store. - * - * @param className the class name - * @param value the value of the class name - */ - void visualizeStoreClassVals(FlowExpressions.ClassName className, A value); - - /** - * Called by {@code CFAbstractStore#internalVisualize()} to visualize the specific information - * collected according to the specific kind of Store. Currently, these Stores call this method: - * {@code LockStore}, {@code NullnessStore}, and {@code InitializationStore} to visualize - * additional information. - * - * @param keyName the name of the specific information to be visualized - * @param value the value of the specific information to be visualized - */ - void visualizeStoreKeyVal(String keyName, Object value); - - /** - * Called by {@code CFAbstractStore} to visualize any information after the invocation of {@code - * CFAbstractStore#internalVisualize()}. - */ - void visualizeStoreFooter(); - - /** - * Visualize a block based on the analysis. - * - * @param bb the block - * @param analysis the current analysis - */ - void visualizeBlock(Block bb, /*@Nullable*/ Analysis analysis); - - /** - * Visualize a SpecialBlock. - * - * @param sbb the special block - */ - void visualizeSpecialBlock(SpecialBlock sbb); - - /** - * Visualize the transferInput of a Block based on the analysis. - * - * @param bb the block - * @param analysis the current analysis - */ - void visualizeBlockTransferInput(Block bb, Analysis analysis); - - /** - * Visualize a Node based on the analysis. - * - * @param t the node - * @param analysis the current analysis - */ - void visualizeBlockNode(Node t, /*@Nullable*/ Analysis analysis); - - /** Shutdown method called once from the shutdown hook of the {@code BaseTypeChecker}. */ - void shutdown(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java deleted file mode 100644 index 0a2687aec29c59..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java +++ /dev/null @@ -1,246 +0,0 @@ -package org.checkerframework.dataflow.cfg; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.Tree; -import java.util.Collections; -import java.util.Deque; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import org.checkerframework.dataflow.cfg.block.Block; -import org.checkerframework.dataflow.cfg.block.Block.BlockType; -import org.checkerframework.dataflow.cfg.block.ConditionalBlock; -import org.checkerframework.dataflow.cfg.block.ExceptionBlock; -import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock; -import org.checkerframework.dataflow.cfg.block.SpecialBlock; -import org.checkerframework.dataflow.cfg.block.SpecialBlockImpl; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.ReturnNode; - -/** - * A control flow graph (CFG for short) of a single method. - * - * @author Stefan Heule - */ -public class ControlFlowGraph { - - /** The entry block of the control flow graph. */ - protected final SpecialBlock entryBlock; - - /** The regular exit block of the control flow graph. */ - protected final SpecialBlock regularExitBlock; - - /** The exceptional exit block of the control flow graph. */ - protected final SpecialBlock exceptionalExitBlock; - - /** The AST this CFG corresponds to. */ - protected UnderlyingAST underlyingAST; - - /** - * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces a value will have at - * least one corresponding Node. Trees that undergo conversions, such as boxing or unboxing, can - * map to two distinct Nodes. The Node for the pre-conversion value is stored in treeLookup, - * while the Node for the post-conversion value is stored in convertedTreeLookup. - */ - protected IdentityHashMap treeLookup; - - /** Map from AST {@link Tree}s to post-conversion {@link Node}s. */ - protected IdentityHashMap convertedTreeLookup; - - /** - * All return nodes (if any) encountered. Only includes return statements that actually return - * something - */ - protected final List returnNodes; - - public ControlFlowGraph( - SpecialBlock entryBlock, - SpecialBlockImpl regularExitBlock, - SpecialBlockImpl exceptionalExitBlock, - UnderlyingAST underlyingAST, - IdentityHashMap treeLookup, - IdentityHashMap convertedTreeLookup, - List returnNodes) { - super(); - this.entryBlock = entryBlock; - this.underlyingAST = underlyingAST; - this.treeLookup = treeLookup; - this.convertedTreeLookup = convertedTreeLookup; - this.regularExitBlock = regularExitBlock; - this.exceptionalExitBlock = exceptionalExitBlock; - this.returnNodes = returnNodes; - } - - /** @return the {@link Node} to which the {@link Tree} {@code t} corresponds. */ - public Node getNodeCorrespondingToTree(Tree t) { - if (convertedTreeLookup.containsKey(t)) { - return convertedTreeLookup.get(t); - } else { - return treeLookup.get(t); - } - } - - /** @return the entry block of the control flow graph. */ - public SpecialBlock getEntryBlock() { - return entryBlock; - } - - public List getReturnNodes() { - return returnNodes; - } - - public SpecialBlock getRegularExitBlock() { - return regularExitBlock; - } - - public SpecialBlock getExceptionalExitBlock() { - return exceptionalExitBlock; - } - - /** @return the AST this CFG corresponds to. */ - public UnderlyingAST getUnderlyingAST() { - return underlyingAST; - } - - /** @return the set of all basic block in this control flow graph */ - public Set getAllBlocks() { - Set visited = new HashSet<>(); - Queue worklist = new LinkedList<>(); - Block cur = entryBlock; - visited.add(entryBlock); - - // traverse the whole control flow graph - while (true) { - if (cur == null) { - break; - } - - Queue succs = new LinkedList<>(); - if (cur.getType() == BlockType.CONDITIONAL_BLOCK) { - ConditionalBlock ccur = ((ConditionalBlock) cur); - succs.add(ccur.getThenSuccessor()); - succs.add(ccur.getElseSuccessor()); - } else { - assert cur instanceof SingleSuccessorBlock; - Block b = ((SingleSuccessorBlock) cur).getSuccessor(); - if (b != null) { - succs.add(b); - } - } - - if (cur.getType() == BlockType.EXCEPTION_BLOCK) { - ExceptionBlock ecur = (ExceptionBlock) cur; - for (Set exceptionSuccSet : ecur.getExceptionalSuccessors().values()) { - succs.addAll(exceptionSuccSet); - } - } - - for (Block b : succs) { - if (!visited.contains(b)) { - visited.add(b); - worklist.add(b); - } - } - - cur = worklist.poll(); - } - - return visited; - } - - /** - * @return the list of all basic block in this control flow graph in reversed depth-first - * postorder sequence. - *

Blocks may appear more than once in the sequence. - */ - public List getDepthFirstOrderedBlocks() { - List dfsOrderResult = new LinkedList<>(); - Set visited = new HashSet<>(); - Deque worklist = new LinkedList<>(); - worklist.add(entryBlock); - while (!worklist.isEmpty()) { - Block cur = worklist.getLast(); - if (visited.contains(cur)) { - dfsOrderResult.add(cur); - worklist.removeLast(); - } else { - visited.add(cur); - Deque successors = getSuccessors(cur); - successors.removeAll(visited); - worklist.addAll(successors); - } - } - - Collections.reverse(dfsOrderResult); - return dfsOrderResult; - } - - /** - * Get a list of all successor Blocks for cur - * - * @return a Deque of successor Blocks - */ - private Deque getSuccessors(Block cur) { - Deque succs = new LinkedList<>(); - if (cur.getType() == BlockType.CONDITIONAL_BLOCK) { - ConditionalBlock ccur = ((ConditionalBlock) cur); - succs.add(ccur.getThenSuccessor()); - succs.add(ccur.getElseSuccessor()); - } else { - assert cur instanceof SingleSuccessorBlock; - Block b = ((SingleSuccessorBlock) cur).getSuccessor(); - if (b != null) { - succs.add(b); - } - } - - if (cur.getType() == BlockType.EXCEPTION_BLOCK) { - ExceptionBlock ecur = (ExceptionBlock) cur; - for (Set exceptionSuccSet : ecur.getExceptionalSuccessors().values()) { - succs.addAll(exceptionSuccSet); - } - } - return succs; - } - - /** @return the tree-lookup map */ - public IdentityHashMap getTreeLookup() { - return new IdentityHashMap<>(treeLookup); - } - - /** - * Get the {@link MethodTree} of the CFG if the argument {@link Tree} maps to a {@link Node} in - * the CFG or null otherwise. - */ - public /*@Nullable*/ MethodTree getContainingMethod(Tree t) { - if (treeLookup.containsKey(t)) { - if (underlyingAST.getKind() == UnderlyingAST.Kind.METHOD) { - UnderlyingAST.CFGMethod cfgMethod = (UnderlyingAST.CFGMethod) underlyingAST; - return cfgMethod.getMethod(); - } - } - return null; - } - - /** - * Get the {@link ClassTree} of the CFG if the argument {@link Tree} maps to a {@link Node} in - * the CFG or null otherwise. - */ - public /*@Nullable*/ ClassTree getContainingClass(Tree t) { - if (treeLookup.containsKey(t)) { - if (underlyingAST.getKind() == UnderlyingAST.Kind.METHOD) { - UnderlyingAST.CFGMethod cfgMethod = (UnderlyingAST.CFGMethod) underlyingAST; - return cfgMethod.getClassTree(); - } - } - return null; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java deleted file mode 100644 index 1eb1cb87a2fb0c..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java +++ /dev/null @@ -1,511 +0,0 @@ -package org.checkerframework.dataflow.cfg; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.tools.javac.tree.JCTree; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.Set; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.analysis.AbstractValue; -import org.checkerframework.dataflow.analysis.Analysis; -import org.checkerframework.dataflow.analysis.FlowExpressions; -import org.checkerframework.dataflow.analysis.Store; -import org.checkerframework.dataflow.analysis.TransferFunction; -import org.checkerframework.dataflow.analysis.TransferInput; -import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod; -import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement; -import org.checkerframework.dataflow.cfg.block.Block; -import org.checkerframework.dataflow.cfg.block.Block.BlockType; -import org.checkerframework.dataflow.cfg.block.ConditionalBlock; -import org.checkerframework.dataflow.cfg.block.ExceptionBlock; -import org.checkerframework.dataflow.cfg.block.RegularBlock; -import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock; -import org.checkerframework.dataflow.cfg.block.SpecialBlock; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.javacutil.ErrorReporter; - -/** - * Generate a graph description in the DOT language of a control graph. - * - * @author Stefan Heule - */ -public class DOTCFGVisualizer< - A extends AbstractValue, S extends Store, T extends TransferFunction> - implements CFGVisualizer { - - protected String outdir; - protected boolean verbose; - protected String checkerName; - - protected StringBuilder sbDigraph; - protected StringBuilder sbStore; - protected StringBuilder sbBlock; - - /** Mapping from class/method representation to generated dot file. */ - protected Map generated; - - @Override - public void init(Map args) { - this.outdir = (String) args.get("outdir"); - { - Object verb = args.get("verbose"); - this.verbose = - verb == null - ? false - : verb instanceof String - ? Boolean.getBoolean((String) verb) - : (boolean) verb; - } - this.checkerName = (String) args.get("checkerName"); - - this.generated = new HashMap<>(); - - this.sbDigraph = new StringBuilder(); - - this.sbStore = new StringBuilder(); - - this.sbBlock = new StringBuilder(); - } - - /** {@inheritDoc} */ - @Override - public /*@Nullable*/ Map visualize( - ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis analysis) { - - String dotgraph = generateDotGraph(cfg, entry, analysis); - - String dotfilename = dotOutputFileName(cfg.underlyingAST); - // System.err.println("Output to DOT file: " + dotfilename); - - try { - FileWriter fstream = new FileWriter(dotfilename); - BufferedWriter out = new BufferedWriter(fstream); - out.write(dotgraph); - out.close(); - } catch (IOException e) { - ErrorReporter.errorAbort( - "Error creating dot file: " + dotfilename + "; ensure the path is valid", e); - } - - Map res = new HashMap<>(); - res.put("dotFileName", dotfilename); - - return res; - } - - /** Generate the dot representation as String. */ - protected String generateDotGraph( - ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis analysis) { - this.sbDigraph.setLength(0); - Set visited = new HashSet<>(); - - // header - this.sbDigraph.append("digraph {\n"); - - Block cur = entry; - Queue worklist = new LinkedList<>(); - visited.add(entry); - // traverse control flow graph and define all arrows - while (true) { - if (cur == null) { - break; - } - - if (cur.getType() == BlockType.CONDITIONAL_BLOCK) { - ConditionalBlock ccur = ((ConditionalBlock) cur); - Block thenSuccessor = ccur.getThenSuccessor(); - addDotEdge(ccur.getId(), thenSuccessor.getId(), "then\\n" + ccur.getThenFlowRule()); - if (!visited.contains(thenSuccessor)) { - visited.add(thenSuccessor); - worklist.add(thenSuccessor); - } - Block elseSuccessor = ccur.getElseSuccessor(); - addDotEdge(ccur.getId(), elseSuccessor.getId(), "else\\n" + ccur.getElseFlowRule()); - if (!visited.contains(elseSuccessor)) { - visited.add(elseSuccessor); - worklist.add(elseSuccessor); - } - } else { - assert cur instanceof SingleSuccessorBlock; - Block b = ((SingleSuccessorBlock) cur).getSuccessor(); - if (b != null) { - addDotEdge( - cur.getId(), - b.getId(), - ((SingleSuccessorBlock) cur).getFlowRule().name()); - if (!visited.contains(b)) { - visited.add(b); - worklist.add(b); - } - } - } - - // exceptional edges - if (cur.getType() == BlockType.EXCEPTION_BLOCK) { - ExceptionBlock ecur = (ExceptionBlock) cur; - for (Entry> e : ecur.getExceptionalSuccessors().entrySet()) { - Set blocks = e.getValue(); - TypeMirror cause = e.getKey(); - String exception = cause.toString(); - if (exception.startsWith("java.lang.")) { - exception = exception.replace("java.lang.", ""); - } - - for (Block b : blocks) { - addDotEdge(cur.getId(), b.getId(), exception); - if (!visited.contains(b)) { - visited.add(b); - worklist.add(b); - } - } - } - } - - cur = worklist.poll(); - } - - generateDotNodes(visited, cfg, analysis); - - // footer - this.sbDigraph.append("}\n"); - - return this.sbDigraph.toString(); - } - - protected void generateDotNodes( - Set visited, ControlFlowGraph cfg, /*@Nullable*/ Analysis analysis) { - IdentityHashMap> processOrder = getProcessOrder(cfg); - this.sbDigraph.append(" node [shape=rectangle];\n\n"); - // definition of all nodes including their labels - for (Block v : visited) { - this.sbDigraph.append(" " + v.getId() + " ["); - if (v.getType() == BlockType.CONDITIONAL_BLOCK) { - this.sbDigraph.append("shape=polygon sides=8 "); - } else if (v.getType() == BlockType.SPECIAL_BLOCK) { - this.sbDigraph.append("shape=oval "); - } - this.sbDigraph.append("label=\""); - if (verbose) { - this.sbDigraph.append( - "Process order: " - + processOrder.get(v).toString().replaceAll("[\\[\\]]", "") - + "\\n"); - } - visualizeBlock(v, analysis); - } - - this.sbDigraph.append("\n"); - } - - /** @return the file name used for DOT output. */ - protected String dotOutputFileName(UnderlyingAST ast) { - StringBuilder srcloc = new StringBuilder(); - - StringBuilder outfile = new StringBuilder(outdir); - outfile.append('/'); - if (ast.getKind() == UnderlyingAST.Kind.ARBITRARY_CODE) { - CFGStatement cfgs = (CFGStatement) ast; - String clsname = cfgs.getClassTree().getSimpleName().toString(); - outfile.append(clsname); - outfile.append("-initializer-"); - outfile.append(ast.hashCode()); - - srcloc.append('<'); - srcloc.append(clsname); - srcloc.append("::initializer::"); - srcloc.append(((JCTree) cfgs.getCode()).pos); - srcloc.append('>'); - } else if (ast.getKind() == UnderlyingAST.Kind.METHOD) { - CFGMethod cfgm = (CFGMethod) ast; - String clsname = cfgm.getClassTree().getSimpleName().toString(); - String methname = cfgm.getMethod().getName().toString(); - outfile.append(clsname); - outfile.append('-'); - outfile.append(methname); - - srcloc.append('<'); - srcloc.append(clsname); - srcloc.append("::"); - srcloc.append(methname); - srcloc.append('('); - srcloc.append(cfgm.getMethod().getParameters()); - srcloc.append(")::"); - srcloc.append(((JCTree) cfgm.getMethod()).pos); - srcloc.append('>'); - } else { - ErrorReporter.errorAbort( - "Unexpected AST kind: " + ast.getKind() + " value: " + ast.toString()); - return null; - } - outfile.append('-'); - outfile.append(checkerName); - outfile.append(".dot"); - - // make path safe for Windows - String out = outfile.toString().replace("<", "_").replace(">", ""); - - generated.put(srcloc.toString(), out); - - return out; - } - - protected IdentityHashMap> getProcessOrder(ControlFlowGraph cfg) { - IdentityHashMap> depthFirstOrder = new IdentityHashMap<>(); - int count = 1; - for (Block b : cfg.getDepthFirstOrderedBlocks()) { - if (depthFirstOrder.get(b) == null) { - depthFirstOrder.put(b, new ArrayList()); - } - depthFirstOrder.get(b).add(count++); - } - return depthFirstOrder; - } - - /** - * Produce a representation of the contests of a basic block. - * - * @param bb basic block to visualize - */ - @Override - public void visualizeBlock(Block bb, /*@Nullable*/ Analysis analysis) { - - this.sbBlock.setLength(0); - - // loop over contents - List contents = new LinkedList<>(); - switch (bb.getType()) { - case REGULAR_BLOCK: - contents.addAll(((RegularBlock) bb).getContents()); - break; - case EXCEPTION_BLOCK: - contents.add(((ExceptionBlock) bb).getNode()); - break; - case CONDITIONAL_BLOCK: - break; - case SPECIAL_BLOCK: - break; - default: - assert false : "All types of basic blocks covered"; - } - boolean notFirst = false; - for (Node t : contents) { - if (notFirst) { - this.sbBlock.append("\\n"); - } - notFirst = true; - visualizeBlockNode(t, analysis); - } - - // handle case where no contents are present - boolean centered = false; - if (this.sbBlock.length() == 0) { - centered = true; - if (bb.getType() == BlockType.SPECIAL_BLOCK) { - visualizeSpecialBlock((SpecialBlock) bb); - } else if (bb.getType() == BlockType.CONDITIONAL_BLOCK) { - this.sbDigraph.append(" \",];\n"); - return; - } else { - this.sbDigraph.append("?? empty ?? \",];\n"); - return; - } - } - - // visualize transfer input if necessary - if (analysis != null) { - visualizeBlockTransferInput(bb, analysis); - } - - this.sbDigraph.append( - (this.sbBlock.toString() + (centered ? "" : "\\n")).replace("\\n", "\\l") - + " \",];\n"); - } - - @Override - public void visualizeSpecialBlock(SpecialBlock sbb) { - switch (sbb.getSpecialType()) { - case ENTRY: - this.sbBlock.append(""); - break; - case EXIT: - this.sbBlock.append(""); - break; - case EXCEPTIONAL_EXIT: - this.sbBlock.append(""); - break; - } - } - - @Override - public void visualizeBlockTransferInput(Block bb, Analysis analysis) { - assert analysis != null - : "analysis should be non-null when visualizing the transfer input of a block."; - - TransferInput input = analysis.getInput(bb); - this.sbStore.setLength(0); - - // split input representation to two lines - this.sbStore.append("Before:"); - S thenStore = input.getThenStore(); - if (!input.containsTwoStores()) { - S regularStore = input.getRegularStore(); - this.sbStore.append('['); - visualizeStore(regularStore); - this.sbStore.append(']'); - } else { - S elseStore = input.getElseStore(); - this.sbStore.append("[then="); - visualizeStore(thenStore); - this.sbStore.append(", else="); - visualizeStore(elseStore); - this.sbStore.append("]"); - } - // separator - this.sbStore.append("\\n~~~~~~~~~\\n"); - - // the transfer input before this block is added before the block content - this.sbBlock.insert(0, this.sbStore); - - if (verbose) { - Node lastNode; - switch (bb.getType()) { - case REGULAR_BLOCK: - List blockContents = ((RegularBlock) bb).getContents(); - lastNode = blockContents.get(blockContents.size() - 1); - break; - case EXCEPTION_BLOCK: - lastNode = ((ExceptionBlock) bb).getNode(); - break; - default: - lastNode = null; - } - if (lastNode != null) { - this.sbStore.setLength(0); - this.sbStore.append("\\n~~~~~~~~~\\n"); - this.sbStore.append("After:"); - visualizeStore(analysis.getResult().getStoreAfter(lastNode)); - this.sbBlock.append(this.sbStore); - } - } - } - - @Override - public void visualizeBlockNode(Node t, /*@Nullable*/ Analysis analysis) { - this.sbBlock.append(prepareString(t.toString()) + " [ " + prepareNodeType(t) + " ]"); - if (analysis != null) { - A value = analysis.getValue(t); - if (value != null) { - this.sbBlock.append(" > " + prepareString(value.toString())); - } - } - } - - protected String prepareNodeType(Node t) { - String name = t.getClass().getSimpleName(); - return name.replace("Node", ""); - } - - protected String prepareString(String s) { - return s.replace("\"", "\\\""); - } - - protected void addDotEdge(long sId, long eId, String labelContent) { - this.sbDigraph.append(" " + sId + " -> " + eId + " [label=\"" + labelContent + "\"];\n"); - } - - @Override - public void visualizeStore(S store) { - store.visualize(this); - } - - @Override - public void visualizeStoreThisVal(A value) { - this.sbStore.append(" this > " + value + "\\n"); - } - - @Override - public void visualizeStoreLocalVar(FlowExpressions.LocalVariable localVar, A value) { - this.sbStore.append(" " + localVar + " > " + toStringEscapeDoubleQuotes(value) + "\\n"); - } - - @Override - public void visualizeStoreFieldVals(FlowExpressions.FieldAccess fieldAccess, A value) { - this.sbStore.append(" " + fieldAccess + " > " + toStringEscapeDoubleQuotes(value) + "\\n"); - } - - @Override - public void visualizeStoreArrayVal(FlowExpressions.ArrayAccess arrayValue, A value) { - this.sbStore.append(" " + arrayValue + " > " + toStringEscapeDoubleQuotes(value) + "\\n"); - } - - @Override - public void visualizeStoreMethodVals(FlowExpressions.MethodCall methodCall, A value) { - this.sbStore.append( - " " + methodCall.toString().replace("\"", "\\\"") + " > " + value + "\\n"); - } - - @Override - public void visualizeStoreClassVals(FlowExpressions.ClassName className, A value) { - this.sbStore.append(" " + className + " > " + toStringEscapeDoubleQuotes(value) + "\\n"); - } - - @Override - public void visualizeStoreKeyVal(String keyName, Object value) { - this.sbStore.append(" " + keyName + " = " + value + "\\n"); - } - - protected String escapeDoubleQuotes(final String str) { - return str.replace("\"", "\\\""); - } - - protected String toStringEscapeDoubleQuotes(final Object obj) { - return escapeDoubleQuotes(String.valueOf(obj)); - } - - @Override - public void visualizeStoreHeader(String classCanonicalName) { - this.sbStore.append(classCanonicalName + " (\\n"); - } - - @Override - public void visualizeStoreFooter() { - this.sbStore.append(")"); - } - - /** - * Write a file {@code methods.txt} that contains a mapping from source code location to - * generated dot file. - */ - @Override - public void shutdown() { - try { - // Open for append, in case of multiple sub-checkers. - FileWriter fstream = new FileWriter(outdir + "/methods.txt", true); - BufferedWriter out = new BufferedWriter(fstream); - for (Map.Entry kv : generated.entrySet()) { - out.write(kv.getKey()); - out.append('\t'); - out.write(kv.getValue()); - out.append('\n'); - } - out.close(); - } catch (IOException e) { - ErrorReporter.errorAbort( - "Error creating methods.txt file in: " + outdir + "; ensure the path is valid", - e); - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java deleted file mode 100644 index fa6ff55dc553e6..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java +++ /dev/null @@ -1,269 +0,0 @@ -package org.checkerframework.dataflow.cfg; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.file.JavacFileManager; -import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Options; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import javax.lang.model.element.ExecutableElement; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.xml.ws.Holder; -import org.checkerframework.dataflow.analysis.AbstractValue; -import org.checkerframework.dataflow.analysis.Analysis; -import org.checkerframework.dataflow.analysis.Store; -import org.checkerframework.dataflow.analysis.TransferFunction; -import org.checkerframework.javacutil.BasicTypeProcessor; -import org.checkerframework.javacutil.TreeUtils; - -/** - * Class to generate the DOT representation of the control flow graph of a given method. - * - * @author Stefan Heule - */ -public class JavaSource2CFGDOT { - - /** Main method. */ - public static void main(String[] args) { - if (args.length < 2) { - printUsage(); - System.exit(1); - } - String input = args[0]; - String output = args[1]; - File file = new File(input); - if (!file.canRead()) { - printError("Cannot read input file: " + file.getAbsolutePath()); - printUsage(); - System.exit(1); - } - - String method = "test"; - String clas = "Test"; - boolean pdf = false; - boolean error = false; - - for (int i = 2; i < args.length; i++) { - if (args[i].equals("-pdf")) { - pdf = true; - } else if (args[i].equals("-method")) { - if (i >= args.length - 1) { - printError("Did not find after -method."); - continue; - } - i++; - method = args[i]; - } else if (args[i].equals("-class")) { - if (i >= args.length - 1) { - printError("Did not find after -class."); - continue; - } - i++; - clas = args[i]; - } else { - printError("Unknown command-line argument: " + args[i]); - error = true; - } - } - - if (error) { - System.exit(1); - } - - generateDOTofCFG(input, output, method, clas, pdf); - } - - /** Print an error message. */ - protected static void printError(String string) { - System.err.println("ERROR: " + string); - } - - /** Print usage information. */ - protected static void printUsage() { - System.out.println( - "Generate the control flow graph of a Java method, represented as a DOT graph."); - System.out.println( - "Parameters: [-method ] [-class ] [-pdf]"); - System.out.println(" -pdf: Also generate the PDF by invoking 'dot'."); - System.out.println(" -method: The method to generate the CFG for (defaults to 'test')."); - System.out.println( - " -class: The class in which to find the method (defaults to 'Test')."); - } - - /** Just like method above but without analysis. */ - public static void generateDOTofCFG( - String inputFile, String outputDir, String method, String clas, boolean pdf) { - generateDOTofCFG(inputFile, outputDir, method, clas, pdf, null); - } - - /** - * Generate the DOT representation of the CFG for a method. - * - * @param inputFile java source input file - * @param outputDir source output directory - * @param method method name to generate the CFG for - * @param pdf also generate a PDF? - * @param analysis analysis to perform befor the visualization (or {@code null} if no analysis - * is to be performed). - */ - public static , S extends Store, T extends TransferFunction> - void generateDOTofCFG( - String inputFile, - String outputDir, - String method, - String clas, - boolean pdf, - /*@Nullable*/ Analysis analysis) { - Entry m = - getMethodTreeAndCompilationUnit(inputFile, method, clas); - generateDOTofCFG( - inputFile, outputDir, method, clas, pdf, analysis, m.getKey(), m.getValue()); - } - - public static , S extends Store, T extends TransferFunction> - void generateDOTofCFG( - String inputFile, - String outputDir, - String method, - String clas, - boolean pdf, - /*@Nullable*/ Analysis analysis, - MethodTree m, - CompilationUnitTree r) { - String fileName = (new File(inputFile)).getName(); - System.out.println("Working on " + fileName + "..."); - - if (m == null) { - printError("Method not found."); - System.exit(1); - } - - ControlFlowGraph cfg = CFGBuilder.build(r, null, m, null); - if (analysis != null) { - analysis.performAnalysis(cfg); - } - - Map args = new HashMap<>(); - args.put("outdir", outputDir); - args.put("checkerName", ""); - - CFGVisualizer viz = new DOTCFGVisualizer(); - viz.init(args); - Map res = viz.visualize(cfg, cfg.getEntryBlock(), analysis); - viz.shutdown(); - - if (pdf) { - producePDF((String) res.get("dotFileName")); - } - } - - /** Invoke DOT to generate a PDF. */ - protected static void producePDF(String file) { - try { - String command = "dot -Tpdf \"" + file + ".txt\" -o \"" + file + ".pdf\""; - Process child = Runtime.getRuntime().exec(command); - child.waitFor(); - } catch (InterruptedException | IOException e) { - e.printStackTrace(); - System.exit(1); - } - } - - /** - * @return the AST of a specific method in a specific class in a specific file (or null if no - * such method exists) - */ - public static /*@Nullable*/ MethodTree getMethodTree( - String file, final String method, String clas) { - return getMethodTreeAndCompilationUnit(file, method, clas).getKey(); - } - - /** - * @return the AST of a specific method in a specific class as well as the {@link - * CompilationUnitTree} in a specific file (or null they do not exist). - */ - public static Entry - getMethodTreeAndCompilationUnit(String file, final String method, String clas) { - final Holder m = new Holder<>(); - final Holder c = new Holder<>(); - BasicTypeProcessor typeProcessor = - new BasicTypeProcessor() { - @Override - protected TreePathScanner createTreePathScanner( - CompilationUnitTree root) { - c.value = root; - return new TreePathScanner() { - @Override - public Void visitMethod(MethodTree node, Void p) { - ExecutableElement el = TreeUtils.elementFromDeclaration(node); - if (el.getSimpleName().contentEquals(method)) { - m.value = node; - // stop execution by throwing an exception. this - // makes sure that compilation does not proceed, and - // thus the AST is not modified by further phases of - // the compilation (and we save the work to do the - // compilation). - throw new RuntimeException(); - } - return null; - } - }; - } - }; - - Context context = new Context(); - Options.instance(context).put("compilePolicy", "ATTR_ONLY"); - JavaCompiler javac = new JavaCompiler(context); - JavacFileManager fileManager = (JavacFileManager) context.get(JavaFileManager.class); - - JavaFileObject l = - fileManager.getJavaFileObjectsFromStrings(List.of(file)).iterator().next(); - - PrintStream err = System.err; - try { - // redirect syserr to nothing (and prevent the compiler from issuing - // warnings about our exception. - System.setErr( - new PrintStream( - new OutputStream() { - @Override - public void write(int b) throws IOException {} - })); - javac.compile(List.of(l), List.of(clas), List.of(typeProcessor)); - } catch (Throwable e) { - // ok - } finally { - System.setErr(err); - } - return new Entry() { - @Override - public CompilationUnitTree setValue(CompilationUnitTree value) { - return null; - } - - @Override - public CompilationUnitTree getValue() { - return c.value; - } - - @Override - public MethodTree getKey() { - return m.value; - } - }; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java deleted file mode 100644 index dd646f110d5b79..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.checkerframework.dataflow.cfg; - -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.LambdaExpressionTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.Tree; - -/** - * Represents an abstract syntax tree of type {@link Tree} that underlies a given control flow - * graph. - * - * @author Stefan Heule - */ -public abstract class UnderlyingAST { - public enum Kind { - /** The underlying code is a whole method */ - METHOD, - /** The underlying code is a lambda expression */ - LAMBDA, - - /** The underlying code is an arbitrary Java statement or expression */ - ARBITRARY_CODE, - } - - protected final Kind kind; - - public UnderlyingAST(Kind kind) { - this.kind = kind; - } - - /** @return the code that corresponds to the CFG */ - public abstract Tree getCode(); - - public Kind getKind() { - return kind; - } - - /** If the underlying AST is a method. */ - public static class CFGMethod extends UnderlyingAST { - - /** The method declaration */ - protected final MethodTree method; - - /** The class tree this method belongs to. */ - protected final ClassTree classTree; - - public CFGMethod(MethodTree method, ClassTree classTree) { - super(Kind.METHOD); - this.method = method; - this.classTree = classTree; - } - - @Override - public Tree getCode() { - return method.getBody(); - } - - public MethodTree getMethod() { - return method; - } - - public ClassTree getClassTree() { - return classTree; - } - - @Override - public String toString() { - return "CFGMethod(\n" + method + "\n)"; - } - } - - /** If the underlying AST is a lambda. */ - public static class CFGLambda extends UnderlyingAST { - - private final LambdaExpressionTree lambda; - - public CFGLambda(LambdaExpressionTree lambda) { - super(Kind.LAMBDA); - this.lambda = lambda; - } - - @Override - public Tree getCode() { - return lambda.getBody(); - } - - public LambdaExpressionTree getLambdaTree() { - return lambda; - } - - @Override - public String toString() { - return "CFGLambda(\n" + lambda + "\n)"; - } - } - - /** If the underlying AST is a statement or expression. */ - public static class CFGStatement extends UnderlyingAST { - - protected final Tree code; - - /** The class tree this method belongs to. */ - protected final ClassTree classTree; - - public CFGStatement(Tree code, ClassTree classTree) { - super(Kind.ARBITRARY_CODE); - this.code = code; - this.classTree = classTree; - } - - @Override - public Tree getCode() { - return code; - } - - public ClassTree getClassTree() { - return classTree; - } - - @Override - public String toString() { - return "CFGStatement(\n" + code + "\n)"; - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java deleted file mode 100644 index 2d58550568b4a7..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -/** - * Represents a basic block in a control flow graph. - * - * @author Stefan Heule - */ -public interface Block { - - /** The types of basic blocks */ - public static enum BlockType { - - /** A regular basic block. */ - REGULAR_BLOCK, - - /** A conditional basic block. */ - CONDITIONAL_BLOCK, - - /** A special basic block. */ - SPECIAL_BLOCK, - - /** A basic block that can throw an exception. */ - EXCEPTION_BLOCK, - } - - /** @return the type of this basic block */ - BlockType getType(); - - /** @return the unique identifier of this block */ - long getId(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java deleted file mode 100644 index 0421a1e3f5ea08..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * Base class of the {@link Block} implementation hierarchy. - * - * @author Stefan Heule - */ -public abstract class BlockImpl implements Block { - - /** A unique ID for this node. */ - protected long id = BlockImpl.uniqueID(); - - /** The last ID that has already been used. */ - protected static long lastId = 0; - - /** The type of this basic block. */ - protected BlockType type; - - /** The set of predecessors. */ - protected Set predecessors; - - /** @return a fresh identifier */ - private static long uniqueID() { - return lastId++; - } - - public BlockImpl() { - predecessors = new HashSet<>(); - } - - @Override - public long getId() { - return id; - } - - @Override - public BlockType getType() { - return type; - } - - /** @return the list of predecessors of this basic block */ - public Set getPredecessors() { - return Collections.unmodifiableSet(predecessors); - } - - public void addPredecessor(BlockImpl pred) { - predecessors.add(pred); - } - - public void removePredecessor(BlockImpl pred) { - predecessors.remove(pred); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java deleted file mode 100644 index dce04abdfe37b3..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import org.checkerframework.dataflow.analysis.Store; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * Represents a conditional basic block that contains exactly one boolean {@link Node}. - * - * @author Stefan Heule - */ -public interface ConditionalBlock extends Block { - - /** @return the entry block of the then branch */ - Block getThenSuccessor(); - - /** @return the entry block of the else branch */ - Block getElseSuccessor(); - - /** @return the flow rule for information flowing from this block to its then successor */ - Store.FlowRule getThenFlowRule(); - - /** @return the flow rule for information flowing from this block to its else successor */ - Store.FlowRule getElseFlowRule(); - - /** Set the flow rule for information flowing from this block to its then successor. */ - void setThenFlowRule(Store.FlowRule rule); - - /** Set the flow rule for information flowing from this block to its else successor. */ - void setElseFlowRule(Store.FlowRule rule); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java deleted file mode 100644 index bd12522983a2c6..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import org.checkerframework.dataflow.analysis.Store; - -/** - * Implementation of a conditional basic block. - * - * @author Stefan Heule - */ -public class ConditionalBlockImpl extends BlockImpl implements ConditionalBlock { - - /** Successor of the then branch. */ - protected BlockImpl thenSuccessor; - - /** Successor of the else branch. */ - protected BlockImpl elseSuccessor; - - /** - * The rules below say that the THEN store before a conditional block flows to BOTH of the - * stores of the then successor, while the ELSE store before a conditional block flows to BOTH - * of the stores of the else successor. - */ - protected Store.FlowRule thenFlowRule = Store.FlowRule.THEN_TO_BOTH; - - protected Store.FlowRule elseFlowRule = Store.FlowRule.ELSE_TO_BOTH; - - /** - * Initialize an empty conditional basic block to be filled with contents and linked to other - * basic blocks later. - */ - public ConditionalBlockImpl() { - type = BlockType.CONDITIONAL_BLOCK; - } - - /** Set the then branch successor. */ - public void setThenSuccessor(BlockImpl b) { - thenSuccessor = b; - b.addPredecessor(this); - } - - /** Set the else branch successor. */ - public void setElseSuccessor(BlockImpl b) { - elseSuccessor = b; - b.addPredecessor(this); - } - - @Override - public Block getThenSuccessor() { - return thenSuccessor; - } - - @Override - public Block getElseSuccessor() { - return elseSuccessor; - } - - @Override - public Store.FlowRule getThenFlowRule() { - return thenFlowRule; - } - - @Override - public Store.FlowRule getElseFlowRule() { - return elseFlowRule; - } - - @Override - public void setThenFlowRule(Store.FlowRule rule) { - thenFlowRule = rule; - } - - @Override - public void setElseFlowRule(Store.FlowRule rule) { - elseFlowRule = rule; - } - - @Override - public String toString() { - return "ConditionalBlock()"; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java deleted file mode 100644 index a549c5f03fab8d..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import java.util.Map; -import java.util.Set; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * Represents a basic block that contains exactly one {@link Node} which can throw an exception. - * This block has exactly one non-exceptional successor, and one or more exceptional successors. - * - *

The following invariant holds. - * - *

- * getNode().getBlock() == this
- * 
- * - * @author Stefan Heule - */ -public interface ExceptionBlock extends SingleSuccessorBlock { - - /** @return the node of this block */ - Node getNode(); - - /** @return the list of exceptional successor blocks as an unmodifiable map */ - Map> getExceptionalSuccessors(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java deleted file mode 100644 index 2a6c3b4914cdd0..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * Base class of the {@link Block} implementation hierarchy. - * - * @author Stefan Heule - */ -public class ExceptionBlockImpl extends SingleSuccessorBlockImpl implements ExceptionBlock { - - /** Set of exceptional successors. */ - protected Map> exceptionalSuccessors; - - public ExceptionBlockImpl() { - type = BlockType.EXCEPTION_BLOCK; - exceptionalSuccessors = new HashMap<>(); - } - - /** The node of this block. */ - protected Node node; - - /** Set the node. */ - public void setNode(Node c) { - node = c; - c.setBlock(this); - } - - @Override - public Node getNode() { - return node; - } - - /** Add an exceptional successor. */ - public void addExceptionalSuccessor(BlockImpl b, TypeMirror cause) { - if (exceptionalSuccessors == null) { - exceptionalSuccessors = new HashMap<>(); - } - Set blocks = exceptionalSuccessors.get(cause); - if (blocks == null) { - blocks = new HashSet(); - exceptionalSuccessors.put(cause, blocks); - } - blocks.add(b); - b.addPredecessor(this); - } - - @Override - public Map> getExceptionalSuccessors() { - if (exceptionalSuccessors == null) { - return Collections.emptyMap(); - } - return Collections.unmodifiableMap(exceptionalSuccessors); - } - - @Override - public String toString() { - return "ExceptionBlock(" + node + ")"; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java deleted file mode 100644 index 566449257bf4da..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import java.util.List; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * A regular basic block that contains a sequence of {@link Node}s. - * - *

The following invariant holds. - * - *

- * forall n in getContents() :: n.getBlock() == this
- * 
- * - * @author Stefan Heule - */ -public interface RegularBlock extends SingleSuccessorBlock { - - /** @return the unmodifiable sequence of {@link Node}s. */ - List getContents(); - - /** @return the regular successor block */ - Block getRegularSuccessor(); - - /** Is this block empty (i.e., does it not contain any contents). */ - boolean isEmpty(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java deleted file mode 100644 index b302710d70a51b..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * Implementation of a regular basic block. - * - * @author Stefan Heule - */ -public class RegularBlockImpl extends SingleSuccessorBlockImpl implements RegularBlock { - - /** Internal representation of the contents. */ - protected List contents; - - /** - * Initialize an empty basic block to be filled with contents and linked to other basic blocks - * later. - */ - public RegularBlockImpl() { - contents = new LinkedList<>(); - type = BlockType.REGULAR_BLOCK; - } - - /** Add a node to the contents of this basic block. */ - public void addNode(Node t) { - contents.add(t); - t.setBlock(this); - } - - /** Add multiple nodes to the contents of this basic block. */ - public void addNodes(List ts) { - for (Node t : ts) { - addNode(t); - } - } - - @Override - public List getContents() { - return Collections.unmodifiableList(contents); - } - - @Override - public BlockImpl getRegularSuccessor() { - return successor; - } - - @Override - public String toString() { - return "RegularBlock(" + contents + ")"; - } - - @Override - public boolean isEmpty() { - return contents.isEmpty(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java deleted file mode 100644 index 038a69d3e49c7b..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import org.checkerframework.dataflow.analysis.Store; - -/** - * A basic block that has at exactly one non-exceptional successor. - * - * @author Stefan Heule - */ -public interface SingleSuccessorBlock extends Block { - - /** @return the non-exceptional successor block, or {@code null} if there is no successor. */ - /*@Nullable*/ Block getSuccessor(); - - /** @return the flow rule for information flowing from this block to its successor */ - Store.FlowRule getFlowRule(); - - /** Set the flow rule for information flowing from this block to its successor. */ - void setFlowRule(Store.FlowRule rule); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java deleted file mode 100644 index 9e8872e850e5f6..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import org.checkerframework.dataflow.analysis.Store; - -/** - * Implementation of a non-special basic block. - * - * @author Stefan Heule - */ -public abstract class SingleSuccessorBlockImpl extends BlockImpl implements SingleSuccessorBlock { - - /** Internal representation of the successor. */ - protected /*@Nullable*/ BlockImpl successor; - - /** - * The rule below say that EACH store at the end of a single successor block flow to the - * corresponding store of the successor. - */ - protected Store.FlowRule flowRule = Store.FlowRule.EACH_TO_EACH; - - @Override - public /*@Nullable*/ Block getSuccessor() { - return successor; - } - - /** Set a basic block as the successor of this block. */ - public void setSuccessor(BlockImpl successor) { - this.successor = successor; - successor.addPredecessor(this); - } - - @Override - public Store.FlowRule getFlowRule() { - return flowRule; - } - - @Override - public void setFlowRule(Store.FlowRule rule) { - flowRule = rule; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java deleted file mode 100644 index dac9b4b8c2e3f1..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -/** - * Represents a special basic block; i.e., one of the following: - * - *
    - *
  • Entry block of a method. - *
  • Regular exit block of a method. - *
  • Exceptional exit block of a method. - *
- * - * @author Stefan Heule - */ -public interface SpecialBlock extends SingleSuccessorBlock { - - /** The types of special basic blocks */ - public static enum SpecialBlockType { - - /** The entry block of a method */ - ENTRY, - - /** The exit block of a method */ - EXIT, - - /** A special exit block of a method for exceptional termination */ - EXCEPTIONAL_EXIT, - } - - /** @return the type of this special basic block */ - SpecialBlockType getSpecialType(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java deleted file mode 100644 index e6f25e8b1b6ad9..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.checkerframework.dataflow.cfg.block; - -public class SpecialBlockImpl extends SingleSuccessorBlockImpl implements SpecialBlock { - - /** The type of this special basic block. */ - protected SpecialBlockType specialType; - - public SpecialBlockImpl(SpecialBlockType type) { - this.specialType = type; - this.type = BlockType.SPECIAL_BLOCK; - } - - @Override - public SpecialBlockType getSpecialType() { - return specialType; - } - - @Override - public String toString() { - return "SpecialBlock(" + specialType + ")"; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java deleted file mode 100644 index 39f1f840743a9e..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java +++ /dev/null @@ -1,374 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/** - * A default implementation of the node visitor interface. The class introduces several 'summary' - * methods, that can be overridden to change the behavior of several related visit methods at once. - * An example is the {@code visitValueLiteral} method, that is called for every {@link - * ValueLiteralNode}. - * - *

This is useful to implement a visitor that performs the same operation (e.g., nothing) for - * most {@link Node}s and only has special behavior for a few. - * - * @author Stefan Heule - * @param return type of the visitor - * @param

parameter type of the visitor - */ -public abstract class AbstractNodeVisitor implements NodeVisitor { - - public abstract R visitNode(Node n, P p); - - public R visitValueLiteral(ValueLiteralNode n, P p) { - return visitNode(n, p); - } - - // Literals - @Override - public R visitShortLiteral(ShortLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitIntegerLiteral(IntegerLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitLongLiteral(LongLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitFloatLiteral(FloatLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitDoubleLiteral(DoubleLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitBooleanLiteral(BooleanLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitCharacterLiteral(CharacterLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitStringLiteral(StringLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - @Override - public R visitNullLiteral(NullLiteralNode n, P p) { - return visitValueLiteral(n, p); - } - - // Unary operations - @Override - public R visitNumericalMinus(NumericalMinusNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitNumericalPlus(NumericalPlusNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitBitwiseComplement(BitwiseComplementNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitNullChk(NullChkNode n, P p) { - return visitNode(n, p); - } - - // Binary operations - @Override - public R visitStringConcatenate(StringConcatenateNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitNumericalAddition(NumericalAdditionNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitNumericalSubtraction(NumericalSubtractionNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitNumericalMultiplication(NumericalMultiplicationNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitIntegerDivision(IntegerDivisionNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitFloatingDivision(FloatingDivisionNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitIntegerRemainder(IntegerRemainderNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitFloatingRemainder(FloatingRemainderNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitLeftShift(LeftShiftNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitSignedRightShift(SignedRightShiftNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitUnsignedRightShift(UnsignedRightShiftNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitBitwiseAnd(BitwiseAndNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitBitwiseOr(BitwiseOrNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitBitwiseXor(BitwiseXorNode n, P p) { - return visitNode(n, p); - } - - // Compound assignments - @Override - public R visitStringConcatenateAssignment(StringConcatenateAssignmentNode n, P p) { - return visitNode(n, p); - } - - // Comparison operations - @Override - public R visitLessThan(LessThanNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitLessThanOrEqual(LessThanOrEqualNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitGreaterThan(GreaterThanNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitGreaterThanOrEqual(GreaterThanOrEqualNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitEqualTo(EqualToNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitNotEqual(NotEqualNode n, P p) { - return visitNode(n, p); - } - - // Conditional operations - @Override - public R visitConditionalAnd(ConditionalAndNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitConditionalOr(ConditionalOrNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitConditionalNot(ConditionalNotNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitTernaryExpression(TernaryExpressionNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitAssignment(AssignmentNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitLocalVariable(LocalVariableNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitVariableDeclaration(VariableDeclarationNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitFieldAccess(FieldAccessNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitMethodAccess(MethodAccessNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitArrayAccess(ArrayAccessNode n, P p) { - return visitNode(n, p); - } - - public R visitThisLiteral(ThisLiteralNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitImplicitThisLiteral(ImplicitThisLiteralNode n, P p) { - return visitThisLiteral(n, p); - } - - @Override - public R visitExplicitThisLiteral(ExplicitThisLiteralNode n, P p) { - return visitThisLiteral(n, p); - } - - @Override - public R visitSuper(SuperNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitReturn(ReturnNode n, P p) { - return visitNode(n, p); - }; - - @Override - public R visitStringConversion(StringConversionNode n, P p) { - return visitNode(n, p); - }; - - @Override - public R visitNarrowingConversion(NarrowingConversionNode n, P p) { - return visitNode(n, p); - }; - - @Override - public R visitWideningConversion(WideningConversionNode n, P p) { - return visitNode(n, p); - }; - - @Override - public R visitInstanceOf(InstanceOfNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitTypeCast(TypeCastNode n, P p) { - return visitNode(n, p); - } - - // Statements - @Override - public R visitAssertionError(AssertionErrorNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitSynchronized(SynchronizedNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitThrow(ThrowNode n, P p) { - return visitNode(n, p); - } - - // Cases - @Override - public R visitCase(CaseNode n, P p) { - return visitNode(n, p); - } - - // Method and constructor invocations - @Override - public R visitMethodInvocation(MethodInvocationNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitObjectCreation(ObjectCreationNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitMemberReference(FunctionalInterfaceNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitArrayCreation(ArrayCreationNode n, P p) { - return visitNode(n, p); - } - - // Type, package and class names - @Override - public R visitArrayType(ArrayTypeNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitPrimitiveType(PrimitiveTypeNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitClassName(ClassNameNode n, P p) { - return visitNode(n, p); - } - - @Override - public R visitPackageName(PackageNameNode n, P p) { - return visitNode(n, p); - } - - // Parameterized types - @Override - public R visitParameterizedType(ParameterizedTypeNode n, P p) { - return visitNode(n, p); - } - - // Marker nodes - @Override - public R visitMarker(MarkerNode n, P p) { - return visitNode(n, p); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java deleted file mode 100644 index 24ef689ee9abd3..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.LinkedList; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for an array access: - * - *

- *   arrayref [ index ]
- * 
- * - * We allow array accesses without corresponding AST {@link Tree}s. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ArrayAccessNode extends Node { - - protected Tree tree; - protected Node array; - protected Node index; - - public ArrayAccessNode(Tree t, Node array, Node index) { - super(InternalUtils.typeOf(t)); - assert t instanceof ArrayAccessTree; - this.tree = t; - this.array = array; - this.index = index; - } - - public Node getArray() { - return array; - } - - public Node getIndex() { - return index; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitArrayAccess(this, p); - } - - @Override - public String toString() { - String base = getArray().toString() + "[" + getIndex().toString() + "]"; - return base; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayAccessNode)) { - return false; - } - ArrayAccessNode other = (ArrayAccessNode) obj; - return getArray().equals(other.getArray()) && getIndex().equals(other.getIndex()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getArray(), getIndex()); - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getArray()); - list.add(getIndex()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java deleted file mode 100644 index 5f277f2a0b3295..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for new array creation - * - *
- *   new type [1][2]
- *   new type [] = { expr1, expr2, ... }
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ArrayCreationNode extends Node { - - /** The tree is null when an array is created for variable arity method calls. */ - protected /*@Nullable*/ NewArrayTree tree; - /** - * The length of this list is the number of dimensions in the array. Each element is the size of - * the given dimension. - */ - protected List dimensions; - - protected List initializers; - - public ArrayCreationNode( - /*@Nullable*/ NewArrayTree tree, - TypeMirror type, - List dimensions, - List initializers) { - super(type); - this.tree = tree; - this.dimensions = dimensions; - this.initializers = initializers; - } - - public List getDimensions() { - return dimensions; - } - - public Node getDimension(int i) { - return dimensions.get(i); - } - - public List getInitializers() { - return initializers; - } - - public Node getInitializer(int i) { - return initializers.get(i); - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitArrayCreation(this, p); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append("new " + type); - if (!dimensions.isEmpty()) { - boolean needComma = false; - sb.append(" ("); - for (Node dim : dimensions) { - if (needComma) { - sb.append(", "); - } - sb.append(dim); - needComma = true; - } - sb.append(")"); - } - if (!initializers.isEmpty()) { - boolean needComma = false; - sb.append(" = {"); - for (Node init : initializers) { - if (needComma) { - sb.append(", "); - } - sb.append(init); - needComma = true; - } - sb.append("}"); - } - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayCreationNode)) { - return false; - } - ArrayCreationNode other = (ArrayCreationNode) obj; - - return getDimensions().equals(other.getDimensions()) - && getInitializers().equals(other.getInitializers()); - } - - @Override - public int hashCode() { - int hash = 0; - for (Node dim : dimensions) { - hash = HashCodeUtils.hash(hash, dim.hashCode()); - } - for (Node init : initializers) { - hash = HashCodeUtils.hash(hash, init.hashCode()); - } - return hash; - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.addAll(dimensions); - list.addAll(initializers); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java deleted file mode 100644 index dfde575b5e585c..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ArrayTypeTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node representing a array type used in an expression such as a field access - * - *

type .class - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ArrayTypeNode extends Node { - - protected final ArrayTypeTree tree; - - public ArrayTypeNode(ArrayTypeTree tree) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitArrayType(this, p); - } - - @Override - public String toString() { - return tree.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayTypeNode)) { - return false; - } - ArrayTypeNode other = (ArrayTypeNode) obj; - return getType().equals(other.getType()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getType()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java deleted file mode 100644 index 0b4d747331e5d8..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import java.util.Collection; -import java.util.LinkedList; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the {@link AssertionError} when an assertion fails. - * - *

- *   assert condition : detail ;
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class AssertionErrorNode extends Node { - - protected Tree tree; - protected Node condition; - protected Node detail; - - public AssertionErrorNode(Tree tree, Node condition, Node detail, TypeMirror type) { - // TODO: Find out the correct "type" for statements. - // Is it TypeKind.NONE? - super(type); - assert tree.getKind() == Kind.ASSERT; - this.tree = tree; - this.condition = condition; - this.detail = detail; - } - - public Node getCondition() { - return condition; - } - - public Node getDetail() { - return detail; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitAssertionError(this, p); - } - - @Override - public String toString() { - return "AssertionError(" + getDetail() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof AssertionErrorNode)) { - return false; - } - AssertionErrorNode other = (AssertionErrorNode) obj; - return getCondition().equals(other.getCondition()) && getDetail().equals(other.getDetail()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getCondition(), getDetail()); - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getCondition()); - list.add(getDetail()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java deleted file mode 100644 index 5e6a1606dec347..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.VariableTree; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import org.checkerframework.javacutil.TreeUtils; - -/** - * An assignment context for a node, which represents the place to which the node with this context - * is 'assigned' to. An 'assignment' (as we use the term here) can occur for Java assignments, - * method calls (for all the actual parameters which get assigned to their formal parameters) or - * method return statements. - * - *

The main use of {@link AssignmentContext} is to be able to get the declared type of the - * left-hand side of the assignment for proper type-refinement. - * - * @author Stefan Heule - */ -public abstract class AssignmentContext { - - /** An assignment context for an assignment 'lhs = rhs'. */ - public static class AssignmentLhsContext extends AssignmentContext { - - protected final Node node; - - public AssignmentLhsContext(Node node) { - this.node = node; - } - - @Override - public Element getElementForType() { - Tree tree = node.getTree(); - if (tree == null) { - return null; - } else if (tree instanceof ExpressionTree) { - return TreeUtils.elementFromUse((ExpressionTree) tree); - } else if (tree instanceof VariableTree) { - return TreeUtils.elementFromDeclaration((VariableTree) tree); - } else { - assert false : "unexpected tree"; - return null; - } - } - - @Override - public Tree getContextTree() { - return node.getTree(); - } - } - - /** An assignment context for a method parameter. */ - public static class MethodParameterContext extends AssignmentContext { - - protected final ExecutableElement method; - protected final int paramNum; - - public MethodParameterContext(ExecutableElement method, int paramNum) { - this.method = method; - this.paramNum = paramNum; - } - - @Override - public Element getElementForType() { - return method.getParameters().get(paramNum); - } - - @Override - public Tree getContextTree() { - // TODO: what is the right assignment context? We might not have - // a tree for the invoked method. - return null; - } - } - - /** An assignment context for method return statements. */ - public static class MethodReturnContext extends AssignmentContext { - - protected final ExecutableElement method; - protected final Tree ret; - - public MethodReturnContext(MethodTree method) { - this.method = TreeUtils.elementFromDeclaration(method); - this.ret = method.getReturnType(); - } - - @Override - public Element getElementForType() { - return method; - } - - @Override - public Tree getContextTree() { - return ret; - } - } - - /** An assignment context for lambda return statements. */ - public static class LambdaReturnContext extends AssignmentContext { - - protected final ExecutableElement method; - - public LambdaReturnContext(ExecutableElement method) { - this.method = method; - } - - @Override - public Element getElementForType() { - return method; - } - - @Override - public Tree getContextTree() { - // TODO: what is the right assignment context? We might not have - // a tree for the invoked method. - return null; - } - } - - /** Returns an {@link Element} that has the type of this assignment context. */ - public abstract Element getElementForType(); - - public abstract Tree getContextTree(); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java deleted file mode 100644 index 32723dd8e4fe45..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.AssignmentTree; -import com.sun.source.tree.CompoundAssignmentTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.UnaryTree; -import com.sun.source.tree.VariableTree; -import java.util.Collection; -import java.util.LinkedList; -import org.checkerframework.dataflow.cfg.node.AssignmentContext.AssignmentLhsContext; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for an assignment: - * - *

- *   variable = expression
- *   expression . field = expression
- *   expression [ index ] = expression
- * 
- * - * We allow assignments without corresponding AST {@link Tree}s. - * - * @author Stefan Heule - */ -public class AssignmentNode extends Node { - - protected Tree tree; - protected Node lhs; - protected Node rhs; - - public AssignmentNode(Tree tree, Node target, Node expression) { - super(InternalUtils.typeOf(tree)); - assert tree instanceof AssignmentTree - || tree instanceof VariableTree - || tree instanceof CompoundAssignmentTree - || tree instanceof UnaryTree; - assert target instanceof FieldAccessNode - || target instanceof LocalVariableNode - || target instanceof ArrayAccessNode; - this.tree = tree; - this.lhs = target; - this.rhs = expression; - rhs.setAssignmentContext(new AssignmentLhsContext(lhs)); - } - - public Node getTarget() { - return lhs; - } - - public Node getExpression() { - return rhs; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitAssignment(this, p); - } - - @Override - public String toString() { - return getTarget() + " = " + getExpression(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof AssignmentNode)) { - return false; - } - AssignmentNode other = (AssignmentNode) obj; - return getTarget().equals(other.getTarget()) - && getExpression().equals(other.getExpression()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getTarget(), getExpression()); - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getTarget()); - list.add(getExpression()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java deleted file mode 100644 index 424747b4ac8723..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import java.util.Collection; -import java.util.LinkedList; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a binary expression. - * - *

For example: - * - *

- *   lefOperandNode operator rightOperandNode
- * 
- * - * @author charleszhuochen - */ -public abstract class BinaryOperationNode extends Node { - - protected final BinaryTree tree; - protected final Node left; - protected final Node right; - - public BinaryOperationNode(BinaryTree tree, Node left, Node right) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - this.left = left; - this.right = right; - } - - public Node getLeftOperand() { - return left; - } - - public Node getRightOperand() { - return right; - } - - @Override - public BinaryTree getTree() { - return tree; - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getLeftOperand()); - list.add(getRightOperand()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java deleted file mode 100644 index 18d7163f2210fa..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the bitwise or logical (single bit) and operation: - * - *
- *   expression & expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class BitwiseAndNode extends BinaryOperationNode { - - public BitwiseAndNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.AND; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitBitwiseAnd(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " & " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof BitwiseAndNode)) { - return false; - } - BitwiseAndNode other = (BitwiseAndNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java deleted file mode 100644 index a1c2111b8c5eb9..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.UnaryTree; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the bitwise complement operation: - * - *
- *   ~ expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class BitwiseComplementNode extends UnaryOperationNode { - - public BitwiseComplementNode(UnaryTree tree, Node operand) { - super(tree, operand); - assert tree.getKind() == Kind.BITWISE_COMPLEMENT; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitBitwiseComplement(this, p); - } - - @Override - public String toString() { - return "(~ " + getOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof BitwiseComplementNode)) { - return false; - } - BitwiseComplementNode other = (BitwiseComplementNode) obj; - return getOperand().equals(other.getOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java deleted file mode 100644 index 66089133f2d976..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the bitwise or logical (single bit) or operation: - * - *
- *   expression | expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class BitwiseOrNode extends BinaryOperationNode { - - public BitwiseOrNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.OR; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitBitwiseOr(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " | " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof BitwiseOrNode)) { - return false; - } - BitwiseOrNode other = (BitwiseOrNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java deleted file mode 100644 index cdbe0ed93db28a..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the bitwise or logical (single bit) xor operation: - * - *
- *   expression ^ expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class BitwiseXorNode extends BinaryOperationNode { - - public BitwiseXorNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.XOR; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitBitwiseXor(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " ^ " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof BitwiseXorNode)) { - return false; - } - BitwiseXorNode other = (BitwiseXorNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java deleted file mode 100644 index 7f5a7a1edad69f..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for a boolean literal: - * - *
- *   true
- *   false
- * 
- * - * @author Stefan Heule - */ -public class BooleanLiteralNode extends ValueLiteralNode { - - public BooleanLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.BOOLEAN_LITERAL); - } - - @Override - public Boolean getValue() { - return (Boolean) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitBooleanLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a BooleanLiteralNode - if (!(obj instanceof BooleanLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java deleted file mode 100644 index a694dfb975e18e..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.CaseTree; -import com.sun.source.tree.Tree.Kind; -import java.util.Collection; -import java.util.LinkedList; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for a case in a switch statement. Although a case has no abstract value, it can imply - * facts about the abstract values of its operands. - * - *
- *   case constant:
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class CaseNode extends Node { - - protected CaseTree tree; - protected Node switchExpr; - protected Node caseExpr; - - public CaseNode(CaseTree tree, Node switchExpr, Node caseExpr, Types types) { - super(types.getNoType(TypeKind.NONE)); - assert tree.getKind().equals(Kind.CASE); - this.tree = tree; - this.switchExpr = switchExpr; - this.caseExpr = caseExpr; - } - - public Node getSwitchOperand() { - return switchExpr; - } - - public Node getCaseOperand() { - return caseExpr; - } - - @Override - public CaseTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitCase(this, p); - } - - @Override - public String toString() { - return "case " + getCaseOperand() + ":"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof CaseNode)) { - return false; - } - CaseNode other = (CaseNode) obj; - return getSwitchOperand().equals(other.getSwitchOperand()) - && getCaseOperand().equals(other.getCaseOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getSwitchOperand(), getCaseOperand()); - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getSwitchOperand()); - list.add(getCaseOperand()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java deleted file mode 100644 index c1d51c7523da88..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for a character literal. For example: - * - *
- *   'a'
- *   '\t'
- *   '\u03a9'
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class CharacterLiteralNode extends ValueLiteralNode { - - public CharacterLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.CHAR_LITERAL); - } - - @Override - public Character getValue() { - return (Character) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitCharacterLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a CharacterLiteralNode - if (obj == null || !(obj instanceof CharacterLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java deleted file mode 100644 index c3e2471309da51..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.element.Element; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; - -/** - * A node representing a class name used in an expression such as a static method invocation. - * - *

parent.class .forName(...) - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ClassNameNode extends Node { - - protected final Tree tree; - /** The class named by this node */ - protected final Element element; - - /** The parent name, if any. */ - protected final /*@Nullable*/ Node parent; - - public ClassNameNode(IdentifierTree tree) { - super(InternalUtils.typeOf(tree)); - assert tree.getKind() == Tree.Kind.IDENTIFIER; - this.tree = tree; - this.element = TreeUtils.elementFromUse(tree); - this.parent = null; - } - - public ClassNameNode(ClassTree tree) { - super(InternalUtils.typeOf(tree)); - assert tree.getKind() == Tree.Kind.CLASS - || tree.getKind() == Tree.Kind.ENUM - || tree.getKind() == Tree.Kind.INTERFACE - || tree.getKind() == Tree.Kind.ANNOTATION_TYPE; - this.tree = tree; - this.element = TreeUtils.elementFromDeclaration(tree); - this.parent = null; - } - - public ClassNameNode(MemberSelectTree tree, Node parent) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - this.element = TreeUtils.elementFromUse(tree); - this.parent = parent; - } - - public ClassNameNode(TypeMirror type, Element element) { - super(type); - this.tree = null; - this.element = element; - this.parent = null; - } - - public Element getElement() { - return element; - } - - public Node getParent() { - return parent; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitClassName(this, p); - } - - @Override - public String toString() { - return getElement().getSimpleName().toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ClassNameNode)) { - return false; - } - ClassNameNode other = (ClassNameNode) obj; - if (getParent() == null) { - return other.getParent() == null && getElement().equals(other.getElement()); - } else { - return getParent().equals(other.getParent()) && getElement().equals(other.getElement()); - } - } - - @Override - public int hashCode() { - if (parent == null) { - return HashCodeUtils.hash(getElement()); - } - return HashCodeUtils.hash(getElement(), getParent()); - } - - @Override - public Collection getOperands() { - if (parent == null) { - return Collections.emptyList(); - } - return Collections.singleton(parent); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java deleted file mode 100644 index fb5145ab891309..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for a conditional and expression: - * - *

- *   expression && expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ConditionalAndNode extends BinaryOperationNode { - - public ConditionalAndNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind().equals(Kind.CONDITIONAL_AND); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitConditionalAnd(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " && " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ConditionalAndNode)) { - return false; - } - ConditionalAndNode other = (ConditionalAndNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java deleted file mode 100644 index 6a28c67a168bc8..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.UnaryTree; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for a conditional not expression: - * - *
- *   ! expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ConditionalNotNode extends UnaryOperationNode { - - public ConditionalNotNode(UnaryTree tree, Node operand) { - super(tree, operand); - assert tree.getKind().equals(Kind.LOGICAL_COMPLEMENT); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitConditionalNot(this, p); - } - - @Override - public String toString() { - return "(!" + getOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ConditionalNotNode)) { - return false; - } - ConditionalNotNode other = (ConditionalNotNode) obj; - return getOperand().equals(other.getOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java deleted file mode 100644 index e5cb0bfc13a58e..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for a conditional or expression: - * - *
- *   expression || expression
- * 
- * - * @author Stefan Heule - */ -public class ConditionalOrNode extends BinaryOperationNode { - - public ConditionalOrNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind().equals(Kind.CONDITIONAL_OR); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitConditionalOr(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " || " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ConditionalOrNode)) { - return false; - } - ConditionalOrNode other = (ConditionalOrNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java deleted file mode 100644 index 60c25749a415b7..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for a double literal. For example: - * - *
- *   -9.
- *   3.14159D
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class DoubleLiteralNode extends ValueLiteralNode { - - public DoubleLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.DOUBLE_LITERAL); - } - - @Override - public Double getValue() { - return (Double) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitDoubleLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a DoubleLiteralNode - if (obj == null || !(obj instanceof DoubleLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java deleted file mode 100644 index b1fb5d8f68e758..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for an equality check: - * - *
- *   expression == expression
- * 
- * - * @author Stefan Heule - */ -public class EqualToNode extends BinaryOperationNode { - - public EqualToNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind().equals(Kind.EQUAL_TO); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitEqualTo(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " == " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof EqualToNode)) { - return false; - } - EqualToNode other = (EqualToNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java deleted file mode 100644 index abb3b5447e2ec4..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.Tree; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a reference to 'this'. - * - *
- *   this
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ExplicitThisLiteralNode extends ThisLiteralNode { - - protected Tree tree; - - public ExplicitThisLiteralNode(Tree t) { - super(InternalUtils.typeOf(t)); - assert t instanceof IdentifierTree && ((IdentifierTree) t).getName().contentEquals("this"); - tree = t; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitExplicitThisLiteral(this, p); - } - - @Override - public String toString() { - return getName(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java deleted file mode 100644 index 1b8e856a1765af..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.element.VariableElement; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.ElementUtils; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; - -/** - * A node for a field access, including a method accesses: - * - *
- *   expression . field
- * 
- * - * @author Stefan Heule - */ -public class FieldAccessNode extends Node { - - protected Tree tree; - protected VariableElement element; - protected String field; - protected Node receiver; - - // TODO: add method to get modifiers (static, access level, ..) - - public FieldAccessNode(Tree tree, Node receiver) { - super(InternalUtils.typeOf(tree)); - assert TreeUtils.isFieldAccess(tree); - this.tree = tree; - this.receiver = receiver; - this.field = TreeUtils.getFieldName(tree); - - if (tree instanceof MemberSelectTree) { - this.element = (VariableElement) TreeUtils.elementFromUse((MemberSelectTree) tree); - } else { - assert tree instanceof IdentifierTree; - this.element = (VariableElement) TreeUtils.elementFromUse((IdentifierTree) tree); - } - } - - public FieldAccessNode(Tree tree, VariableElement element, Node receiver) { - super(element.asType()); - this.tree = tree; - this.element = element; - this.receiver = receiver; - this.field = element.getSimpleName().toString(); - } - - public VariableElement getElement() { - return element; - } - - public Node getReceiver() { - return receiver; - } - - public String getFieldName() { - return field; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitFieldAccess(this, p); - } - - @Override - public String toString() { - return getReceiver() + "." + field; - } - - /** Is this a static field? */ - public boolean isStatic() { - return ElementUtils.isStatic(getElement()); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof FieldAccessNode)) { - return false; - } - FieldAccessNode other = (FieldAccessNode) obj; - return getReceiver().equals(other.getReceiver()) - && getFieldName().equals(other.getFieldName()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getReceiver(), getFieldName()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(receiver); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java deleted file mode 100644 index ee8b5103ed7bc4..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for a float literal. For example: - * - *
- *   8.0f
- *   6.022137e+23F
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class FloatLiteralNode extends ValueLiteralNode { - - public FloatLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.FLOAT_LITERAL); - } - - @Override - public Float getValue() { - return (Float) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitFloatLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a FloatLiteralNode - if (obj == null || !(obj instanceof FloatLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java deleted file mode 100644 index 6eb6c41ac4cc05..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the floating-point division: - * - *
- *   expression / expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class FloatingDivisionNode extends BinaryOperationNode { - - public FloatingDivisionNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.DIVIDE; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitFloatingDivision(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " / " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof FloatingDivisionNode)) { - return false; - } - FloatingDivisionNode other = (FloatingDivisionNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java deleted file mode 100644 index d3a7918ff19d86..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the floating-point remainder: - * - *
- *   expression % expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class FloatingRemainderNode extends BinaryOperationNode { - - public FloatingRemainderNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.REMAINDER; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitFloatingRemainder(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " % " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof FloatingRemainderNode)) { - return false; - } - FloatingRemainderNode other = (FloatingRemainderNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java deleted file mode 100644 index a0ddbaf10cc298..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LambdaExpressionTree; -import com.sun.source.tree.MemberReferenceTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.LinkedList; -import org.checkerframework.javacutil.ErrorReporter; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for member references and lambdas. - * - *

The {@link Node#type} of a FunctionalInterfaceNode is determined by the assignment context the - * member reference or lambda is used in. - * - *

- *   FunctionalInterface func = param1, param2, ... → statement
- * 
- * - *
- *   FunctionalInterface func = param1, param2, ... → { ... }
- * 
- * - *
- *   FunctionalInterface func = member reference
- * 
- * - * @author David - */ -public class FunctionalInterfaceNode extends Node { - - protected Tree tree; - - public FunctionalInterfaceNode(MemberReferenceTree tree) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - } - - public FunctionalInterfaceNode(LambdaExpressionTree tree) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitMemberReference(this, p); - } - - @Override - public String toString() { - if (tree instanceof LambdaExpressionTree) { - return "FunctionalInterfaceNode:" + ((LambdaExpressionTree) tree).getBodyKind(); - } else if (tree instanceof MemberReferenceTree) { - return "FunctionalInterfaceNode:" + ((MemberReferenceTree) tree).getName(); - } else { - // This should never happen. - ErrorReporter.errorAbort("Invalid tree in FunctionalInterfaceNode"); - return null; // Dead code - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - FunctionalInterfaceNode that = (FunctionalInterfaceNode) o; - - if (tree != null ? !tree.equals(that.tree) : that.tree != null) return false; - - return true; - } - - @Override - public int hashCode() { - return tree != null ? tree.hashCode() : 0; - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java deleted file mode 100644 index f1713a924130f9..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the greater than comparison: - * - *
- *   expression > expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class GreaterThanNode extends BinaryOperationNode { - - public GreaterThanNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.GREATER_THAN; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitGreaterThan(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " > " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof GreaterThanNode)) { - return false; - } - GreaterThanNode other = (GreaterThanNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java deleted file mode 100644 index 058ae7be849394..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the greater than or equal comparison: - * - *
- *   expression >= expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class GreaterThanOrEqualNode extends BinaryOperationNode { - - public GreaterThanOrEqualNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.GREATER_THAN_EQUAL; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitGreaterThanOrEqual(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " >= " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof GreaterThanOrEqualNode)) { - return false; - } - GreaterThanOrEqualNode other = (GreaterThanOrEqualNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java deleted file mode 100644 index 25a63617adb78c..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import javax.lang.model.type.TypeMirror; - -/** - * A node to model the implicit {@code this}, e.g., in a field access. - * - * @author Stefan Heule - */ -public class ImplicitThisLiteralNode extends ThisLiteralNode { - - public ImplicitThisLiteralNode(TypeMirror type) { - super(type); - } - - @Override - public Tree getTree() { - return null; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitImplicitThisLiteral(this, p); - } - - @Override - public String toString() { - return "(" + getName() + ")"; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java deleted file mode 100644 index 78b4e06916ed4c..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.InstanceOfTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the instanceof operator: - * - *

x instanceof Point - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class InstanceOfNode extends Node { - - /** The value being tested. */ - protected Node operand; - - /** The reference type being tested against. */ - protected TypeMirror refType; - - /** The tree associated with this node. */ - protected final InstanceOfTree tree; - - public InstanceOfNode(Tree tree, Node operand, TypeMirror refType, Types types) { - super(types.getPrimitiveType(TypeKind.BOOLEAN)); - assert tree.getKind() == Tree.Kind.INSTANCE_OF; - this.tree = (InstanceOfTree) tree; - this.operand = operand; - this.refType = refType; - } - - public Node getOperand() { - return operand; - } - - @Override - public TypeMirror getType() { - return type; - } - - public TypeMirror getRefType() { - return refType; - } - - @Override - public InstanceOfTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitInstanceOf(this, p); - } - - @Override - public String toString() { - return "(" + getOperand() + " instanceof " + getRefType() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof InstanceOfNode)) { - return false; - } - InstanceOfNode other = (InstanceOfNode) obj; - // TODO: TypeMirror.equals may be too restrictive. - // Check whether Types.isSameType is the better comparison. - return getOperand().equals(other.getOperand()) && getRefType().equals(other.getRefType()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java deleted file mode 100644 index e69947bea54eae..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the integer division: - * - *

- *   expression / expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class IntegerDivisionNode extends BinaryOperationNode { - - public IntegerDivisionNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.DIVIDE; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitIntegerDivision(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " / " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof IntegerDivisionNode)) { - return false; - } - IntegerDivisionNode other = (IntegerDivisionNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java deleted file mode 100644 index 5bea7793698855..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for an integer literal. For example: - * - *
- *   42
- * 
- * - * @author Stefan Heule - */ -public class IntegerLiteralNode extends ValueLiteralNode { - - int value; - - public IntegerLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.INT_LITERAL); - value = (Integer) tree.getValue(); - } - - @Override - public Integer getValue() { - return value; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitIntegerLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a IntegerLiteralNode - if (!(obj instanceof IntegerLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java deleted file mode 100644 index d5399183a729b1..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the integer remainder: - * - *
- *   expression % expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class IntegerRemainderNode extends BinaryOperationNode { - - public IntegerRemainderNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.REMAINDER; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitIntegerRemainder(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " % " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof IntegerRemainderNode)) { - return false; - } - IntegerRemainderNode other = (IntegerRemainderNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java deleted file mode 100644 index 65a1e13d3ccb42..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for bitwise left shift operations: - * - *
- *   expression << expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class LeftShiftNode extends BinaryOperationNode { - - public LeftShiftNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.LEFT_SHIFT; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitLeftShift(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " << " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof LeftShiftNode)) { - return false; - } - LeftShiftNode other = (LeftShiftNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java deleted file mode 100644 index fcc901150a4105..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the less than comparison: - * - *
- *   expression < expression
- * 
- * - * We allow less than nodes without corresponding AST {@link Tree}s. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class LessThanNode extends BinaryOperationNode { - - public LessThanNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.LESS_THAN; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitLessThan(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " < " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof LessThanNode)) { - return false; - } - LessThanNode other = (LessThanNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java deleted file mode 100644 index 0dfb65ec41c8f1..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the less than or equal comparison: - * - *
- *   expression <= expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class LessThanOrEqualNode extends BinaryOperationNode { - - public LessThanOrEqualNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.LESS_THAN_EQUAL; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitLessThanOrEqual(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " <= " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof LessThanOrEqualNode)) { - return false; - } - LessThanOrEqualNode other = (LessThanOrEqualNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java deleted file mode 100644 index 724d63a46b8e14..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.VariableTree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.element.Element; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; - -/** - * A node for a local variable or a parameter: - * - *
- *   identifier
- * 
- * - * We allow local variable uses introduced by the {@link - * org.checkerframework.dataflow.cfg.CFGBuilder} without corresponding AST {@link Tree}s. - * - * @author Stefan Heule - */ -// TODO: don't use for parameters, as they don't have a tree -public class LocalVariableNode extends Node { - - protected Tree tree; - protected Node receiver; - - public LocalVariableNode(Tree t) { - super(InternalUtils.typeOf(t)); - // IdentifierTree for normal uses of the local variable or parameter, - // and VariableTree for the translation of an initializer block - assert t != null; - assert t instanceof IdentifierTree || t instanceof VariableTree; - tree = t; - this.receiver = null; - } - - public LocalVariableNode(Tree t, Node receiver) { - this(t); - this.receiver = receiver; - } - - public Element getElement() { - Element el; - if (tree instanceof IdentifierTree) { - el = TreeUtils.elementFromUse((IdentifierTree) tree); - } else { - assert tree instanceof VariableTree; - el = TreeUtils.elementFromDeclaration((VariableTree) tree); - } - return el; - } - - public Node getReceiver() { - return receiver; - } - - public String getName() { - if (tree instanceof IdentifierTree) { - return ((IdentifierTree) tree).getName().toString(); - } - return ((VariableTree) tree).getName().toString(); - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitLocalVariable(this, p); - } - - @Override - public String toString() { - return getName().toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof LocalVariableNode)) { - return false; - } - LocalVariableNode other = (LocalVariableNode) obj; - return getName().equals(other.getName()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getName()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java deleted file mode 100644 index b92575ef90f8ac..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for a long literal. For example: - * - *
- *   -3l
- *   0x80808080L
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class LongLiteralNode extends ValueLiteralNode { - - public LongLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.LONG_LITERAL); - } - - @Override - public Long getValue() { - return (Long) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitLongLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a LongLiteralNode - if (obj == null || !(obj instanceof LongLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java deleted file mode 100644 index a7a892f3be67dc..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * MarkerNodes are no-op Nodes used for debugging information. They can hold a Tree and a message, - * which will be part of the String representation of the MarkerNode. - * - *

An example use case for MarkerNodes is representing switch statements. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class MarkerNode extends Node { - - protected /*@Nullable*/ Tree tree; - protected String message; - - public MarkerNode(/*@Nullable*/ Tree tree, String message, Types types) { - super(types.getNoType(TypeKind.NONE)); - this.tree = tree; - this.message = message; - } - - public String getMessage() { - return message; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitMarker(this, p); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append("marker "); - sb.append("(" + message + ")"); - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof MarkerNode)) { - return false; - } - MarkerNode other = (MarkerNode) obj; - if (tree == null && other.getTree() != null) { - return false; - } - - return getTree().equals(other.getTree()) && getMessage().equals(other.getMessage()); - } - - @Override - public int hashCode() { - int hash = 0; - if (tree != null) { - hash = HashCodeUtils.hash(tree); - } - return HashCodeUtils.hash(hash, getMessage()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java deleted file mode 100644 index 060f17b62dbd62..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.element.ExecutableElement; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; - -/** - * A node for a method access, including a method accesses: - * - *

- *   expression . method ()
- * 
- * - * @author Stefan Heule - */ -public class MethodAccessNode extends Node { - - protected ExpressionTree tree; - protected ExecutableElement method; - protected Node receiver; - - // TODO: add method to get modifiers (static, access level, ..) - - public MethodAccessNode(ExpressionTree tree, Node receiver) { - super(InternalUtils.typeOf(tree)); - assert TreeUtils.isMethodAccess(tree); - this.tree = tree; - this.method = (ExecutableElement) TreeUtils.elementFromUse(tree); - this.receiver = receiver; - } - - public ExecutableElement getMethod() { - return method; - } - - public Node getReceiver() { - return receiver; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitMethodAccess(this, p); - } - - @Override - public String toString() { - return getReceiver() + "." + method.getSimpleName(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof MethodAccessNode)) { - return false; - } - MethodAccessNode other = (MethodAccessNode) obj; - return getReceiver().equals(other.getReceiver()) && getMethod().equals(other.getMethod()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getReceiver(), getMethod()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(receiver); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java deleted file mode 100644 index 9456f37808ed4f..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.Tree; -import com.sun.source.util.TreePath; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import org.checkerframework.dataflow.cfg.node.AssignmentContext.MethodParameterContext; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for method invocation - * - *
- *   target(arg1, arg2, ...)
- * 
- * - * CFGs may contain {@link MethodInvocationNode}s that correspond to no AST {@link Tree}, in which - * case, the tree field will be null. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class MethodInvocationNode extends Node { - - protected MethodInvocationTree tree; - protected MethodAccessNode target; - protected List arguments; - protected TreePath treePath; - - public MethodInvocationNode( - MethodInvocationTree tree, - MethodAccessNode target, - List arguments, - TreePath treePath) { - super(tree != null ? InternalUtils.typeOf(tree) : target.getMethod().getReturnType()); - this.tree = tree; - this.target = target; - this.arguments = arguments; - this.treePath = treePath; - - // set assignment contexts for parameters - int i = 0; - for (Node arg : arguments) { - AssignmentContext ctx = new MethodParameterContext(target.getMethod(), i++); - arg.setAssignmentContext(ctx); - } - } - - public MethodInvocationNode(MethodAccessNode target, List arguments, TreePath treePath) { - this(null, target, arguments, treePath); - } - - public MethodAccessNode getTarget() { - return target; - } - - public List getArguments() { - return arguments; - } - - public Node getArgument(int i) { - return arguments.get(i); - } - - public TreePath getTreePath() { - return treePath; - } - - @Override - public MethodInvocationTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitMethodInvocation(this, p); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(target); - sb.append("("); - boolean needComma = false; - for (Node arg : arguments) { - if (needComma) { - sb.append(", "); - } - sb.append(arg); - needComma = true; - } - sb.append(")"); - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof MethodInvocationNode)) { - return false; - } - MethodInvocationNode other = (MethodInvocationNode) obj; - - return getTarget().equals(other.getTarget()) && getArguments().equals(other.getArguments()); - } - - @Override - public int hashCode() { - int hash = 0; - hash = HashCodeUtils.hash(target); - for (Node arg : arguments) { - hash = HashCodeUtils.hash(hash, arg.hashCode()); - } - return hash; - } - - @Override - public Collection getOperands() { - List list = new LinkedList(); - list.add(target); - list.addAll(arguments); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java deleted file mode 100644 index 79a47283eb104f..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.TypesUtils; - -/** - * A node for the narrowing primitive conversion operation. See JLS 5.1.3 for the definition of - * narrowing primitive conversion. - * - *

A {@link NarrowingConversionNode} does not correspond to any tree node in the parsed AST. It - * is introduced when a value of some primitive type appears in a context that requires a different - * primitive with more bits of precision. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NarrowingConversionNode extends Node { - - protected Tree tree; - protected Node operand; - - public NarrowingConversionNode(Tree tree, Node operand, TypeMirror type) { - super(type); - assert TypesUtils.isPrimitive(type) : "non-primitive type in narrowing conversion"; - this.tree = tree; - this.operand = operand; - } - - public Node getOperand() { - return operand; - } - - @Override - public TypeMirror getType() { - return type; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNarrowingConversion(this, p); - } - - @Override - public String toString() { - return "NarrowingConversion(" + getOperand() + ", " + type + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NarrowingConversionNode)) { - return false; - } - NarrowingConversionNode other = (NarrowingConversionNode) obj; - return getOperand().equals(other.getOperand()) - && TypesUtils.areSamePrimitiveTypes(getType(), other.getType()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java deleted file mode 100644 index fb5bf5335dbbb3..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.LinkedList; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.cfg.CFGBuilder; -import org.checkerframework.dataflow.cfg.block.Block; - -/** - * A node in the abstract representation used for Java code inside a basic block. - * - *

The following invariants hold: - * - *

- * block == null || block instanceof RegularBlock || block instanceof ExceptionBlock
- * block instanceof RegularBlock ⇒ block.getContents().contains(this)
- * block instanceof ExceptionBlock ⇒ block.getNode() == this
- * block == null ⇔ "This object represents a parameter of the method."
- * 
- * - *
- * type != null
- * tree != null ⇒ node.getType() == InternalUtils.typeOf(node.getTree())
- * 
- * - * @author Stefan Heule - */ -public abstract class Node { - - /** The basic block this node belongs to (see invariant about this field above). */ - protected /*@Nullable*/ Block block; - - /** Is this node an l-value? */ - protected boolean lvalue = false; - - /** The assignment context of this node. See {@link AssignmentContext}. */ - protected /*@Nullable*/ AssignmentContext assignmentContext; - - /** - * Does this node represent a tree that appears in the source code (true) or one that the CFG - * builder added while desugaring (false). - */ - protected boolean inSource = true; - - /** - * The type of this node. For {@link Node}s with {@link Tree}s, this type is the type of the - * {@link Tree}. Otherwise, it is the type is set by the {@link CFGBuilder}. - */ - protected final TypeMirror type; - - public Node(TypeMirror type) { - assert type != null; - this.type = type; - } - - /** - * @return the basic block this node belongs to (or {@code null} if it represents the parameter - * of a method). - */ - public /*@Nullable*/ Block getBlock() { - return block; - } - - /** Set the basic block this node belongs to. */ - public void setBlock(Block b) { - block = b; - } - - /** - * Returns the {@link Tree} in the abstract syntax tree, or {@code null} if no corresponding - * tree exists. For instance, this is the case for an {@link ImplicitThisLiteralNode}. - * - * @return the corresponding {@link Tree} or {@code null}. - */ - public abstract /*@Nullable*/ Tree getTree(); - - /** - * Returns a {@link TypeMirror} representing the type of a {@link Node} A {@link Node} will - * always have a type even when it has no {@link Tree}. - * - * @return a {@link TypeMirror} representing the type of this {@link Node} - */ - public TypeMirror getType() { - return type; - } - - /** - * Accept method of the visitor pattern - * - * @param result type of the operation - * @param

parameter type - * @param visitor the visitor to be applied to this node - * @param p the parameter for this operation - */ - public abstract R accept(NodeVisitor visitor, P p); - - public boolean isLValue() { - return lvalue; - } - - /** Make this node an l-value. */ - public void setLValue() { - lvalue = true; - } - - public boolean getInSource() { - return inSource; - } - - public void setInSource(boolean inSrc) { - inSource = inSrc; - } - - public AssignmentContext getAssignmentContext() { - return assignmentContext; - } - - public void setAssignmentContext(AssignmentContext assignmentContext) { - this.assignmentContext = assignmentContext; - } - - /** @return a collection containing all of the operand {@link Node}s of this {@link Node}. */ - public abstract Collection getOperands(); - - /** - * @return a collection containing all of the operand {@link Node}s of this {@link Node}, as - * well as (transitively) the operands of its operands - */ - public Collection getTransitiveOperands() { - LinkedList operands = new LinkedList<>(getOperands()); - LinkedList transitiveOperands = new LinkedList<>(); - while (!operands.isEmpty()) { - Node next = operands.removeFirst(); - operands.addAll(next.getOperands()); - transitiveOperands.add(next); - } - return transitiveOperands; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java deleted file mode 100644 index 8a2f513924c669..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/** - * A visitor for a {@link Node} tree. - * - * @author Stefan Heule - * @param return type of the visitor. Use {@link Void} if the visitor does not have a return - * value. - * @param

parameter type of the visitor. Use {@link Void} if the visitor does not have a - * parameter. - */ -public interface NodeVisitor { - // Literals - R visitShortLiteral(ShortLiteralNode n, P p); - - R visitIntegerLiteral(IntegerLiteralNode n, P p); - - R visitLongLiteral(LongLiteralNode n, P p); - - R visitFloatLiteral(FloatLiteralNode n, P p); - - R visitDoubleLiteral(DoubleLiteralNode n, P p); - - R visitBooleanLiteral(BooleanLiteralNode n, P p); - - R visitCharacterLiteral(CharacterLiteralNode n, P p); - - R visitStringLiteral(StringLiteralNode n, P p); - - R visitNullLiteral(NullLiteralNode n, P p); - - // Unary operations - R visitNumericalMinus(NumericalMinusNode n, P p); - - R visitNumericalPlus(NumericalPlusNode n, P p); - - R visitBitwiseComplement(BitwiseComplementNode n, P p); - - R visitNullChk(NullChkNode n, P p); - - // Binary operations - R visitStringConcatenate(StringConcatenateNode n, P p); - - R visitNumericalAddition(NumericalAdditionNode n, P p); - - R visitNumericalSubtraction(NumericalSubtractionNode n, P p); - - R visitNumericalMultiplication(NumericalMultiplicationNode n, P p); - - R visitIntegerDivision(IntegerDivisionNode n, P p); - - R visitFloatingDivision(FloatingDivisionNode n, P p); - - R visitIntegerRemainder(IntegerRemainderNode n, P p); - - R visitFloatingRemainder(FloatingRemainderNode n, P p); - - R visitLeftShift(LeftShiftNode n, P p); - - R visitSignedRightShift(SignedRightShiftNode n, P p); - - R visitUnsignedRightShift(UnsignedRightShiftNode n, P p); - - R visitBitwiseAnd(BitwiseAndNode n, P p); - - R visitBitwiseOr(BitwiseOrNode n, P p); - - R visitBitwiseXor(BitwiseXorNode n, P p); - - // Compound assignments - R visitStringConcatenateAssignment(StringConcatenateAssignmentNode n, P p); - - // Comparison operations - R visitLessThan(LessThanNode n, P p); - - R visitLessThanOrEqual(LessThanOrEqualNode n, P p); - - R visitGreaterThan(GreaterThanNode n, P p); - - R visitGreaterThanOrEqual(GreaterThanOrEqualNode n, P p); - - R visitEqualTo(EqualToNode n, P p); - - R visitNotEqual(NotEqualNode n, P p); - - // Conditional operations - R visitConditionalAnd(ConditionalAndNode n, P p); - - R visitConditionalOr(ConditionalOrNode n, P p); - - R visitConditionalNot(ConditionalNotNode n, P p); - - R visitTernaryExpression(TernaryExpressionNode n, P p); - - R visitAssignment(AssignmentNode n, P p); - - R visitLocalVariable(LocalVariableNode n, P p); - - R visitVariableDeclaration(VariableDeclarationNode n, P p); - - R visitFieldAccess(FieldAccessNode n, P p); - - R visitMethodAccess(MethodAccessNode n, P p); - - R visitArrayAccess(ArrayAccessNode n, P p); - - R visitImplicitThisLiteral(ImplicitThisLiteralNode n, P p); - - R visitExplicitThisLiteral(ExplicitThisLiteralNode n, P p); - - R visitSuper(SuperNode n, P p); - - R visitReturn(ReturnNode n, P p); - - R visitStringConversion(StringConversionNode n, P p); - - R visitNarrowingConversion(NarrowingConversionNode n, P p); - - R visitWideningConversion(WideningConversionNode n, P p); - - R visitInstanceOf(InstanceOfNode n, P p); - - R visitTypeCast(TypeCastNode n, P p); - - // Blocks - - R visitSynchronized(SynchronizedNode n, P p); - - // Statements - R visitAssertionError(AssertionErrorNode n, P p); - - R visitThrow(ThrowNode n, P p); - - // Cases - R visitCase(CaseNode n, P p); - - // Method and constructor invocations - R visitMethodInvocation(MethodInvocationNode n, P p); - - R visitObjectCreation(ObjectCreationNode n, P p); - - R visitMemberReference(FunctionalInterfaceNode n, P p); - - R visitArrayCreation(ArrayCreationNode n, P p); - - // Type, package and class names - R visitArrayType(ArrayTypeNode n, P p); - - R visitPrimitiveType(PrimitiveTypeNode n, P p); - - R visitClassName(ClassNameNode n, P p); - - R visitPackageName(PackageNameNode n, P p); - - // Parameterized types - R visitParameterizedType(ParameterizedTypeNode n, P p); - - // Marker nodes - R visitMarker(MarkerNode n, P p); -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java deleted file mode 100644 index debd7cbaf0b9ad..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the not equal comparison: - * - *

- *   expression != expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NotEqualNode extends BinaryOperationNode { - - public NotEqualNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.NOT_EQUAL_TO; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNotEqual(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " != " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NotEqualNode)) { - return false; - } - NotEqualNode other = (NotEqualNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java deleted file mode 100644 index 6609a29b598cdc..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for the unary 'nullchk' operation (generated by the Java compiler): - * - *
- *   <*nullchk*>expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NullChkNode extends Node { - - protected Tree tree; - protected Node operand; - - public NullChkNode(Tree tree, Node operand) { - super(InternalUtils.typeOf(tree)); - assert tree.getKind() == Kind.OTHER; - this.tree = tree; - this.operand = operand; - } - - public Node getOperand() { - return operand; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNullChk(this, p); - } - - @Override - public String toString() { - return "(+ " + getOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NumericalPlusNode)) { - return false; - } - NumericalPlusNode other = (NumericalPlusNode) obj; - return getOperand().equals(other.getOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java deleted file mode 100644 index 1fcdeb4825a295..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for the null literal. - * - *
- *   null
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NullLiteralNode extends ValueLiteralNode { - - public NullLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.NULL_LITERAL); - } - - @Override - public Void getValue() { - return (Void) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNullLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a NullLiteralNode - if (obj == null || !(obj instanceof NullLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java deleted file mode 100644 index 4692856dd8bc21..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the numerical addition: - * - *
- *   expression + expression
- * 
- * - * @author Stefan Heule - */ -public class NumericalAdditionNode extends BinaryOperationNode { - - public NumericalAdditionNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.PLUS || tree.getKind() == Kind.PLUS_ASSIGNMENT; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNumericalAddition(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " + " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NumericalAdditionNode)) { - return false; - } - NumericalAdditionNode other = (NumericalAdditionNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java deleted file mode 100644 index 141ab580e0af8f..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.UnaryTree; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the unary minus operation: - * - *
- *   - expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NumericalMinusNode extends UnaryOperationNode { - - public NumericalMinusNode(UnaryTree tree, Node operand) { - super(tree, operand); - assert tree.getKind() == Kind.UNARY_MINUS; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNumericalMinus(this, p); - } - - @Override - public String toString() { - return "(- " + getOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NumericalMinusNode)) { - return false; - } - NumericalMinusNode other = (NumericalMinusNode) obj; - return getOperand().equals(other.getOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java deleted file mode 100644 index 85561a1a024668..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the numerical multiplication: - * - *
- *   expression * expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NumericalMultiplicationNode extends BinaryOperationNode { - - public NumericalMultiplicationNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.MULTIPLY; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNumericalMultiplication(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " * " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NumericalMultiplicationNode)) { - return false; - } - NumericalMultiplicationNode other = (NumericalMultiplicationNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java deleted file mode 100644 index 21b5b584d23772..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.UnaryTree; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the unary plus operation: - * - *
- *   + expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NumericalPlusNode extends UnaryOperationNode { - - public NumericalPlusNode(UnaryTree tree, Node operand) { - super(tree, operand); - assert tree.getKind() == Kind.UNARY_PLUS; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNumericalPlus(this, p); - } - - @Override - public String toString() { - return "(+ " + getOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NumericalPlusNode)) { - return false; - } - NumericalPlusNode other = (NumericalPlusNode) obj; - return getOperand().equals(other.getOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java deleted file mode 100644 index a962eadd788110..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the numerical subtraction: - * - *
- *   expression - expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class NumericalSubtractionNode extends BinaryOperationNode { - - public NumericalSubtractionNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.MINUS; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitNumericalSubtraction(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " - " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof NumericalSubtractionNode)) { - return false; - } - NumericalSubtractionNode other = (NumericalSubtractionNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java deleted file mode 100644 index 8ab862a2efc79b..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.NewClassTree; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for new object creation - * - *
- *   new constructor(arg1, arg2, ...)
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ObjectCreationNode extends Node { - - protected NewClassTree tree; - protected Node constructor; - protected List arguments; - - public ObjectCreationNode(NewClassTree tree, Node constructor, List arguments) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - this.constructor = constructor; - this.arguments = arguments; - } - - public Node getConstructor() { - return constructor; - } - - public List getArguments() { - return arguments; - } - - public Node getArgument(int i) { - return arguments.get(i); - } - - @Override - public NewClassTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitObjectCreation(this, p); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append("new " + constructor + "("); - boolean needComma = false; - for (Node arg : arguments) { - if (needComma) { - sb.append(", "); - } - sb.append(arg); - needComma = true; - } - sb.append(")"); - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ObjectCreationNode)) { - return false; - } - ObjectCreationNode other = (ObjectCreationNode) obj; - if (constructor == null && other.getConstructor() != null) { - return false; - } - - return getConstructor().equals(other.getConstructor()) - && getArguments().equals(other.getArguments()); - } - - @Override - public int hashCode() { - int hash = HashCodeUtils.hash(constructor); - for (Node arg : arguments) { - hash = HashCodeUtils.hash(hash, arg.hashCode()); - } - return hash; - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(constructor); - list.addAll(arguments); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java deleted file mode 100644 index 3c69b8252b36ce..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.element.Element; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TreeUtils; - -/** - * A node representing a package name used in an expression such as a constructor invocation - * - *

package.class.object(...) - * - *

parent.package.class.object(...) - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class PackageNameNode extends Node { - - protected final Tree tree; - /** The package named by this node */ - protected final Element element; - - /** The parent name, if any. */ - protected final /*@Nullable*/ PackageNameNode parent; - - public PackageNameNode(IdentifierTree tree) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - this.element = TreeUtils.elementFromUse(tree); - this.parent = null; - } - - public PackageNameNode(MemberSelectTree tree, PackageNameNode parent) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - this.element = TreeUtils.elementFromUse(tree); - this.parent = parent; - } - - public Element getElement() { - return element; - } - - public PackageNameNode getParent() { - return parent; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitPackageName(this, p); - } - - @Override - public String toString() { - return getElement().getSimpleName().toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof PackageNameNode)) { - return false; - } - PackageNameNode other = (PackageNameNode) obj; - if (getParent() == null) { - return other.getParent() == null && getElement().equals(other.getElement()); - } else { - return getParent().equals(other.getParent()) && getElement().equals(other.getElement()); - } - } - - @Override - public int hashCode() { - if (parent == null) { - return HashCodeUtils.hash(getElement()); - } - return HashCodeUtils.hash(getElement(), getParent()); - } - - @Override - public Collection getOperands() { - if (parent == null) { - return Collections.emptyList(); - } - return Collections.singleton((Node) parent); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java deleted file mode 100644 index 774ac8b7c5439a..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ParameterizedTypeTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a parameterized type occurring in an expression: - * - *

- *   type<arg1, arg2>
- * 
- * - * Parameterized types don't represent any computation to be done at runtime, so we might choose to - * represent them differently by modifying the {@link Node}s in which parameterized types can occur, - * such as {@link ObjectCreationNode}s. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ParameterizedTypeNode extends Node { - - protected Tree tree; - - public ParameterizedTypeNode(Tree t) { - super(InternalUtils.typeOf(t)); - assert t instanceof ParameterizedTypeTree; - tree = t; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitParameterizedType(this, p); - } - - @Override - public String toString() { - return getTree().toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ParameterizedTypeNode)) { - return false; - } - ParameterizedTypeNode other = (ParameterizedTypeNode) obj; - return getTree().equals(other.getTree()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getTree()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java deleted file mode 100644 index 379bb9202423a7..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.PrimitiveTypeTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node representing a primitive type used in an expression such as a field access - * - *

type .class - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class PrimitiveTypeNode extends Node { - - protected final PrimitiveTypeTree tree; - - public PrimitiveTypeNode(PrimitiveTypeTree tree) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitPrimitiveType(this, p); - } - - @Override - public String toString() { - return tree.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof PrimitiveTypeNode)) { - return false; - } - PrimitiveTypeNode other = (PrimitiveTypeNode) obj; - return getType().equals(other.getType()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getType()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java deleted file mode 100644 index b7222dfa1818b0..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import com.sun.source.tree.LambdaExpressionTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.ReturnTree; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.cfg.node.AssignmentContext.LambdaReturnContext; -import org.checkerframework.dataflow.cfg.node.AssignmentContext.MethodReturnContext; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for a return statement: - * - *

- *   return
- *   return expression
- * 
- * - * @author Stefan Heule - */ -public class ReturnNode extends Node { - - protected ReturnTree tree; - protected /*@Nullable*/ Node result; - - public ReturnNode(ReturnTree t, /*@Nullable*/ Node result, Types types, MethodTree methodTree) { - super(types.getNoType(TypeKind.NONE)); - this.result = result; - tree = t; - result.setAssignmentContext(new MethodReturnContext(methodTree)); - } - - public ReturnNode( - ReturnTree t, - /*@Nullable*/ Node result, - Types types, - LambdaExpressionTree lambda, - MethodSymbol methodSymbol) { - super(types.getNoType(TypeKind.NONE)); - this.result = result; - tree = t; - result.setAssignmentContext(new LambdaReturnContext(methodSymbol)); - } - - public Node getResult() { - return result; - } - - @Override - public ReturnTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitReturn(this, p); - } - - @Override - public String toString() { - if (result != null) { - return "return " + result; - } - return "return"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ReturnNode)) { - return false; - } - ReturnNode other = (ReturnNode) obj; - if ((result == null) != (other.result == null)) { - return false; - } - return (result == null || result.equals(other.result)); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(result); - } - - @Override - public Collection getOperands() { - if (result == null) { - return Collections.emptyList(); - } else { - return Collections.singletonList(result); - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java deleted file mode 100644 index cd1db1e5609e50..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for a short literal. For example: - * - *
- *   5
- *   0x8fff
- * 
- * - * Java source and the AST representation do not have "short" literals. They have integer literals - * that may be narrowed to shorts depending on context. If we use explicit NarrowingConversionNodes, - * do we need ShortLiteralNodes too? TODO: Decide this question. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ShortLiteralNode extends ValueLiteralNode { - - public ShortLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.INT_LITERAL); - } - - @Override - public Short getValue() { - return (Short) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitShortLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a ShortLiteralNode - if (obj == null || !(obj instanceof ShortLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java deleted file mode 100644 index ac4aa5878349c6..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for bitwise right shift operations with sign extension: - * - *
- *   expression >> expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class SignedRightShiftNode extends BinaryOperationNode { - - public SignedRightShiftNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.RIGHT_SHIFT; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitSignedRightShift(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " >> " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof SignedRightShiftNode)) { - return false; - } - SignedRightShiftNode other = (SignedRightShiftNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java deleted file mode 100644 index 0e6f006d7e7595..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import java.util.Collection; -import java.util.LinkedList; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for the string concatenation compound assignment: - * - *
- *   variable += expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class StringConcatenateAssignmentNode extends Node { - protected Tree tree; - protected Node left; - protected Node right; - - public StringConcatenateAssignmentNode(Tree tree, Node left, Node right) { - super(InternalUtils.typeOf(tree)); - assert tree.getKind() == Kind.PLUS_ASSIGNMENT; - this.tree = tree; - this.left = left; - this.right = right; - } - - public Node getLeftOperand() { - return left; - } - - public Node getRightOperand() { - return right; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitStringConcatenateAssignment(this, p); - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getLeftOperand()); - list.add(getRightOperand()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java deleted file mode 100644 index c69beea694c970..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for string concatenation: - * - *
- *   expression + expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class StringConcatenateNode extends BinaryOperationNode { - - public StringConcatenateNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.PLUS; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitStringConcatenate(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " + " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof StringConcatenateNode)) { - return false; - } - StringConcatenateNode other = (StringConcatenateNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java deleted file mode 100644 index 8ba8c6ff60e9a1..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the string conversion operation. See JLS 5.1.11 for the definition of string - * conversion. - * - *

A {@link StringConversionNode} does not correspond to any tree node in the parsed AST. It is - * introduced when a value of non-string type appears in a context that requires a {@link String}, - * such as in a string concatenation. A {@link StringConversionNode} should be treated as a - * potential call to the toString method of its operand, but does not necessarily call any method - * because null is converted to the string "null". - * - *

Conversion of primitive types to Strings requires first boxing and then string conversion. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class StringConversionNode extends Node { - - protected Tree tree; - protected Node operand; - - // TODO: The type of a string conversion should be a final - // TypeMirror representing java.lang.String. Currently we require - // the caller to pass in a TypeMirror instead of creating one - // through the javax.lang.model.type.Types interface. - public StringConversionNode(Tree tree, Node operand, TypeMirror type) { - super(type); - this.tree = tree; - this.operand = operand; - } - - public Node getOperand() { - return operand; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitStringConversion(this, p); - } - - @Override - public String toString() { - return "StringConversion(" + getOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof StringConversionNode)) { - return false; - } - StringConversionNode other = (StringConversionNode) obj; - return getOperand().equals(other.getOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java deleted file mode 100644 index c6ec1c90b87b71..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; - -/** - * A node for an string literal. For example: - * - *

- *   "abc"
- * 
- * - * @author Stefan Heule - */ -public class StringLiteralNode extends ValueLiteralNode { - - public StringLiteralNode(LiteralTree t) { - super(t); - assert t.getKind().equals(Tree.Kind.STRING_LITERAL); - } - - @Override - public String getValue() { - return (String) tree.getValue(); - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitStringLiteral(this, p); - } - - @Override - public boolean equals(Object obj) { - // test that obj is a StringLiteralNode - if (!(obj instanceof StringLiteralNode)) { - return false; - } - // super method compares values - return super.equals(obj); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } - - @Override - public String toString() { - return "\"" + super.toString() + "\""; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java deleted file mode 100644 index 797eae8e7a8d20..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a reference to 'super'. - * - *
- *   super
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class SuperNode extends Node { - - protected Tree tree; - - public SuperNode(Tree t) { - super(InternalUtils.typeOf(t)); - assert t instanceof IdentifierTree && ((IdentifierTree) t).getName().contentEquals("super"); - tree = t; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitSuper(this, p); - } - - public String getName() { - return "super"; - } - - @Override - public String toString() { - return getName(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof SuperNode)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getName()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java deleted file mode 100644 index a17e2fa2e80a32..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -/* - * This represents the start and end of synchronized code block. - * If startOfBlock == true it is the node preceding a synchronized code block. - * Otherwise it is the node immediately after a synchronized code block. - */ - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.util.HashCodeUtils; - -public class SynchronizedNode extends Node { - - protected /*@Nullable*/ Tree tree; - protected Node expression; - protected boolean startOfBlock; - - public SynchronizedNode( - /*@Nullable*/ Tree tree, Node expression, boolean startOfBlock, Types types) { - super(types.getNoType(TypeKind.NONE)); - this.tree = tree; - this.expression = expression; - this.startOfBlock = startOfBlock; - } - - @Override - public Tree getTree() { - return tree; - } - - public Node getExpression() { - return expression; - } - - public boolean getIsStartOfBlock() { - return startOfBlock; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitSynchronized(this, p); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append("synchronized "); - sb.append("(" + expression + ")"); - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof SynchronizedNode)) { - return false; - } - SynchronizedNode other = (SynchronizedNode) obj; - if (tree == null && other.getTree() != null) { - return false; - } - - return getTree().equals(other.getTree()) - && getExpression().equals(other.getExpression()) - && startOfBlock == other.startOfBlock; - } - - @Override - public int hashCode() { - int hash = 0; - if (tree != null) { - hash = HashCodeUtils.hash(tree); - } - hash = HashCodeUtils.hash(startOfBlock); - return HashCodeUtils.hash(hash, getExpression()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java deleted file mode 100644 index 9a149a33259714..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ConditionalExpressionTree; -import com.sun.source.tree.Tree.Kind; -import java.util.Collection; -import java.util.LinkedList; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a conditional expression: - * - *
- *   expression ? expression : expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class TernaryExpressionNode extends Node { - - protected ConditionalExpressionTree tree; - protected Node condition; - protected Node thenOperand; - protected Node elseOperand; - - public TernaryExpressionNode( - ConditionalExpressionTree tree, Node condition, Node thenOperand, Node elseOperand) { - super(InternalUtils.typeOf(tree)); - assert tree.getKind().equals(Kind.CONDITIONAL_EXPRESSION); - this.tree = tree; - this.condition = condition; - this.thenOperand = thenOperand; - this.elseOperand = elseOperand; - } - - public Node getConditionOperand() { - return condition; - } - - public Node getThenOperand() { - return thenOperand; - } - - public Node getElseOperand() { - return elseOperand; - } - - @Override - public ConditionalExpressionTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitTernaryExpression(this, p); - } - - @Override - public String toString() { - return "(" - + getConditionOperand() - + " ? " - + getThenOperand() - + " : " - + getElseOperand() - + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof TernaryExpressionNode)) { - return false; - } - TernaryExpressionNode other = (TernaryExpressionNode) obj; - return getConditionOperand().equals(other.getConditionOperand()) - && getThenOperand().equals(other.getThenOperand()) - && getElseOperand().equals(other.getElseOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getConditionOperand(), getThenOperand(), getElseOperand()); - } - - @Override - public Collection getOperands() { - LinkedList list = new LinkedList(); - list.add(getConditionOperand()); - list.add(getThenOperand()); - list.add(getElseOperand()); - return list; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java deleted file mode 100644 index 3bb4c186e6dbb1..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for a reference to 'this', either implicit or explicit. - * - *
- *   this
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public abstract class ThisLiteralNode extends Node { - - public ThisLiteralNode(TypeMirror type) { - super(type); - } - - public String getName() { - return "this"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ThisLiteralNode)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getName()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java deleted file mode 100644 index bb36e10a4a1da2..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.ThrowTree; -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.Types; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for exception throws: - * - *
- *   throw expr
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class ThrowNode extends Node { - - protected ThrowTree tree; - protected Node expression; - - public ThrowNode(ThrowTree tree, Node expression, Types types) { - super(types.getNoType(TypeKind.NONE)); - this.tree = tree; - this.expression = expression; - } - - public Node getExpression() { - return expression; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitThrow(this, p); - } - - @Override - public String toString() { - return "throw " + expression; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ThrowNode)) { - return false; - } - ThrowNode other = (ThrowNode) obj; - return getExpression().equals(other.getExpression()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(expression); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(expression); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java deleted file mode 100644 index f6e71bf6aac0d9..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for the cast operator: - * - *

(Point) x - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class TypeCastNode extends Node { - - protected Tree tree; - protected Node operand; - - public TypeCastNode(Tree tree, Node operand, TypeMirror type) { - super(type); - this.tree = tree; - this.operand = operand; - } - - public Node getOperand() { - return operand; - } - - @Override - public TypeMirror getType() { - return type; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitTypeCast(this, p); - } - - @Override - public String toString() { - return "(" + getType() + ")" + getOperand(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof TypeCastNode)) { - return false; - } - TypeCastNode other = (TypeCastNode) obj; - // TODO: TypeMirror.equals may be too restrictive. - // Check whether Types.isSameType is the better comparison. - return getOperand().equals(other.getOperand()) && getType().equals(other.getType()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java deleted file mode 100644 index cb33e6a3f16b97..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.UnaryTree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a postfix or an unary expression. - * - *

For example: - * - *

- *   operator expressionNode
- *
- *   expressionNode operator
- * 
- * - * @author charleszhuochen - */ -public abstract class UnaryOperationNode extends Node { - - protected final UnaryTree tree; - protected final Node operand; - - public UnaryOperationNode(UnaryTree tree, Node operand) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - this.operand = operand; - } - - public Node getOperand() { - return this.operand; - } - - @Override - public UnaryTree getTree() { - return tree; - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java deleted file mode 100644 index 2609a7d7aee31c..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.Tree.Kind; -import org.checkerframework.dataflow.util.HashCodeUtils; - -/** - * A node for bitwise right shift operations with zero extension: - * - *
- *   expression >>> expression
- * 
- * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class UnsignedRightShiftNode extends BinaryOperationNode { - - public UnsignedRightShiftNode(BinaryTree tree, Node left, Node right) { - super(tree, left, right); - assert tree.getKind() == Kind.UNSIGNED_RIGHT_SHIFT; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitUnsignedRightShift(this, p); - } - - @Override - public String toString() { - return "(" + getLeftOperand() + " >>> " + getRightOperand() + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof UnsignedRightShiftNode)) { - return false; - } - UnsignedRightShiftNode other = (UnsignedRightShiftNode) obj; - return getLeftOperand().equals(other.getLeftOperand()) - && getRightOperand().equals(other.getRightOperand()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getLeftOperand(), getRightOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java deleted file mode 100644 index 4c9c18f0aff198..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.LiteralTree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -/** - * A node for a literals that have some form of value: - * - *
    - *
  • integer literal - *
  • long literal - *
  • char literal - *
  • string literal - *
  • float literal - *
  • double literal - *
  • boolean literal - *
  • null literal - *
- * - * @author Stefan Heule - */ -public abstract class ValueLiteralNode extends Node { - - protected final LiteralTree tree; - - /** @return the value of the literal */ - public abstract /*@Nullable*/ Object getValue(); - - public ValueLiteralNode(LiteralTree tree) { - super(InternalUtils.typeOf(tree)); - this.tree = tree; - } - - @Override - public LiteralTree getTree() { - return tree; - } - - @Override - public String toString() { - return String.valueOf(getValue()); - } - - /** Compare the value of this nodes. */ - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ValueLiteralNode)) { - return false; - } - ValueLiteralNode other = (ValueLiteralNode) obj; - Object val = getValue(); - Object otherVal = other.getValue(); - return ((val == null || otherVal == null) && val == otherVal) || val.equals(otherVal); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getValue()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java deleted file mode 100644 index 867cdf1ad99706..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.VariableTree; -import java.util.Collection; -import java.util.Collections; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.InternalUtils; - -/** - * A node for a local variable declaration: - * - *
- *   modifier type identifier;
- * 
- * - * Note: Does not have an initializer block, as that will be translated to a separate {@link - * AssignmentNode}. - * - * @author Stefan Heule - */ -public class VariableDeclarationNode extends Node { - - protected VariableTree tree; - protected String name; - - // TODO: make modifier accessible - - public VariableDeclarationNode(VariableTree t) { - super(InternalUtils.typeOf(t)); - tree = t; - name = tree.getName().toString(); - } - - public String getName() { - return name; - } - - @Override - public VariableTree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitVariableDeclaration(this, p); - } - - @Override - public String toString() { - return name; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof VariableDeclarationNode)) { - return false; - } - VariableDeclarationNode other = (VariableDeclarationNode) obj; - return getName().equals(other.getName()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getName()); - } - - @Override - public Collection getOperands() { - return Collections.emptyList(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java deleted file mode 100644 index 9b949ea5467645..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.checkerframework.dataflow.cfg.node; - -import com.sun.source.tree.Tree; -import java.util.Collection; -import java.util.Collections; -import javax.lang.model.type.TypeMirror; -import org.checkerframework.dataflow.util.HashCodeUtils; -import org.checkerframework.javacutil.TypesUtils; - -/** - * A node for the widening primitive conversion operation. See JLS 5.1.2 for the definition of - * widening primitive conversion. - * - *

A {@link WideningConversionNode} does not correspond to any tree node in the parsed AST. It is - * introduced when a value of some primitive type appears in a context that requires a different - * primitive with more bits of precision. - * - * @author Stefan Heule - * @author Charlie Garrett - */ -public class WideningConversionNode extends Node { - - protected Tree tree; - protected Node operand; - - public WideningConversionNode(Tree tree, Node operand, TypeMirror type) { - super(type); - assert TypesUtils.isPrimitive(type) : "non-primitive type in widening conversion"; - this.tree = tree; - this.operand = operand; - } - - public Node getOperand() { - return operand; - } - - @Override - public TypeMirror getType() { - return type; - } - - @Override - public Tree getTree() { - return tree; - } - - @Override - public R accept(NodeVisitor visitor, P p) { - return visitor.visitWideningConversion(this, p); - } - - @Override - public String toString() { - return "WideningConversion(" + getOperand() + ", " + type + ")"; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof WideningConversionNode)) { - return false; - } - WideningConversionNode other = (WideningConversionNode) obj; - return getOperand().equals(other.getOperand()) - && TypesUtils.areSamePrimitiveTypes(getType(), other.getType()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getOperand()); - } - - @Override - public Collection getOperands() { - return Collections.singletonList(getOperand()); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java deleted file mode 100644 index 79088386a9a3e3..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.checkerframework.dataflow.cfg.playground; - -import org.checkerframework.dataflow.analysis.Analysis; -import org.checkerframework.dataflow.cfg.JavaSource2CFGDOT; -import org.checkerframework.dataflow.constantpropagation.Constant; -import org.checkerframework.dataflow.constantpropagation.ConstantPropagationStore; -import org.checkerframework.dataflow.constantpropagation.ConstantPropagationTransfer; - -public class ConstantPropagationPlayground { - - /** Run constant propagation for a specific file and create a PDF of the CFG in the end. */ - public static void main(String[] args) { - - /* Configuration: change as appropriate */ - String inputFile = "cfg-input.java"; // input file name and path - String outputDir = "cfg"; // output directory - String method = "test"; // name of the method to analyze - String clazz = "Test"; // name of the class to consider - - // run the analysis and create a PDF file - ConstantPropagationTransfer transfer = new ConstantPropagationTransfer(); - // TODO: correct processing environment - Analysis analysis = - new Analysis<>(null, transfer); - JavaSource2CFGDOT.generateDOTofCFG(inputFile, outputDir, method, clazz, true, analysis); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java deleted file mode 100644 index a95af7fa435111..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.checkerframework.dataflow.constantpropagation; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import java.util.Objects; -import org.checkerframework.dataflow.analysis.AbstractValue; - -public class Constant implements AbstractValue { - - /** What kind of abstract value is this? */ - protected Type type; - - /** The value of this abstract value (or null) */ - protected /*@Nullable*/ Integer value; - - public enum Type { - CONSTANT, - TOP, - BOTTOM, - } - - public Constant(Type type) { - assert !type.equals(Type.CONSTANT); - this.type = type; - } - - public Constant(Integer value) { - this.type = Type.CONSTANT; - this.value = value; - } - - public boolean isTop() { - return type.equals(Type.TOP); - } - - public boolean isBottom() { - return type.equals(Type.BOTTOM); - } - - public boolean isConstant() { - return type.equals(Type.CONSTANT); - } - - public Integer getValue() { - assert isConstant(); - return value; - } - - public Constant copy() { - if (isConstant()) { - return new Constant(value); - } - return new Constant(type); - } - - @Override - public Constant leastUpperBound(Constant other) { - if (other.isBottom()) { - return this.copy(); - } - if (this.isBottom()) { - return other.copy(); - } - if (other.isTop() || this.isTop()) { - return new Constant(Type.TOP); - } - if (other.getValue().equals(getValue())) { - return this.copy(); - } - return new Constant(Type.TOP); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof Constant)) { - return false; - } - Constant other = (Constant) obj; - return type == other.type && Objects.equals(value, other.value); - } - - @Override - public int hashCode() { - return type.hashCode() + (value != null ? value.hashCode() : 0); - } - - @Override - public String toString() { - switch (type) { - case TOP: - return "T"; - case BOTTOM: - return "-"; - case CONSTANT: - return value.toString(); - } - assert false; - return "???"; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java deleted file mode 100644 index e7a718ee5bd2fb..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.checkerframework.dataflow.constantpropagation; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import org.checkerframework.dataflow.analysis.FlowExpressions; -import org.checkerframework.dataflow.analysis.Store; -import org.checkerframework.dataflow.cfg.CFGVisualizer; -import org.checkerframework.dataflow.cfg.node.IntegerLiteralNode; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.constantpropagation.Constant.Type; - -public class ConstantPropagationStore implements Store { - - /** Information about variables gathered so far. */ - Map contents; - - public ConstantPropagationStore() { - contents = new HashMap<>(); - } - - protected ConstantPropagationStore(Map contents) { - this.contents = contents; - } - - public Constant getInformation(Node n) { - if (contents.containsKey(n)) { - return contents.get(n); - } - return new Constant(Type.TOP); - } - - public void mergeInformation(Node n, Constant val) { - Constant value; - if (contents.containsKey(n)) { - value = val.leastUpperBound(contents.get(n)); - } else { - value = val; - } - // TODO: remove (only two nodes supported atm) - assert n instanceof IntegerLiteralNode || n instanceof LocalVariableNode; - contents.put(n, value); - } - - public void setInformation(Node n, Constant val) { - // TODO: remove (only two nodes supported atm) - assert n instanceof IntegerLiteralNode || n instanceof LocalVariableNode; - contents.put(n, val); - } - - @Override - public ConstantPropagationStore copy() { - return new ConstantPropagationStore(new HashMap<>(contents)); - } - - @Override - public ConstantPropagationStore leastUpperBound(ConstantPropagationStore other) { - Map newContents = new HashMap<>(); - - // go through all of the information of the other class - for (Entry e : other.contents.entrySet()) { - Node n = e.getKey(); - Constant otherVal = e.getValue(); - if (contents.containsKey(n)) { - // merge if both contain information about a variable - newContents.put(n, otherVal.leastUpperBound(contents.get(n))); - } else { - // add new information - newContents.put(n, otherVal); - } - } - - for (Entry e : contents.entrySet()) { - Node n = e.getKey(); - Constant thisVal = e.getValue(); - if (!other.contents.containsKey(n)) { - // add new information - newContents.put(n, thisVal); - } - } - - return new ConstantPropagationStore(newContents); - } - - @Override - public ConstantPropagationStore widenedUpperBound(ConstantPropagationStore previous) { - return leastUpperBound(previous); - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (!(o instanceof ConstantPropagationStore)) { - return false; - } - ConstantPropagationStore other = (ConstantPropagationStore) o; - // go through all of the information of the other object - for (Entry e : other.contents.entrySet()) { - Node n = e.getKey(); - Constant otherVal = e.getValue(); - if (otherVal.isBottom()) { - continue; // no information - } - if (contents.containsKey(n)) { - if (!otherVal.equals(contents.get(n))) { - return false; - } - } else { - return false; - } - } - // go through all of the information of the this object - for (Entry e : contents.entrySet()) { - Node n = e.getKey(); - Constant thisVal = e.getValue(); - if (thisVal.isBottom()) { - continue; // no information - } - if (other.contents.containsKey(n)) { - continue; - } else { - return false; - } - } - return true; - } - - @Override - public int hashCode() { - int s = 0; - for (Entry e : contents.entrySet()) { - if (!e.getValue().isBottom()) { - s += e.hashCode(); - } - } - return s; - } - - @Override - public String toString() { - // only output local variable information - Map smallerContents = new HashMap<>(); - for (Entry e : contents.entrySet()) { - if (e.getKey() instanceof LocalVariableNode) { - smallerContents.put(e.getKey(), e.getValue()); - } - } - return smallerContents.toString(); - } - - @Override - public boolean canAlias(FlowExpressions.Receiver a, FlowExpressions.Receiver b) { - return true; - } - - @Override - public void visualize(CFGVisualizer viz) { - // Do nothing since ConstantPropagationStore doesn't support visualize - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java deleted file mode 100644 index d5da13a51875f9..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.checkerframework.dataflow.constantpropagation; - -import java.util.List; -import org.checkerframework.dataflow.analysis.ConditionalTransferResult; -import org.checkerframework.dataflow.analysis.RegularTransferResult; -import org.checkerframework.dataflow.analysis.TransferFunction; -import org.checkerframework.dataflow.analysis.TransferInput; -import org.checkerframework.dataflow.analysis.TransferResult; -import org.checkerframework.dataflow.cfg.UnderlyingAST; -import org.checkerframework.dataflow.cfg.node.AbstractNodeVisitor; -import org.checkerframework.dataflow.cfg.node.AssignmentNode; -import org.checkerframework.dataflow.cfg.node.EqualToNode; -import org.checkerframework.dataflow.cfg.node.IntegerLiteralNode; -import org.checkerframework.dataflow.cfg.node.LocalVariableNode; -import org.checkerframework.dataflow.cfg.node.Node; - -public class ConstantPropagationTransfer - extends AbstractNodeVisitor< - TransferResult, - TransferInput> - implements TransferFunction { - - @Override - public ConstantPropagationStore initialStore( - UnderlyingAST underlyingAST, List parameters) { - ConstantPropagationStore store = new ConstantPropagationStore(); - return store; - } - - @Override - public TransferResult visitLocalVariable( - LocalVariableNode node, TransferInput before) { - ConstantPropagationStore store = before.getRegularStore(); - Constant value = store.getInformation(node); - return new RegularTransferResult<>(value, store); - } - - @Override - public TransferResult visitNode( - Node n, TransferInput p) { - return new RegularTransferResult<>(null, p.getRegularStore()); - } - - @Override - public TransferResult visitAssignment( - AssignmentNode n, TransferInput pi) { - ConstantPropagationStore p = pi.getRegularStore(); - Node target = n.getTarget(); - Constant info = null; - if (target instanceof LocalVariableNode) { - LocalVariableNode t = (LocalVariableNode) target; - info = p.getInformation(n.getExpression()); - p.setInformation(t, info); - } - return new RegularTransferResult<>(info, p); - } - - @Override - public TransferResult visitIntegerLiteral( - IntegerLiteralNode n, TransferInput pi) { - ConstantPropagationStore p = pi.getRegularStore(); - Constant c = new Constant(n.getValue()); - p.setInformation(n, c); - return new RegularTransferResult<>(c, p); - } - - @Override - public TransferResult visitEqualTo( - EqualToNode n, TransferInput pi) { - ConstantPropagationStore p = pi.getRegularStore(); - ConstantPropagationStore old = p.copy(); - Node left = n.getLeftOperand(); - Node right = n.getRightOperand(); - process(p, left, right); - process(p, right, left); - return new ConditionalTransferResult<>(null, p, old); - } - - protected void process(ConstantPropagationStore p, Node a, Node b) { - Constant val = p.getInformation(a); - if (b instanceof LocalVariableNode && val.isConstant()) { - p.setInformation(b, val); - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java deleted file mode 100644 index 7e7d8b9cdc17e8..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.checkerframework.dataflow.qual; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A method is called deterministic if it returns the same value (according to {@code ==}) - * every time it is called with the same parameters and in the same environment. The parameters - * include the receiver, and the environment includes all of the Java heap (that is, all fields of - * all objects and all static variables). - * - *

Determinism refers to the return value during a non-exceptional execution. If a method throws - * an exception, the Throwable does not have to be exactly the same object on each invocation (and - * generally should not be, to capture the correct stack trace). - * - *

This annotation is important to pluggable type-checking because, after a call to a - * {@code @Deterministic} method, flow-sensitive type refinement can assume that anything learned - * about the first invocation is true about subsequent invocations (so long as no - * non-{@code @}{@link SideEffectFree} method call intervenes). For example, the following code - * never suffers a null pointer exception, so the Nullness Checker need not issue a warning: - * - *

{@code
- * if (x.myDeterministicMethod() != null) {
- *   x.myDeterministicMethod().hashCode();
- * }
- * }
- * - *

Note that {@code @Deterministic} guarantees that the result is identical according to {@code - * ==}, not just equal according to {@code equals()}. This means that writing - * {@literal @}Deterministic on a method that returns a reference (including a String) is - * often erroneous unless the returned value is cached or interned. - * - *

Also see {@link Pure}, which means both deterministic and {@link SideEffectFree}. - * - *

Analysis: The Checker Framework performs a conservative analysis to verify a - * {@code @Deterministic} annotation. The Checker Framework issues a warning if the method uses any - * of the following Java constructs: - * - *

    - *
  1. Assignment to any expression, except for local variables (and method parameters). - *
  2. A method invocation of a method that is not {@link Deterministic}. - *
  3. Construction of a new object. - *
  4. Catching any exceptions. This is to prevent a method to get a hold of newly created objects - * and using these objects (or some property thereof) to change their return value. For - * instance, the following method must be forbidden. - *
    - * {@code @Deterministic
    - * int f() {
    - *   try {
    - *     int b = 0;
    - *     int a = 1/b;
    - *   } catch (Throwable t) {
    - *     return t.hashCode();
    - *   }
    - *   return 0;
    - * }
    - * }
    - *
- * - * A constructor can be {@code @Pure}, but a constructor invocation is not deterministic - * since it returns a different new object each time. TODO: Side-effect-free constructors could be - * allowed to set their own fields. - * - *

Note that the rules for checking currently imply that every {@code Deterministic} method is - * also {@link SideEffectFree}. This might change in the future; in general, a deterministic method - * does not need to be side-effect-free. - * - *

These rules are conservative: any code that passes the checks is deterministic, but the - * Checker Framework may issue false positive warnings, for code that uses one of the forbidden - * constructs but is deterministic nonetheless. - * - *

In fact, the rules are so conservative that checking is currently disabled by default, but can - * be enabled via the {@code -AcheckPurityAnnotations} command-line option. - * - *

- * - * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and - * flow-sensitive analysis - * @author Stefan Heule - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -public @interface Deterministic {} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java deleted file mode 100644 index 5a00db7a1b9223..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.checkerframework.dataflow.qual; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * {@code Pure} is a method annotation that means both {@link SideEffectFree} and {@link - * Deterministic}. The more important of these, when performing pluggable type-checking, is usually - * {@link SideEffectFree}. - * - * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and - * flow-sensitive analysis - * @author Stefan Heule - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -public @interface Pure { - /** The type of purity. */ - public static enum Kind { - /** The method has no visible side-effects. */ - SIDE_EFFECT_FREE, - - /** The method returns exactly the same value when called in the same environment. */ - DETERMINISTIC - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java deleted file mode 100644 index 6a969c43649636..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.checkerframework.dataflow.qual; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A method is called side-effect-free if it has no visible side-effects, such as setting a - * field of an object that existed before the method was called. - * - *

Only the visible side-effects are important. The method is allowed to cache the answer to a - * computationally expensive query, for instance. It is also allowed to modify newly-created - * objects, and a constructor is side-effect-free if it does not modify any objects that existed - * before it was called. - * - *

This annotation is important to pluggable type-checking because if some fact about an object - * is known before a call to such a method, then the fact is still known afterwards, even if the - * fact is about some non-final field. When any non-{@code @SideEffectFree} method is called, then a - * pluggable type-checker must assume that any field of any accessible object might have been - * modified, which annuls the effect of flow-sensitive type refinement and prevents the pluggable - * type-checker from making conclusions that are obvious to a programmer. - * - *

Also see {@link Pure}, which means both side-effect-free and {@link Deterministic}. - * - *

Analysis: The Checker Framework performs a conservative analysis to verify a - * {@code @SideEffectFree} annotation. The Checker Framework issues a warning if the method uses any - * of the following Java constructs: - * - *

    - *
  1. Assignment to any expression, except for local variables and method parameters. - *
  2. A method invocation of a method that is not {@code @SideEffectFree}. - *
  3. Construction of a new object where the constructor is not {@code @SideEffectFree}. - *
- * - * These rules are conservative: any code that passes the checks is side-effect-free, but the - * Checker Framework may issue false positive warnings, for code that uses one of the forbidden - * constructs but is side-effect-free nonetheless. In particular, a method that caches its result - * will be rejected. - * - *

In fact, the rules are so conservative that checking is currently disabled by default, but can - * be enabled via the {@code -AcheckPurityAnnotations} command-line option. - * - *

- * - * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and - * flow-sensitive analysis - * @author Stefan Heule - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -public @interface SideEffectFree {} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java deleted file mode 100644 index 4e83dcdb6445f3..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.checkerframework.dataflow.qual; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * {@code TerminatesExecution} is a method annotation that indicates that a method terminates the - * execution of the program. This can be used to annotate methods such as {@code System.exit()}. - * - *

The annotation enables flow-sensitive type refinement to be more precise. For example, after - * - *

- * if (x == null) {
- *   System.err.println("Bad value supplied");
- *   System.exit(1);
- * }
- * 
- * - * the Nullness Checker can determine that {@code x} is non-null. - * - *

The annotation is a trusted annotation, meaning that it is not checked whether the - * annotated method really does terminate the program. - * - * @checker_framework.manual #type-refinement Automatic type refinement (flow-sensitive type - * qualifier inference) - * @author Stefan Heule - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -public @interface TerminatesExecution {} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java deleted file mode 100644 index f898e3c9b447cf..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.checkerframework.dataflow.util; - -/** - * Utility class to implement the {@code hashCode} method. - * - * @author Stefan Heule - */ -public class HashCodeUtils { - - /** Odd prime number. */ - private static int prime = 31; - - /** Seed. */ - private static int seed = 17; - - /** Add a boolean value to a given hash. */ - public static int hash(int hash, boolean item) { - return hash * prime + (item ? 1 : 0); - } - - /** Add a char value to a given hash. */ - public static int hash(int hash, char item) { - return hash * prime + item; - } - - /** Add an int value to a given hash. */ - public static int hash(int hash, int item) { - return hash * prime + item; - } - - /** Add a long value to a given hash. */ - public static int hash(int hash, long item) { - return hash * prime + (int) (item ^ (item >>> 32)); - } - - /** Add a float value to a given hash. */ - public static int hash(int hash, float item) { - return hash * prime + Float.floatToIntBits(item); - } - - /** Add a double value to a given hash. */ - public static int hash(int hash, double item) { - long l = Double.doubleToLongBits(item); - return seed * prime + (int) (l ^ (l >>> 32)); - } - - /** Add an object to a given hash. */ - public static int hash(int hash, Object item) { - if (item == null) { - return hash * prime; - } - return hash * prime + item.hashCode(); - } - - /** Hash a boolean value. */ - public static int hash(boolean item) { - return (item ? 1 : 0); - } - - /** Hash a char value. */ - public static int hash(char item) { - return item; - } - - /** Hash an int value. */ - public static int hash(int item) { - return item; - } - - /** Hash a long value. */ - public static int hash(long item) { - return (int) (item ^ (item >>> 32)); - } - - /** Hash a float value. */ - public static int hash(float item) { - return Float.floatToIntBits(item); - } - - /** Hash a double value. */ - public static int hash(double item) { - long l = Double.doubleToLongBits(item); - return (int) (l ^ (l >>> 32)); - } - - /** Hash an object. */ - public static int hash(Object item) { - if (item == null) { - return 0; - } - return item.hashCode(); - } - - /** Hash multiple objects. */ - public static int hash(Object... items) { - int result = seed; - for (Object item : items) { - result = result * prime + (item == null ? 0 : item.hashCode()); - } - return result; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java deleted file mode 100644 index 7e9172da912938..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.checkerframework.dataflow.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Set; - -/** A set that is more efficient than HashSet for 0 and 1 elements. */ -public final class MostlySingleton implements Set { - private enum State { - EMPTY, - SINGLETON, - ANY - } - - private State state = State.EMPTY; - private T value; - private HashSet set; - - @Override - public int size() { - switch (state) { - case EMPTY: - return 0; - case SINGLETON: - return 1; - case ANY: - return set.size(); - default: - throw new AssertionError(); - } - } - - @Override - public boolean isEmpty() { - return size() == 0; - } - - @Override - public boolean contains(Object o) { - switch (state) { - case EMPTY: - return false; - case SINGLETON: - return Objects.equals(o, value); - case ANY: - return set.contains(o); - default: - throw new AssertionError(); - } - } - - @Override - @SuppressWarnings("fallthrough") - public boolean add(T e) { - switch (state) { - case EMPTY: - state = State.SINGLETON; - value = e; - return true; - case SINGLETON: - state = State.ANY; - set = new HashSet(); - set.add(value); - value = null; - // fallthrough - case ANY: - return set.add(e); - default: - throw new AssertionError(); - } - } - - @Override - public Iterator iterator() { - switch (state) { - case EMPTY: - return Collections.emptyIterator(); - case SINGLETON: - return new Iterator() { - private boolean hasNext = true; - - @Override - public boolean hasNext() { - return hasNext; - } - - @Override - public T next() { - if (hasNext) { - hasNext = false; - return value; - } - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - case ANY: - return set.iterator(); - default: - throw new AssertionError(); - } - } - - @Override - public Object[] toArray() { - throw new UnsupportedOperationException(); - } - - @Override - public S[] toArray(S[] a) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean containsAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java deleted file mode 100644 index cf7a090024303d..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.checkerframework.dataflow.util; - -import com.sun.source.tree.Tree; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.tree.JCTree; -import javax.lang.model.type.TypeKind; -import org.checkerframework.dataflow.cfg.node.ConditionalOrNode; -import org.checkerframework.dataflow.cfg.node.FieldAccessNode; -import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.javacutil.TypesUtils; - -/** - * A utility class to operate on a given {@link Node}. - * - * @author Stefan Heule - */ -public class NodeUtils { - - /** - * @return true iff {@code node} corresponds to a boolean typed expression (either the primitive - * type {@code boolean}, or class type {@link java.lang.Boolean}) - */ - public static boolean isBooleanTypeNode(Node node) { - - if (node instanceof ConditionalOrNode) { - return true; - } - - // not all nodes have an associated tree, but those are all not of a - // boolean type. - Tree tree = node.getTree(); - if (tree == null) { - return false; - } - - Type type = ((JCTree) tree).type; - if (TypesUtils.isBooleanType(type)) { - return true; - } - - return false; - } - - /** - * @return true iff {@code node} is a {@link FieldAccessNode} that is an access to an array's - * length - */ - public static boolean isArrayLengthFieldAccess(Node node) { - if (!(node instanceof FieldAccessNode)) { - return false; - } - FieldAccessNode fieldAccess = (FieldAccessNode) node; - return fieldAccess.getFieldName().equals("length") - && fieldAccess.getReceiver().getType().getKind() == TypeKind.ARRAY; - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java deleted file mode 100644 index 0b298f19552b6e..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java +++ /dev/null @@ -1,491 +0,0 @@ -package org.checkerframework.dataflow.util; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; -*/ - -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.AssertTree; -import com.sun.source.tree.AssignmentTree; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.BlockTree; -import com.sun.source.tree.BreakTree; -import com.sun.source.tree.CaseTree; -import com.sun.source.tree.CatchTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompoundAssignmentTree; -import com.sun.source.tree.ConditionalExpressionTree; -import com.sun.source.tree.ContinueTree; -import com.sun.source.tree.DoWhileLoopTree; -import com.sun.source.tree.EmptyStatementTree; -import com.sun.source.tree.EnhancedForLoopTree; -import com.sun.source.tree.ExpressionStatementTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.ForLoopTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.IfTree; -import com.sun.source.tree.InstanceOfTree; -import com.sun.source.tree.LabeledStatementTree; -import com.sun.source.tree.LambdaExpressionTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberReferenceTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.ParenthesizedTree; -import com.sun.source.tree.ReturnTree; -import com.sun.source.tree.SwitchTree; -import com.sun.source.tree.SynchronizedTree; -import com.sun.source.tree.ThrowTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.TryTree; -import com.sun.source.tree.TypeCastTree; -import com.sun.source.tree.UnaryTree; -import com.sun.source.tree.VariableTree; -import com.sun.source.tree.WhileLoopTree; -import com.sun.source.util.SimpleTreeVisitor; -import com.sun.tools.javac.tree.TreeScanner; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.List; -import javax.lang.model.element.Element; -import org.checkerframework.dataflow.qual.Deterministic; -import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.Pure.Kind; -import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.javacutil.AnnotationProvider; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.Pair; -import org.checkerframework.javacutil.TreeUtils; - -/** - * A visitor that determines the purity (as defined by {@link - * org.checkerframework.dataflow.qual.SideEffectFree}, {@link - * org.checkerframework.dataflow.qual.Deterministic}, and {@link - * org.checkerframework.dataflow.qual.Pure}) of a statement or expression. The entry point is method - * {@link #checkPurity}. - * - * @see SideEffectFree - * @see Deterministic - * @see Pure - * @author Stefan Heule - */ -public class PurityChecker { - - /** - * Compute whether the given statement is side-effect-free, deterministic, or both. Returns a - * result that can be queried. - */ - public static PurityResult checkPurity( - Tree statement, AnnotationProvider annoProvider, boolean assumeSideEffectFree) { - PurityCheckerHelper helper = new PurityCheckerHelper(annoProvider, assumeSideEffectFree); - PurityResult res = helper.scan(statement, new PurityResult()); - return res; - } - - /** - * Result of the {@link PurityChecker}. Can be queried regarding whether a given tree was - * side-effect-free, deterministic, or both; also gives reasons if the answer is "no". - */ - public static class PurityResult { - - protected final List> notSeFreeReasons; - protected final List> notDetReasons; - protected final List> notBothReasons; - protected EnumSet types; - - public PurityResult() { - notSeFreeReasons = new ArrayList<>(); - notDetReasons = new ArrayList<>(); - notBothReasons = new ArrayList<>(); - types = EnumSet.allOf(Pure.Kind.class); - } - - public EnumSet getTypes() { - return types; - } - - /** Is the method pure w.r.t. a given set of types? */ - public boolean isPure(Collection kinds) { - return types.containsAll(kinds); - } - - /** Get the {@code reason}s why the method is not side-effect-free. */ - public List> getNotSeFreeReasons() { - return notSeFreeReasons; - } - - /** Add {@code reason} as a reason why the method is not side-effect free. */ - public void addNotSeFreeReason(Tree t, String msgId) { - notSeFreeReasons.add(Pair.of(t, msgId)); - types.remove(Kind.SIDE_EFFECT_FREE); - } - - /** Get the {@code reason}s why the method is not deterministic. */ - public List> getNotDetReasons() { - return notDetReasons; - } - - /** Add {@code reason} as a reason why the method is not deterministic. */ - public void addNotDetReason(Tree t, String msgId) { - notDetReasons.add(Pair.of(t, msgId)); - types.remove(Kind.DETERMINISTIC); - } - - /** - * Get the {@code reason}s why the method is not both side-effect-free and deterministic. - */ - public List> getNotBothReasons() { - return notBothReasons; - } - - /** - * Add {@code reason} as a reason why the method is not both side-effect free and - * deterministic. - */ - public void addNotBothReason(Tree t, String msgId) { - notBothReasons.add(Pair.of(t, msgId)); - types.remove(Kind.DETERMINISTIC); - types.remove(Kind.SIDE_EFFECT_FREE); - } - } - - /** - * Helper class to keep {@link PurityChecker}'s interface clean. The implementation is heavily - * based on {@link TreeScanner}, but some parts of the AST are skipped (such as types or - * modifiers). Furthermore, scanning works differently in that the input parameter (usually - * named {@code p}) gets "threaded through", instead of using {@code reduce}. - */ - protected static class PurityCheckerHelper - extends SimpleTreeVisitor { - - protected final AnnotationProvider annoProvider; - /** - * True if all methods should be assumed to be @SideEffectFree, for the purposes of - * org.checkerframework.dataflow analysis. - */ - private final boolean assumeSideEffectFree; - - protected /*@Nullable*/ List methodParameter; - - public PurityCheckerHelper(AnnotationProvider annoProvider, boolean assumeSideEffectFree) { - this.annoProvider = annoProvider; - this.assumeSideEffectFree = assumeSideEffectFree; - } - - /** Scan a single node. */ - public PurityResult scan(Tree node, PurityResult p) { - return node == null ? p : node.accept(this, p); - } - - /** Scan a list of nodes. */ - public PurityResult scan(Iterable nodes, PurityResult p) { - PurityResult r = p; - if (nodes != null) { - for (Tree node : nodes) { - r = scan(node, r); - } - } - return r; - } - - @Override - protected PurityResult defaultAction(Tree node, PurityResult p) { - assert false : "this type of tree is unexpected here"; - return null; - } - - @Override - public PurityResult visitClass(ClassTree node, PurityResult p) { - return p; - } - - @Override - public PurityResult visitVariable(VariableTree node, PurityResult p) { - return scan(node.getInitializer(), p); - } - - @Override - public PurityResult visitEmptyStatement(EmptyStatementTree node, PurityResult p) { - return p; - } - - @Override - public PurityResult visitBlock(BlockTree node, PurityResult p) { - return scan(node.getStatements(), p); - } - - @Override - public PurityResult visitDoWhileLoop(DoWhileLoopTree node, PurityResult p) { - PurityResult r = scan(node.getStatement(), p); - r = scan(node.getCondition(), r); - return r; - } - - @Override - public PurityResult visitWhileLoop(WhileLoopTree node, PurityResult p) { - PurityResult r = scan(node.getCondition(), p); - r = scan(node.getStatement(), r); - return r; - } - - @Override - public PurityResult visitForLoop(ForLoopTree node, PurityResult p) { - PurityResult r = scan(node.getInitializer(), p); - r = scan(node.getCondition(), r); - r = scan(node.getUpdate(), r); - r = scan(node.getStatement(), r); - return r; - } - - @Override - public PurityResult visitEnhancedForLoop(EnhancedForLoopTree node, PurityResult p) { - PurityResult r = scan(node.getVariable(), p); - r = scan(node.getExpression(), r); - r = scan(node.getStatement(), r); - return r; - } - - @Override - public PurityResult visitLabeledStatement(LabeledStatementTree node, PurityResult p) { - return scan(node.getStatement(), p); - } - - @Override - public PurityResult visitSwitch(SwitchTree node, PurityResult p) { - PurityResult r = scan(node.getExpression(), p); - r = scan(node.getCases(), r); - return r; - } - - @Override - public PurityResult visitCase(CaseTree node, PurityResult p) { - PurityResult r = scan(node.getExpression(), p); - r = scan(node.getStatements(), r); - return r; - } - - @Override - public PurityResult visitSynchronized(SynchronizedTree node, PurityResult p) { - PurityResult r = scan(node.getExpression(), p); - r = scan(node.getBlock(), r); - return r; - } - - @Override - public PurityResult visitTry(TryTree node, PurityResult p) { - PurityResult r = scan(node.getResources(), p); - r = scan(node.getBlock(), r); - r = scan(node.getCatches(), r); - r = scan(node.getFinallyBlock(), r); - return r; - } - - @Override - public PurityResult visitCatch(CatchTree node, PurityResult p) { - p.addNotDetReason(node, "catch"); - PurityResult r = scan(node.getParameter(), p); - r = scan(node.getBlock(), r); - return r; - } - - @Override - public PurityResult visitConditionalExpression( - ConditionalExpressionTree node, PurityResult p) { - PurityResult r = scan(node.getCondition(), p); - r = scan(node.getTrueExpression(), r); - r = scan(node.getFalseExpression(), r); - return r; - } - - @Override - public PurityResult visitIf(IfTree node, PurityResult p) { - PurityResult r = scan(node.getCondition(), p); - r = scan(node.getThenStatement(), r); - r = scan(node.getElseStatement(), r); - return r; - } - - @Override - public PurityResult visitExpressionStatement(ExpressionStatementTree node, PurityResult p) { - return scan(node.getExpression(), p); - } - - @Override - public PurityResult visitBreak(BreakTree node, PurityResult p) { - return p; - } - - @Override - public PurityResult visitContinue(ContinueTree node, PurityResult p) { - return p; - } - - @Override - public PurityResult visitReturn(ReturnTree node, PurityResult p) { - return scan(node.getExpression(), p); - } - - @Override - public PurityResult visitThrow(ThrowTree node, PurityResult p) { - return scan(node.getExpression(), p); - } - - @Override - public PurityResult visitAssert(AssertTree node, PurityResult p) { - PurityResult r = scan(node.getCondition(), p); - r = scan(node.getDetail(), r); - return r; - } - - @Override - public PurityResult visitMethodInvocation(MethodInvocationTree node, PurityResult p) { - Element elt = TreeUtils.elementFromUse(node); - String reason = "call"; - if (!PurityUtils.hasPurityAnnotation(annoProvider, elt)) { - p.addNotBothReason(node, reason); - } else { - boolean det = PurityUtils.isDeterministic(annoProvider, elt); - boolean seFree = - (assumeSideEffectFree || PurityUtils.isSideEffectFree(annoProvider, elt)); - if (!det && !seFree) { - p.addNotBothReason(node, reason); - } else if (!det) { - p.addNotDetReason(node, reason); - } else if (!seFree) { - p.addNotSeFreeReason(node, reason); - } - } - PurityResult r = scan(node.getMethodSelect(), p); - r = scan(node.getArguments(), r); - return r; - } - - @Override - public PurityResult visitNewClass(NewClassTree node, PurityResult p) { - Element methodElement = InternalUtils.symbol(node); - boolean sideEffectFree = - (assumeSideEffectFree - || PurityUtils.isSideEffectFree(annoProvider, methodElement)); - if (sideEffectFree) { - p.addNotDetReason(node, "object.creation"); - } else { - p.addNotBothReason(node, "object.creation"); - } - PurityResult r = scan(node.getEnclosingExpression(), p); - r = scan(node.getArguments(), r); - r = scan(node.getClassBody(), r); - return r; - } - - @Override - public PurityResult visitNewArray(NewArrayTree node, PurityResult p) { - PurityResult r = scan(node.getDimensions(), p); - r = scan(node.getInitializers(), r); - return r; - } - - @Override - public PurityResult visitLambdaExpression(LambdaExpressionTree node, PurityResult p) { - PurityResult r = scan(node.getParameters(), p); - r = scan(node.getBody(), r); - return r; - } - - @Override - public PurityResult visitParenthesized(ParenthesizedTree node, PurityResult p) { - return scan(node.getExpression(), p); - } - - @Override - public PurityResult visitAssignment(AssignmentTree node, PurityResult p) { - ExpressionTree variable = node.getVariable(); - p = assignmentCheck(p, variable); - PurityResult r = scan(variable, p); - r = scan(node.getExpression(), r); - return r; - } - - protected PurityResult assignmentCheck(PurityResult p, ExpressionTree variable) { - if (TreeUtils.isFieldAccess(variable)) { - // rhs is a field access - p.addNotBothReason(variable, "assign.field"); - } else if (variable instanceof ArrayAccessTree) { - // rhs is array access - p.addNotBothReason(variable, "assign.array"); - } else { - // rhs is a local variable - assert isLocalVariable(variable); - } - return p; - } - - protected boolean isLocalVariable(ExpressionTree variable) { - return variable instanceof IdentifierTree && !TreeUtils.isFieldAccess(variable); - } - - @Override - public PurityResult visitCompoundAssignment(CompoundAssignmentTree node, PurityResult p) { - ExpressionTree variable = node.getVariable(); - p = assignmentCheck(p, variable); - PurityResult r = scan(variable, p); - r = scan(node.getExpression(), r); - return r; - } - - @Override - public PurityResult visitUnary(UnaryTree node, PurityResult p) { - return scan(node.getExpression(), p); - } - - @Override - public PurityResult visitBinary(BinaryTree node, PurityResult p) { - PurityResult r = scan(node.getLeftOperand(), p); - r = scan(node.getRightOperand(), r); - return r; - } - - @Override - public PurityResult visitTypeCast(TypeCastTree node, PurityResult p) { - PurityResult r = scan(node.getExpression(), p); - return r; - } - - @Override - public PurityResult visitInstanceOf(InstanceOfTree node, PurityResult p) { - PurityResult r = scan(node.getExpression(), p); - return r; - } - - @Override - public PurityResult visitArrayAccess(ArrayAccessTree node, PurityResult p) { - PurityResult r = scan(node.getExpression(), p); - r = scan(node.getIndex(), r); - return r; - } - - @Override - public PurityResult visitMemberSelect(MemberSelectTree node, PurityResult p) { - return scan(node.getExpression(), p); - } - - @Override - public PurityResult visitMemberReference(MemberReferenceTree node, PurityResult p) { - assert false : "this type of tree is unexpected here"; - return null; - } - - @Override - public PurityResult visitIdentifier(IdentifierTree node, PurityResult p) { - return p; - } - - @Override - public PurityResult visitLiteral(LiteralTree node, PurityResult p) { - return p; - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java deleted file mode 100644 index c175877a249eae..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.checkerframework.dataflow.util; - -import com.sun.source.tree.MethodTree; -import java.util.ArrayList; -import java.util.List; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import org.checkerframework.dataflow.qual.Deterministic; -import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.Pure.Kind; -import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.javacutil.AnnotationProvider; -import org.checkerframework.javacutil.InternalUtils; - -/** - * An utility class for working with the {@link SideEffectFree}, {@link Deterministic}, and {@link - * Pure} annotations. - * - * @see SideEffectFree - * @see Deterministic - * @see Pure - * @author Stefan Heule - */ -public class PurityUtils { - - /** Does the method {@code tree} have any purity annotation? */ - public static boolean hasPurityAnnotation(AnnotationProvider provider, MethodTree tree) { - return !getPurityKinds(provider, tree).isEmpty(); - } - - /** Does the method {@code methodElement} have any purity annotation? */ - public static boolean hasPurityAnnotation(AnnotationProvider provider, Element methodElement) { - return !getPurityKinds(provider, methodElement).isEmpty(); - } - - /** Is the method {@code tree} deterministic? */ - public static boolean isDeterministic(AnnotationProvider provider, MethodTree tree) { - Element methodElement = InternalUtils.symbol(tree); - return isDeterministic(provider, methodElement); - } - - /** Is the method {@code methodElement} deterministic? */ - public static boolean isDeterministic(AnnotationProvider provider, Element methodElement) { - List kinds = getPurityKinds(provider, methodElement); - return kinds.contains(Kind.DETERMINISTIC); - } - - /** Is the method {@code tree} side-effect-free? */ - public static boolean isSideEffectFree(AnnotationProvider provider, MethodTree tree) { - Element methodElement = InternalUtils.symbol(tree); - return isSideEffectFree(provider, methodElement); - } - - /** Is the method {@code methodElement} side-effect-free? */ - public static boolean isSideEffectFree(AnnotationProvider provider, Element methodElement) { - List kinds = getPurityKinds(provider, methodElement); - return kinds.contains(Kind.SIDE_EFFECT_FREE); - } - - /** @return the types of purity of the method {@code tree}. */ - public static List getPurityKinds(AnnotationProvider provider, MethodTree tree) { - Element methodElement = InternalUtils.symbol(tree); - return getPurityKinds(provider, methodElement); - } - - /** - * @return the types of purity of the method {@code methodElement}. TODO: should the return type - * be an EnumSet? - */ - public static List getPurityKinds( - AnnotationProvider provider, Element methodElement) { - AnnotationMirror pureAnnotation = provider.getDeclAnnotation(methodElement, Pure.class); - AnnotationMirror sefAnnotation = - provider.getDeclAnnotation(methodElement, SideEffectFree.class); - AnnotationMirror detAnnotation = - provider.getDeclAnnotation(methodElement, Deterministic.class); - - List kinds = new ArrayList<>(); - if (pureAnnotation != null) { - kinds.add(Kind.DETERMINISTIC); - kinds.add(Kind.SIDE_EFFECT_FREE); - } - if (sefAnnotation != null) { - kinds.add(Kind.SIDE_EFFECT_FREE); - } - if (detAnnotation != null) { - kinds.add(Kind.DETERMINISTIC); - } - return kinds; - } -} diff --git a/third_party/checker_framework_javacutil/BUILD b/third_party/checker_framework_javacutil/BUILD index cc18ab202005fc..a13586c2243365 100644 --- a/third_party/checker_framework_javacutil/BUILD +++ b/third_party/checker_framework_javacutil/BUILD @@ -4,19 +4,13 @@ licenses(["restricted"]) # GNU GPL v2 with Classpath exception filegroup( name = "srcs", - srcs = glob(["**"]), + srcs = ["javacutil-2.2.2-sources.jar"], ) -java_library( +java_import( name = "checker_framework_javacutil", - srcs = glob(["java/**"]), - deps = ["@local_jdk//:langtools-neverlink"], -) - -load("//tools/build_rules:java_rules_skylark.bzl", "bootstrap_java_library") - -bootstrap_java_library( - name = "bootstrap", - srcs = glob(["java/**"]), - neverlink_jars = ["@local_jdk//:langtools"], + jars = [ + "javacutil-2.2.2.jar", + ], + srcjar = "javacutil-2.2.2-sources.jar", ) diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java deleted file mode 100644 index 114ce6d0b6adc6..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java +++ /dev/null @@ -1,196 +0,0 @@ -package org.checkerframework.javacutil; - -import com.sun.source.tree.ClassTree; -import com.sun.source.util.JavacTask; -import com.sun.source.util.TaskEvent; -import com.sun.source.util.TaskListener; -import com.sun.source.util.TreePath; -import com.sun.source.util.Trees; -import com.sun.tools.javac.comp.CompileStates.CompileState; -import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Log; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.ElementFilter; - -/** - * This class is an abstract annotation processor designed to be a convenient superclass for - * concrete "type processors", processors that require the type information in the processed source. - * - *

Type processing occurs in one round after the tool (e.g. Java compiler) analyzes the source - * (all sources taken as input to the tool and sources generated by other annotation processors). - * - *

The tool infrastructure will interact with classes extending this abstract class as follows. - * - *

1-3 are identical to the {@link Processor} life cycle. 4-5 are unique to {@code - * AbstractTypeProcessor} subclasses. - * - *

    - *
  1. If an existing {@code Processor} object is not being used, to create an instance of a - * processor the tool calls the no-arg constructor of the processor class. - *
  2. Next, the tool calls the {@link #init init} method with an appropriate {@code - * ProcessingEnvironment}. - *
  3. Afterwards, the tool calls {@link #getSupportedAnnotationTypes - * getSupportedAnnotationTypes}, {@link #getSupportedOptions getSupportedOptions}, and {@link - * #getSupportedSourceVersion getSupportedSourceVersion}. These methods are only called once - * per run, not on each round. - *
  4. For each class containing a supported annotation, the tool calls {@link - * #typeProcess(TypeElement, TreePath) typeProcess} method on the {@code Processor}. The class - * is guaranteed to be type-checked Java code and all the tree type and symbol information is - * resolved. - *
  5. Finally, the tools calls the {@link #typeProcessingOver() typeProcessingOver} method on the - * {@code Processor}. - *
- * - *

The tool is permitted to ask type processors to process a class once it is analyzed before the - * rest of classes are analyzed. The tool is also permitted to stop type processing immediately if - * any errors are raised, without invoking {@code typeProcessingOver} - * - *

A subclass may override any of the methods in this class, as long as the general {@link - * javax.annotation.processing.Processor Processor} contract is obeyed, with one notable exception. - * {@link #process(Set, RoundEnvironment)} may not be overridden, as it is called during the - * declaration annotation phase before classes are analyzed. - * - * @author Mahmood Ali - * @author Werner Dietl - */ -public abstract class AbstractTypeProcessor extends AbstractProcessor { - /** - * The set of fully-qualified element names that should be type-checked. We store the names of - * the elements, in order to prevent possible confusion between different Element - * instantiations. - */ - private final Set elements = new HashSet(); - - /** - * Method {@link #typeProcessingStart()} must be invoked exactly once, before any invocation of - * {@link #typeProcess(TypeElement, TreePath)}. - */ - private boolean hasInvokedTypeProcessingStart = false; - - /** - * Method {@link #typeProcessingOver()} must be invoked exactly once, after the last invocation - * of {@link #typeProcess(TypeElement, TreePath)}. - */ - private static boolean hasInvokedTypeProcessingOver = false; - - /** The TaskListener registered for completion of attribution. */ - private final AttributionTaskListener listener = new AttributionTaskListener(); - - /** Constructor for subclasses to call. */ - protected AbstractTypeProcessor() {} - - /** - * {@inheritDoc} - * - *

Register a TaskListener that will get called after FLOW. - */ - @Override - public synchronized void init(ProcessingEnvironment env) { - super.init(env); - JavacTask.instance(env).addTaskListener(listener); - Context ctx = ((JavacProcessingEnvironment) processingEnv).getContext(); - JavaCompiler compiler = JavaCompiler.instance(ctx); - compiler.shouldStopPolicyIfNoError = - CompileState.max(compiler.shouldStopPolicyIfNoError, CompileState.FLOW); - compiler.shouldStopPolicyIfError = - CompileState.max(compiler.shouldStopPolicyIfError, CompileState.FLOW); - } - - /** - * The use of this method is obsolete in type processors. The method is called during - * declaration annotation processing phase only. It registers the names of elements to process. - */ - @Override - public final boolean process( - Set annotations, RoundEnvironment roundEnv) { - for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) { - elements.add(elem.getQualifiedName()); - } - return false; - } - - /** - * A method to be called once before the first call to typeProcess. - * - *

Subclasses may override this method to do any initialization work. - */ - public void typeProcessingStart() {} - - /** - * Processes a fully-analyzed class that contains a supported annotation (see {@link - * #getSupportedAnnotationTypes()}). - * - *

The passed class is always valid type-checked Java code. - * - * @param element element of the analyzed class - * @param tree the tree path to the element, with the leaf being a {@link ClassTree} - */ - public abstract void typeProcess(TypeElement element, TreePath tree); - - /** - * A method to be called once all the classes are processed and no error is reported. - * - *

Subclasses may override this method to do any aggregate analysis (e.g. generate report, - * persistence) or resource deallocation. - * - *

If an error (a Java error or a processor error) is reported, this method is not guaranteed - * to be invoked. - */ - public void typeProcessingOver() {} - - /** A task listener that invokes the processor whenever a class is fully analyzed. */ - private final class AttributionTaskListener implements TaskListener { - - @Override - public void finished(TaskEvent e) { - if (e.getKind() != TaskEvent.Kind.ANALYZE) { - return; - } - - if (!hasInvokedTypeProcessingStart) { - typeProcessingStart(); - hasInvokedTypeProcessingStart = true; - } - - Log log = Log.instance(((JavacProcessingEnvironment) processingEnv).getContext()); - - if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) { - typeProcessingOver(); - hasInvokedTypeProcessingOver = true; - } - - if (e.getTypeElement() == null) { - throw new AssertionError("event task without a type element"); - } - if (e.getCompilationUnit() == null) { - throw new AssertionError("event task without compilation unit"); - } - - if (!elements.remove(e.getTypeElement().getQualifiedName())) { - return; - } - - TypeElement elem = e.getTypeElement(); - TreePath p = Trees.instance(processingEnv).getPath(elem); - - typeProcess(elem, p); - - if (!hasInvokedTypeProcessingOver && elements.isEmpty() && log.nerrors == 0) { - typeProcessingOver(); - hasInvokedTypeProcessingOver = true; - } - } - - @Override - public void started(TaskEvent e) {} - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java deleted file mode 100644 index 1245960eddd1b3..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.checkerframework.javacutil; - -import com.sun.source.tree.Tree; -import java.lang.annotation.Annotation; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; - -/** An implementation of AnnotationProvider returns annotations on Java AST elements. */ -public interface AnnotationProvider { - - /** - * Returns the actual annotation mirror used to annotate this type, whose name equals the passed - * annotationName if one exists, null otherwise. - * - * @param anno annotation class - * @return the annotation mirror for anno - */ - public AnnotationMirror getDeclAnnotation(Element elt, Class anno); - - /** - * Return the annotation on {@code tree} that has the class {@code target}. If no annotation for - * the given target class exists, the result is {@code null} - * - * @param tree the tree of which the annotation is returned - * @param target the class of the annotation - */ - public AnnotationMirror getAnnotationMirror(Tree tree, Class target); -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java deleted file mode 100644 index c80f57cc5dfb0b..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java +++ /dev/null @@ -1,650 +0,0 @@ -package org.checkerframework.javacutil; - -/*>>> -import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.checker.nullness.qual.*; -import org.checkerframework.checker.interning.qual.*; -*/ - -import com.sun.source.tree.AnnotationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.ModifiersTree; -import com.sun.tools.javac.code.Symbol.VarSymbol; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.model.JavacElements; -import java.lang.annotation.Annotation; -import java.lang.annotation.Inherited; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; -import javax.lang.model.util.Elements; - -/** A utility class for working with annotations. */ -public class AnnotationUtils { - - // Class cannot be instantiated. - private AnnotationUtils() { - throw new AssertionError("Class AnnotationUtils cannot be instantiated."); - } - - // TODO: hack to clear out static state. - public static void clear() { - annotationsFromNames.clear(); - annotationMirrorNames.clear(); - annotationMirrorSimpleNames.clear(); - annotationClassNames.clear(); - } - - // ********************************************************************** - // Factory Methods to create instances of AnnotationMirror - // ********************************************************************** - - /** Caching for annotation creation. */ - private static final Map annotationsFromNames = - Collections.synchronizedMap(new HashMap()); - - private static final int ANNOTATION_CACHE_SIZE = 500; - - /** - * Cache names of AnnotationMirrors for faster access. Values in the map are interned Strings, - * so they can be compared with ==. - */ - private static final Map annotationMirrorNames = - Collections.synchronizedMap( - CollectionUtils.createLRUCache( - ANNOTATION_CACHE_SIZE)); - - /** - * Cache simple names of AnnotationMirrors for faster access. Values in the map are interned - * Strings, so they can be compared with ==. - */ - private static final Map annotationMirrorSimpleNames = - Collections.synchronizedMap( - CollectionUtils.createLRUCache( - ANNOTATION_CACHE_SIZE)); - - /** - * Cache names of classes representing AnnotationMirrors for faster access. Values in the map - * are interned Strings, so they can be compared with ==. - */ - private static final Map, /*@Interned*/ String> - annotationClassNames = - Collections.synchronizedMap( - new HashMap, /*@Interned*/ String>()); - - /** - * Creates an {@link AnnotationMirror} given by a particular fully-qualified name. - * getElementValues on the result returns an empty map. - * - * @param elements the element utilities to use - * @param name the name of the annotation to create - * @return an {@link AnnotationMirror} of type {@code} name - */ - public static AnnotationMirror fromName(Elements elements, CharSequence name) { - AnnotationMirror res = annotationsFromNames.get(name); - if (res != null) { - return res; - } - final DeclaredType annoType = typeFromName(elements, name); - if (annoType == null) { - return null; - } - if (annoType.asElement().getKind() != ElementKind.ANNOTATION_TYPE) { - ErrorReporter.errorAbort(annoType + " is not an annotation"); - return null; // dead code - } - AnnotationMirror result = - new AnnotationMirror() { - String toString = "@" + annoType; - - @Override - public DeclaredType getAnnotationType() { - return annoType; - } - - @Override - public Map - getElementValues() { - return Collections.emptyMap(); - } - /*@SideEffectFree*/ - @Override - public String toString() { - return toString; - } - }; - annotationsFromNames.put(name, result); - return result; - } - - /** - * Creates an {@link AnnotationMirror} given by a particular annotation class. - * - * @param elements the element utilities to use - * @param clazz the annotation class - * @return an {@link AnnotationMirror} of type given type - */ - public static AnnotationMirror fromClass(Elements elements, Class clazz) { - return fromName(elements, clazz.getCanonicalName()); - } - - /** - * A utility method that converts a {@link CharSequence} (usually a {@link String}) into a - * {@link TypeMirror} named thereby. - * - * @param elements the element utilities to use - * @param name the name of a type - * @return the {@link TypeMirror} corresponding to that name - */ - private static DeclaredType typeFromName(Elements elements, CharSequence name) { - /*@Nullable*/ TypeElement typeElt = elements.getTypeElement(name); - if (typeElt == null) { - return null; - } - - return (DeclaredType) typeElt.asType(); - } - - // ********************************************************************** - // Helper methods to handle annotations. mainly workaround - // AnnotationMirror.equals undesired property - // (I think the undesired property is that it's reference equality.) - // ********************************************************************** - - /** @return the fully-qualified name of an annotation as a String */ - public static final /*@Interned*/ String annotationName(AnnotationMirror annotation) { - String res = annotationMirrorNames.get(annotation); - if (res != null) { - return res; - } - final DeclaredType annoType = annotation.getAnnotationType(); - final TypeElement elm = (TypeElement) annoType.asElement(); - /*@Interned*/ String name = elm.getQualifiedName().toString().intern(); - annotationMirrorNames.put(annotation, name); - return name; - } - - /** @return the simple name of an annotation as a String */ - public static String annotationSimpleName(AnnotationMirror annotation) { - String res = annotationMirrorSimpleNames.get(annotation); - if (res != null) { - return res; - } - final DeclaredType annoType = annotation.getAnnotationType(); - final TypeElement elm = (TypeElement) annoType.asElement(); - /*@Interned*/ String name = elm.getSimpleName().toString().intern(); - annotationMirrorSimpleNames.put(annotation, name); - return name; - } - - /** - * Checks if both annotations are the same. - * - *

Returns true iff both annotations are of the same type and have the same annotation - * values. This behavior differs from {@code AnnotationMirror.equals(Object)}. The equals method - * returns true iff both annotations are the same and annotate the same annotation target (e.g. - * field, variable, etc). - * - * @return true iff a1 and a2 are the same annotation - */ - public static boolean areSame( - /*@Nullable*/ AnnotationMirror a1, /*@Nullable*/ AnnotationMirror a2) { - if (a1 != null && a2 != null) { - if (annotationName(a1) != annotationName(a2)) { - return false; - } - - Map elval1 = - getElementValuesWithDefaults(a1); - Map elval2 = - getElementValuesWithDefaults(a2); - - return elval1.toString().equals(elval2.toString()); - } - - // only true, iff both are null - return a1 == a2; - } - - /** - * @see #areSame(AnnotationMirror, AnnotationMirror) - * @return true iff a1 and a2 have the same annotation type - */ - public static boolean areSameIgnoringValues(AnnotationMirror a1, AnnotationMirror a2) { - if (a1 != null && a2 != null) { - return annotationName(a1) == annotationName(a2); - } - return a1 == a2; - } - - /** Checks that the annotation {@code am} has the name {@code aname}. Values are ignored. */ - public static boolean areSameByName(AnnotationMirror am, /*@Interned*/ String aname) { - // Both strings are interned. - return annotationName(am) == aname; - } - - /** Checks that the annotation {@code am} has the name of {@code anno}. Values are ignored. */ - public static boolean areSameByClass(AnnotationMirror am, Class anno) { - /*@Interned*/ String canonicalName = annotationClassNames.get(anno); - if (canonicalName == null) { - canonicalName = anno.getCanonicalName().intern(); - annotationClassNames.put(anno, canonicalName); - } - return areSameByName(am, canonicalName); - } - - /** - * Checks that two collections contain the same annotations. - * - * @return true iff c1 and c2 contain the same annotations - */ - public static boolean areSame( - Collection c1, Collection c2) { - if (c1.size() != c2.size()) { - return false; - } - if (c1.size() == 1) { - return areSame(c1.iterator().next(), c2.iterator().next()); - } - - Set s1 = createAnnotationSet(); - Set s2 = createAnnotationSet(); - s1.addAll(c1); - s2.addAll(c2); - - // depend on the fact that Set is an ordered set. - Iterator iter1 = s1.iterator(); - Iterator iter2 = s2.iterator(); - - while (iter1.hasNext()) { - AnnotationMirror anno1 = iter1.next(); - AnnotationMirror anno2 = iter2.next(); - if (!areSame(anno1, anno2)) { - return false; - } - } - return true; - } - - /** - * Checks that the collection contains the annotation. Using Collection.contains does not always - * work, because it does not use areSame for comparison. - * - * @return true iff c contains anno, according to areSame - */ - public static boolean containsSame( - Collection c, AnnotationMirror anno) { - return getSame(c, anno) != null; - } - - /** - * Returns the AnnotationMirror in {@code c} that is the same annotation as {@code anno}. - * - * @return AnnotationMirror with the same class as {@code anno} iff c contains anno, according - * to areSame; otherwise, {@code null} - */ - public static AnnotationMirror getSame( - Collection c, AnnotationMirror anno) { - for (AnnotationMirror an : c) { - if (AnnotationUtils.areSame(an, anno)) { - return an; - } - } - return null; - } - - /** - * Checks that the collection contains the annotation. Using Collection.contains does not always - * work, because it does not use areSame for comparison. - * - * @return true iff c contains anno, according to areSameByClass - */ - public static boolean containsSameByClass( - Collection c, Class anno) { - return getAnnotationByClass(c, anno) != null; - } - - /** - * Returns the AnnotationMirror in {@code c} that has the same class as {@code anno}. - * - * @return AnnotationMirror with the same class as {@code anno} iff c contains anno, according - * to areSameByClass; otherwise, {@code null} - */ - public static AnnotationMirror getAnnotationByClass( - Collection c, Class anno) { - for (AnnotationMirror an : c) { - if (AnnotationUtils.areSameByClass(an, anno)) { - return an; - } - } - return null; - } - - /** - * Checks that the collection contains the annotation ignoring values. Using Collection.contains - * does not always work, because it does not use areSameIgnoringValues for comparison. - * - * @return true iff c contains anno, according to areSameIgnoringValues - */ - public static boolean containsSameIgnoringValues( - Collection c, AnnotationMirror anno) { - return getSameIgnoringValues(c, anno) != null; - } - - /** - * Returns the AnnotationMirror in {@code c} that is the same annotation as {@code anno} - * ignoring values. - * - * @return AnnotationMirror with the same class as {@code anno} iff c contains anno, according - * to areSameIgnoringValues; otherwise, {@code null} - */ - public static AnnotationMirror getSameIgnoringValues( - Collection c, AnnotationMirror anno) { - for (AnnotationMirror an : c) { - if (AnnotationUtils.areSameIgnoringValues(an, anno)) { - return an; - } - } - return null; - } - - private static final Comparator ANNOTATION_ORDERING = - new Comparator() { - @Override - public int compare(AnnotationMirror a1, AnnotationMirror a2) { - // AnnotationMirror.toString() prints the elements of an annotation in the - // order in which they were written. So, use areSame to check for equality. - if (AnnotationUtils.areSame(a1, a2)) { - return 0; - } - - String n1 = a1.toString(); - String n2 = a2.toString(); - - // Because the AnnotationMirror.toString prints the annotation as it appears - // in source code, the order in which annotations of the same class are - // sorted may be confusing. For example, it might order - // @IntRange(from=1, to=MAX) before @IntRange(to=MAX,from=0). - return n1.compareTo(n2); - } - }; - - /** - * provide ordering for {@link AnnotationMirror} based on their fully qualified name. The - * ordering ignores annotation values when ordering. - * - *

The ordering is meant to be used as {@link TreeSet} or {@link TreeMap} ordering. A {@link - * Set} should not contain two annotations that only differ in values. - */ - public static Comparator annotationOrdering() { - return ANNOTATION_ORDERING; - } - - /** - * Create a map suitable for storing {@link AnnotationMirror} as keys. - * - *

It can store one instance of {@link AnnotationMirror} of a given declared type, regardless - * of the annotation element values. - * - * @param the value of the map - * @return a new map with {@link AnnotationMirror} as key - */ - public static Map createAnnotationMap() { - return new TreeMap(annotationOrdering()); - } - - /** - * Constructs a {@link Set} suitable for storing {@link AnnotationMirror}s. - * - *

It stores at most once instance of {@link AnnotationMirror} of a given type, regardless of - * the annotation element values. - * - * @return a new set to store {@link AnnotationMirror} as element - */ - public static Set createAnnotationSet() { - return new TreeSet(annotationOrdering()); - } - - /** Returns true if the given annotation has a @Inherited meta-annotation. */ - public static boolean hasInheritedMeta(AnnotationMirror anno) { - return anno.getAnnotationType().asElement().getAnnotation(Inherited.class) != null; - } - - // ********************************************************************** - // Extractors for annotation values - // ********************************************************************** - - /** - * Returns the values of an annotation's attributes, including defaults. The method with the - * same name in JavacElements cannot be used directly, because it includes a cast to - * Attribute.Compound, which doesn't hold for annotations generated by the Checker Framework. - * - * @see AnnotationMirror#getElementValues() - * @see JavacElements#getElementValuesWithDefaults(AnnotationMirror) - * @param ad annotation to examine - * @return the values of the annotation's elements, including defaults - */ - public static Map - getElementValuesWithDefaults(AnnotationMirror ad) { - Map valMap = - new HashMap(); - if (ad.getElementValues() != null) { - valMap.putAll(ad.getElementValues()); - } - for (ExecutableElement meth : - ElementFilter.methodsIn(ad.getAnnotationType().asElement().getEnclosedElements())) { - AnnotationValue defaultValue = meth.getDefaultValue(); - if (defaultValue != null && !valMap.containsKey(meth)) { - valMap.put(meth, defaultValue); - } - } - return valMap; - } - - /** - * Verify whether the attribute with the name {@code name} exists in the annotation {@code - * anno}. - * - * @param anno the annotation to examine - * @param name the name of the attribute - * @return whether the attribute exists in anno - */ - public static boolean hasElementValue(AnnotationMirror anno, CharSequence name) { - Map valmap = - anno.getElementValues(); - for (ExecutableElement elem : valmap.keySet()) { - if (elem.getSimpleName().contentEquals(name)) { - return true; - } - } - return false; - } - - /** - * Get the attribute with the name {@code name} of the annotation {@code anno}. The result is - * expected to have type {@code expectedType}. - * - *

Note 1: The method does not work well for attributes of an array type (as it - * would return a list of {@link AnnotationValue}s). Use {@code getElementValueArray} instead. - * - *

Note 2: The method does not work for attributes of an enum type, as the - * AnnotationValue is a VarSymbol and would be cast to the enum type, which doesn't work. Use - * {@code getElementValueEnum} instead. - * - * @param anno the annotation to disassemble - * @param name the name of the attribute to access - * @param expectedType the expected type used to cast the return type - * @param useDefaults whether to apply default values to the attribute - * @return the value of the attribute with the given name - */ - public static T getElementValue( - AnnotationMirror anno, CharSequence name, Class expectedType, boolean useDefaults) { - Map valmap; - if (useDefaults) { - valmap = getElementValuesWithDefaults(anno); - } else { - valmap = anno.getElementValues(); - } - for (ExecutableElement elem : valmap.keySet()) { - if (elem.getSimpleName().contentEquals(name)) { - AnnotationValue val = valmap.get(elem); - return expectedType.cast(val.getValue()); - } - } - ErrorReporter.errorAbort("No element with name \'" + name + "\' in annotation " + anno); - return null; // dead code - } - - /** Version that is suitable for Enum elements. */ - public static > T getElementValueEnum( - AnnotationMirror anno, CharSequence name, Class t, boolean useDefaults) { - VarSymbol vs = getElementValue(anno, name, VarSymbol.class, useDefaults); - T value = Enum.valueOf(t, vs.getSimpleName().toString()); - return value; - } - - /** - * Get the attribute with the name {@code name} of the annotation {@code anno}, where the - * attribute has an array type. One element of the result is expected to have type {@code - * expectedType}. - * - *

Parameter useDefaults is used to determine whether default values should be used for - * annotation values. Finding defaults requires more computation, so should be false when no - * defaulting is needed. - * - * @param anno the annotation to disassemble - * @param name the name of the attribute to access - * @param expectedType the expected type used to cast the return type - * @param useDefaults whether to apply default values to the attribute - * @return the value of the attribute with the given name - */ - public static List getElementValueArray( - AnnotationMirror anno, CharSequence name, Class expectedType, boolean useDefaults) { - @SuppressWarnings("unchecked") - List la = getElementValue(anno, name, List.class, useDefaults); - List result = new ArrayList(la.size()); - for (AnnotationValue a : la) { - result.add(expectedType.cast(a.getValue())); - } - return result; - } - - /** - * Get the attribute with the name {@code name} of the annotation {@code anno}, or the default - * value if no attribute is present explicitly, where the attribute has an array type and the - * elements are {@code Enum}s. One element of the result is expected to have type {@code - * expectedType}. - */ - public static > List getElementValueEnumArray( - AnnotationMirror anno, CharSequence name, Class t, boolean useDefaults) { - @SuppressWarnings("unchecked") - List la = getElementValue(anno, name, List.class, useDefaults); - List result = new ArrayList(la.size()); - for (AnnotationValue a : la) { - T value = Enum.valueOf(t, a.getValue().toString()); - result.add(value); - } - return result; - } - - /** - * Get the Name of the class that is referenced by attribute {@code name}. - * - *

This is a convenience method for the most common use-case. Like getElementValue(anno, - * name, ClassType.class).getQualifiedName(), but this method ensures consistent use of the - * qualified name. - */ - public static Name getElementValueClassName( - AnnotationMirror anno, CharSequence name, boolean useDefaults) { - Type.ClassType ct = getElementValue(anno, name, Type.ClassType.class, useDefaults); - // TODO: Is it a problem that this returns the type parameters too? Should I cut them off? - return ct.asElement().getQualifiedName(); - } - - /** Get the list of Names of the classes that are referenced by attribute {@code name}. */ - public static List getElementValueClassNames( - AnnotationMirror anno, CharSequence name, boolean useDefaults) { - List la = - getElementValueArray(anno, name, Type.ClassType.class, useDefaults); - List names = new ArrayList<>(); - for (Type.ClassType classType : la) { - names.add(classType.asElement().getQualifiedName()); - } - return names; - } - - /** - * Get the Class that is referenced by attribute {@code name}. This method uses Class.forName to - * load the class. It returns null if the class wasn't found. - */ - public static Class getElementValueClass( - AnnotationMirror anno, CharSequence name, boolean useDefaults) { - Name cn = getElementValueClassName(anno, name, useDefaults); - try { - ClassLoader classLoader = InternalUtils.getClassLoaderForClass(AnnotationUtils.class); - Class cls = Class.forName(cn.toString(), true, classLoader); - return cls; - } catch (ClassNotFoundException e) { - String msg = - String.format( - "Could not load class '%s' for field '%s' in annotation %s", - cn, name, anno); - ErrorReporter.errorAbort(msg, e); - return null; // dead code - } - } - - /** - * See checkers.types.QualifierHierarchy#updateMappingToMutableSet(QualifierHierarchy, Map, - * Object, AnnotationMirror) (Not linked because it is in an independent project. - */ - public static void updateMappingToImmutableSet( - Map> map, T key, Set newQual) { - - Set result = AnnotationUtils.createAnnotationSet(); - // TODO: if T is also an AnnotationMirror, should we use areSame? - if (!map.containsKey(key)) { - result.addAll(newQual); - } else { - result.addAll(map.get(key)); - result.addAll(newQual); - } - map.put(key, Collections.unmodifiableSet(result)); - } - - /** - * Returns the annotations explicitly written on a constructor result. Callers should check that - * {@code constructorDeclaration} is in fact a declaration of a constructor. - * - * @param constructorDeclaration declaration tree of constructor - * @return set of annotations explicit on the resulting type of the constructor - */ - public static Set getExplicitAnnotationsOnConstructorResult( - MethodTree constructorDeclaration) { - Set annotationSet = AnnotationUtils.createAnnotationSet(); - ModifiersTree modifiersTree = constructorDeclaration.getModifiers(); - if (modifiersTree != null) { - List annotationTrees = modifiersTree.getAnnotations(); - annotationSet.addAll(InternalUtils.annotationsFromTypeAnnotationTrees(annotationTrees)); - } - return annotationSet; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java deleted file mode 100644 index 6cf40e79cfa9c0..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.checkerframework.javacutil; - -import com.sun.source.tree.Tree; -import java.lang.annotation.Annotation; -import java.util.List; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; - -public class BasicAnnotationProvider implements AnnotationProvider { - - @Override - public AnnotationMirror getDeclAnnotation(Element elt, Class anno) { - List annotationMirrors = elt.getAnnotationMirrors(); - - // Then look at the real annotations. - for (AnnotationMirror am : annotationMirrors) { - if (AnnotationUtils.areSameByClass(am, anno)) { - return am; - } - } - - return null; - } - - @Override - public AnnotationMirror getAnnotationMirror(Tree tree, Class target) { - return null; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java deleted file mode 100644 index 6b68fa4dc23be3..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.checkerframework.javacutil; - -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.TreePath; -import com.sun.source.util.TreePathScanner; -import javax.lang.model.element.TypeElement; - -/** - * Process the types in an AST in a trivial manner, with hooks for derived classes to actually do - * something. - */ -public abstract class BasicTypeProcessor extends AbstractTypeProcessor { - /** The source tree that's being scanned. */ - protected CompilationUnitTree currentRoot; - - /** Create a TreePathScanner at the given root. */ - protected abstract TreePathScanner createTreePathScanner(CompilationUnitTree root); - - /** Visit the tree path for the type element. */ - @Override - public void typeProcess(TypeElement e, TreePath p) { - currentRoot = p.getCompilationUnit(); - - TreePathScanner scanner = null; - try { - scanner = createTreePathScanner(currentRoot); - scanner.scan(p, null); - } catch (Throwable t) { - System.err.println( - "BasicTypeProcessor.typeProcess: unexpected Throwable (" - + t.getClass().getSimpleName() - + ") when processing " - + currentRoot.getSourceFile().getName() - + (t.getMessage() != null ? "; message: " + t.getMessage() : "")); - } - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java deleted file mode 100644 index a6a58250fc0f49..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.checkerframework.javacutil; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** Utility methods related to Java Collections */ -public class CollectionUtils { - - /** - * A Utility method for creating LRU cache - * - * @param size size of the cache - * @return a new cache with the provided size - */ - public static Map createLRUCache(final int size) { - return new LinkedHashMap() { - - private static final long serialVersionUID = 5261489276168775084L; - - @Override - protected boolean removeEldestEntry(Map.Entry entry) { - return size() > size; - } - }; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java deleted file mode 100644 index 4abfa86cb77b9b..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java +++ /dev/null @@ -1,492 +0,0 @@ -package org.checkerframework.javacutil; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import static com.sun.tools.javac.code.Flags.ABSTRACT; -import static com.sun.tools.javac.code.Flags.EFFECTIVELY_FINAL; -import static com.sun.tools.javac.code.Flags.FINAL; - -import com.sun.tools.javac.code.Symbol; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; -import javax.lang.model.util.Elements; - -/** A Utility class for analyzing {@code Element}s. */ -public class ElementUtils { - - // Class cannot be instantiated. - private ElementUtils() { - throw new AssertionError("Class ElementUtils cannot be instantiated."); - } - - /** - * Returns the innermost type element enclosing the given element - * - * @param elem the enclosed element of a class - * @return the innermost type element - */ - public static TypeElement enclosingClass(final Element elem) { - Element result = elem; - while (result != null && !result.getKind().isClass() && !result.getKind().isInterface()) { - /*@Nullable*/ Element encl = result.getEnclosingElement(); - result = encl; - } - return (TypeElement) result; - } - - /** - * Returns the innermost package element enclosing the given element. The same effect as {@link - * javax.lang.model.util.Elements#getPackageOf(Element)}. Returns the element itself if it is a - * package. - * - * @param elem the enclosed element of a package - * @return the innermost package element - */ - public static PackageElement enclosingPackage(final Element elem) { - Element result = elem; - while (result != null && result.getKind() != ElementKind.PACKAGE) { - /*@Nullable*/ Element encl = result.getEnclosingElement(); - result = encl; - } - return (PackageElement) result; - } - - /** - * Returns the "parent" package element for the given package element. For package "A.B" it - * gives "A". For package "A" it gives the default package. For the default package it returns - * null; - * - *

Note that packages are not enclosed within each other, we have to manually climb the - * namespaces. Calling "enclosingPackage" on a package element returns the package element - * itself again. - * - * @param elem the package to start from - * @return the parent package element - */ - public static PackageElement parentPackage(final Elements e, final PackageElement elem) { - // The following might do the same thing: - // ((Symbol) elt).owner; - // TODO: verify and see whether the change is worth it. - String fqnstart = elem.getQualifiedName().toString(); - String fqn = fqnstart; - if (fqn != null && !fqn.isEmpty() && fqn.contains(".")) { - fqn = fqn.substring(0, fqn.lastIndexOf('.')); - return e.getPackageElement(fqn); - } - return null; - } - - /** - * Returns true if the element is a static element: whether it is a static field, static method, - * or static class - * - * @return true if element is static - */ - public static boolean isStatic(Element element) { - return element.getModifiers().contains(Modifier.STATIC); - } - - /** - * Returns true if the element is a final element: a final field, final method, or final class - * - * @return true if the element is final - */ - public static boolean isFinal(Element element) { - return element.getModifiers().contains(Modifier.FINAL); - } - - /** - * Returns true if the element is a effectively final element. - * - * @return true if the element is effectively final - */ - public static boolean isEffectivelyFinal(Element element) { - Symbol sym = (Symbol) element; - if (sym.getEnclosingElement().getKind() == ElementKind.METHOD - && (sym.getEnclosingElement().flags() & ABSTRACT) != 0) { - return true; - } - return (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0; - } - - /** - * Returns the {@code TypeMirror} for usage of Element as a value. It returns the return type of - * a method element, the class type of a constructor, or simply the type mirror of the element - * itself. - * - * @return the type for the element used as a value - */ - public static TypeMirror getType(Element element) { - if (element.getKind() == ElementKind.METHOD) { - return ((ExecutableElement) element).getReturnType(); - } else if (element.getKind() == ElementKind.CONSTRUCTOR) { - return enclosingClass(element).asType(); - } else { - return element.asType(); - } - } - - /** - * Returns the qualified name of the inner most class enclosing the provided {@code Element} - * - * @param element an element enclosed by a class, or a {@code TypeElement} - * @return the qualified {@code Name} of the innermost class enclosing the element - */ - public static /*@Nullable*/ Name getQualifiedClassName(Element element) { - if (element.getKind() == ElementKind.PACKAGE) { - PackageElement elem = (PackageElement) element; - return elem.getQualifiedName(); - } - - TypeElement elem = enclosingClass(element); - if (elem == null) { - return null; - } - - return elem.getQualifiedName(); - } - - /** Returns a verbose name that identifies the element. */ - public static String getVerboseName(Element elt) { - if (elt.getKind() == ElementKind.PACKAGE - || elt.getKind().isClass() - || elt.getKind().isInterface()) { - return getQualifiedClassName(elt).toString(); - } else { - return getQualifiedClassName(elt) + "." + elt.toString(); - } - } - - /** - * Check if the element is an element for 'java.lang.Object' - * - * @param element the type element - * @return true iff the element is java.lang.Object element - */ - public static boolean isObject(TypeElement element) { - return element.getQualifiedName().contentEquals("java.lang.Object"); - } - - /** Returns true if the element is a constant time reference */ - public static boolean isCompileTimeConstant(Element elt) { - return elt != null - && (elt.getKind() == ElementKind.FIELD - || elt.getKind() == ElementKind.LOCAL_VARIABLE) - && ((VariableElement) elt).getConstantValue() != null; - } - - /** - * Returns true if the element is declared in ByteCode. Always return false if elt is a package. - */ - public static boolean isElementFromByteCode(Element elt) { - if (elt == null) { - return false; - } - - if (elt instanceof Symbol.ClassSymbol) { - Symbol.ClassSymbol clss = (Symbol.ClassSymbol) elt; - if (null != clss.classfile) { - // The class file could be a .java file - return clss.classfile.getName().endsWith(".class"); - } else { - return false; - } - } - return isElementFromByteCode(elt.getEnclosingElement(), elt); - } - - /** - * Returns true if the element is declared in ByteCode. Always return false if elt is a package. - */ - private static boolean isElementFromByteCode(Element elt, Element orig) { - if (elt == null) { - return false; - } - if (elt instanceof Symbol.ClassSymbol) { - Symbol.ClassSymbol clss = (Symbol.ClassSymbol) elt; - if (null != clss.classfile) { - // The class file could be a .java file - return (clss.classfile.getName().endsWith(".class") - || clss.classfile.getName().endsWith(".class)") - || clss.classfile.getName().endsWith(".class)]")); - } else { - return false; - } - } - return isElementFromByteCode(elt.getEnclosingElement(), elt); - } - - /** Returns the field of the class */ - public static VariableElement findFieldInType(TypeElement type, String name) { - for (VariableElement field : ElementFilter.fieldsIn(type.getEnclosedElements())) { - if (field.getSimpleName().toString().equals(name)) { - return field; - } - } - return null; - } - - /** - * Returns the elements of the fields whose simple names are {@code names} and are declared in - * {@code type}. - * - *

If a field isn't declared in {@code type}, its element isn't included in the returned set. - * If none of the fields is declared in {@code type}, the empty set is returned. - * - * @param type where to look for fields - * @param names simple names of fields that might be declared in {@code type} - * @return the elements of the fields whose simple names are {@code names} and are declared in - * {@code type} - */ - public static Set findFieldsInType( - TypeElement type, Collection names) { - Set results = new HashSet(); - for (VariableElement field : ElementFilter.fieldsIn(type.getEnclosedElements())) { - if (names.contains(field.getSimpleName().toString())) { - results.add(field); - } - } - return results; - } - - /** - * Returns non-private field elements, and side-effects {@code names} to remove them. For every - * field name in {@code names} that is declared in {@code type} or a supertype, add its element - * to the returned set and remove it from {@code names}. - * - *

When this routine returns, the combination of the return value and {@code names} has the - * same cardinality, and represents the same fields, as {@code names} did when the method was - * called. - * - * @param type where to look for fields - * @param names simple names of fields that might be declared in {@code type} or a supertype. - * (Names that are found are removed from this list.) - * @return the {@code VariableElement}s for non-private fields that are declared in {@code type} - * whose simple names were in {@code names} when the method was called. - */ - public static Set findFieldsInTypeOrSuperType( - TypeMirror type, Collection names) { - Set elements = new HashSet<>(); - findFieldsInTypeOrSuperType(type, names, elements); - return elements; - } - - /** - * Side-effects both {@code foundFields} (which starts empty) and {@code notFound}, conceptually - * moving elements from {@code notFound} to {@code foundFields}. - */ - private static void findFieldsInTypeOrSuperType( - TypeMirror type, Collection notFound, Set foundFields) { - if (TypesUtils.isObject(type)) { - return; - } - TypeElement elt = InternalUtils.getTypeElement(type); - - Set fieldElts = findFieldsInType(elt, notFound); - for (VariableElement field : new HashSet<>(fieldElts)) { - if (!field.getModifiers().contains(Modifier.PRIVATE)) { - notFound.remove(field.getSimpleName().toString()); - } else { - fieldElts.remove(field); - } - } - foundFields.addAll(fieldElts); - - if (!notFound.isEmpty()) { - findFieldsInTypeOrSuperType(elt.getSuperclass(), notFound, foundFields); - } - } - - public static boolean isError(Element element) { - return element.getClass() - .getName() - .equals("com.sun.tools.javac.comp.Resolve$SymbolNotFoundError"); - } - - /** - * Does the given element need a receiver for accesses? For example, an access to a local - * variable does not require a receiver. - * - * @param element the element to test - * @return whether the element requires a receiver for accesses - */ - public static boolean hasReceiver(Element element) { - return (element.getKind().isField() - || element.getKind() == ElementKind.METHOD - || element.getKind() == ElementKind.CONSTRUCTOR) - && !ElementUtils.isStatic(element); - } - - /** - * Determine all type elements for the classes and interfaces referenced (directly or - * indirectly) in the extends/implements clauses of the given type element. - * - *

TODO: can we learn from the implementation of - * com.sun.tools.javac.model.JavacElements.getAllMembers(TypeElement)? - */ - public static List getSuperTypes(Elements elements, TypeElement type) { - - List superelems = new ArrayList(); - if (type == null) { - return superelems; - } - - // Set up a stack containing type, which is our starting point. - Deque stack = new ArrayDeque(); - stack.push(type); - - while (!stack.isEmpty()) { - TypeElement current = stack.pop(); - - // For each direct supertype of the current type element, if it - // hasn't already been visited, push it onto the stack and - // add it to our superelems set. - TypeMirror supertypecls; - try { - supertypecls = current.getSuperclass(); - } catch (com.sun.tools.javac.code.Symbol.CompletionFailure cf) { - // Looking up a supertype failed. This sometimes happens - // when transitive dependencies are not on the classpath. - // As javac didn't complain, let's also not complain. - // TODO: Use an expanded ErrorReporter to output a message. - supertypecls = null; - } - - if (supertypecls != null && supertypecls.getKind() != TypeKind.NONE) { - TypeElement supercls = (TypeElement) ((DeclaredType) supertypecls).asElement(); - if (!superelems.contains(supercls)) { - stack.push(supercls); - superelems.add(supercls); - } - } - - for (TypeMirror supertypeitf : current.getInterfaces()) { - TypeElement superitf = (TypeElement) ((DeclaredType) supertypeitf).asElement(); - if (!superelems.contains(superitf)) { - stack.push(superitf); - superelems.add(superitf); - } - } - } - - // Include java.lang.Object as implicit superclass for all classes and interfaces. - TypeElement jlobject = elements.getTypeElement("java.lang.Object"); - if (!superelems.contains(jlobject)) { - superelems.add(jlobject); - } - - return Collections.unmodifiableList(superelems); - } - - /** - * Return all fields declared in the given type or any superclass/interface. TODO: should this - * use javax.lang.model.util.Elements.getAllMembers(TypeElement) instead of our own - * getSuperTypes? - */ - public static List getAllFieldsIn(Elements elements, TypeElement type) { - List fields = new ArrayList(); - fields.addAll(ElementFilter.fieldsIn(type.getEnclosedElements())); - List alltypes = getSuperTypes(elements, type); - for (TypeElement atype : alltypes) { - fields.addAll(ElementFilter.fieldsIn(atype.getEnclosedElements())); - } - return Collections.unmodifiableList(fields); - } - - /** - * Return all methods declared in the given type or any superclass/interface. Note that no - * constructors will be returned. TODO: should this use - * javax.lang.model.util.Elements.getAllMembers(TypeElement) instead of our own getSuperTypes? - */ - public static List getAllMethodsIn(Elements elements, TypeElement type) { - List meths = new ArrayList(); - meths.addAll(ElementFilter.methodsIn(type.getEnclosedElements())); - - List alltypes = getSuperTypes(elements, type); - for (TypeElement atype : alltypes) { - meths.addAll(ElementFilter.methodsIn(atype.getEnclosedElements())); - } - return Collections.unmodifiableList(meths); - } - - public static boolean isTypeDeclaration(Element elt) { - switch (elt.getKind()) { - // These tree kinds are always declarations. Uses of the declared - // types have tree kind IDENTIFIER. - case ANNOTATION_TYPE: - case CLASS: - case ENUM: - case INTERFACE: - case TYPE_PARAMETER: - return true; - - default: - return false; - } - } - - /** - * Check that a method Element matches a signature. - * - *

Note: Matching the receiver type must be done elsewhere as the Element receiver type is - * only populated when annotated. - * - * @param method the method Element - * @param methodName the name of the method - * @param parameters the formal parameters' Classes - * @return true if the method matches - */ - public static boolean matchesElement( - ExecutableElement method, String methodName, Class... parameters) { - - if (!method.getSimpleName().toString().equals(methodName)) { - return false; - } - - if (method.getParameters().size() != parameters.length) { - return false; - } else { - for (int i = 0; i < method.getParameters().size(); i++) { - if (!method.getParameters() - .get(i) - .asType() - .toString() - .equals(parameters[i].getName())) { - - return false; - } - } - } - - return true; - } - - /** Returns true if the given element is, or overrides, method. */ - public static boolean isMethod( - ExecutableElement questioned, ExecutableElement method, ProcessingEnvironment env) { - TypeElement enclosing = (TypeElement) questioned.getEnclosingElement(); - return questioned.equals(method) - || env.getElementUtils().overrides(questioned, method, enclosing); - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java deleted file mode 100644 index 76ee74eaca7294..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.checkerframework.javacutil; - -/** - * An implementation of the ErrorHandler interface can be registered with the ErrorReporter class to - * change the default behavior on errors. - */ -public interface ErrorHandler { - - /** - * Log an error message and abort processing. - * - * @param msg the error message to log - */ - public void errorAbort(String msg); - - public void errorAbort(String msg, Throwable cause); -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java deleted file mode 100644 index 4ff62e05d1bf39..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.checkerframework.javacutil; - -/** - * Handle errors detected in utility classes. By default, the error reporter throws a - * RuntimeException, but clients of the utility library may register a handler to change the - * behavior. For example, type checkers can direct errors to the - * org.checkerframework.framework.source.SourceChecker class. - */ -public class ErrorReporter { - - protected static ErrorHandler handler = null; - - /** Register a handler to customize error reporting. */ - public static void setHandler(ErrorHandler h) { - handler = h; - } - - /** - * Log an error message and abort processing. Call this method instead of raising an exception. - * - * @param msg the error message to log - */ - public static void errorAbort(String msg) { - if (handler != null) { - handler.errorAbort(msg); - } else { - throw new RuntimeException(msg, new Throwable()); - } - } - - /** - * Log an error message use {@link String#format(String, Object...)}} and abort processing. Call - * this method instead of raising an exception. - * - * @param format a format string - * @param args arguments to the format string - */ - public static void errorAbort(String format, Object... args) { - String formattedMsg = String.format(format, args); - if (handler != null) { - handler.errorAbort(formattedMsg); - } else { - throw new RuntimeException(formattedMsg, new Throwable()); - } - } - - public static void errorAbort(String msg, Throwable cause) { - if (handler != null) { - handler.errorAbort(msg, cause); - } else { - throw new RuntimeException(msg, cause); - } - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java deleted file mode 100644 index 10a48cd719afa2..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java +++ /dev/null @@ -1,483 +0,0 @@ -package org.checkerframework.javacutil; - -import com.sun.source.tree.AnnotatedTypeTree; -import com.sun.source.tree.AnnotationTree; -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.AssignmentTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.NewArrayTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.TypeParameterTree; -import com.sun.source.util.TreePath; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.TypeSymbol; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.Type.CapturedType; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCAnnotatedType; -import com.sun.tools.javac.tree.JCTree.JCAnnotation; -import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; -import com.sun.tools.javac.tree.JCTree.JCMemberReference; -import com.sun.tools.javac.tree.JCTree.JCMethodDecl; -import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; -import com.sun.tools.javac.tree.JCTree.JCNewArray; -import com.sun.tools.javac.tree.JCTree.JCNewClass; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.WildcardType; -import javax.lang.model.util.Elements; - -/*>>> -import org.checkerframework.checker.nullness.qual.*; -*/ - -/** - * Static utility methods used by annotation abstractions in this package. Some methods in this - * class depend on the use of Sun javac internals; any procedure in the Checker Framework that uses - * a non-public API should be placed here. - */ -public class InternalUtils { - - // Class cannot be instantiated. - private InternalUtils() { - throw new AssertionError("Class InternalUtils cannot be instantiated."); - } - - /** - * Gets the {@link Element} ("symbol") for the given Tree API node. - * - * @param tree the {@link Tree} node to get the symbol for - * @throws IllegalArgumentException if {@code tree} is null or is not a valid javac-internal - * tree (JCTree) - * @return the {@link Symbol} for the given tree, or null if one could not be found - */ - public static /*@Nullable*/ Element symbol(Tree tree) { - if (tree == null) { - ErrorReporter.errorAbort("InternalUtils.symbol: tree is null"); - return null; // dead code - } - - if (!(tree instanceof JCTree)) { - ErrorReporter.errorAbort("InternalUtils.symbol: tree is not a valid Javac tree"); - return null; // dead code - } - - if (TreeUtils.isExpressionTree(tree)) { - tree = TreeUtils.skipParens((ExpressionTree) tree); - } - - switch (tree.getKind()) { - case VARIABLE: - case METHOD: - case CLASS: - case ENUM: - case INTERFACE: - case ANNOTATION_TYPE: - case TYPE_PARAMETER: - return TreeInfo.symbolFor((JCTree) tree); - - // symbol() only works on MethodSelects, so we need to get it manually - // for method invocations. - case METHOD_INVOCATION: - return TreeInfo.symbol(((JCMethodInvocation) tree).getMethodSelect()); - - case ASSIGNMENT: - return TreeInfo.symbol((JCTree) ((AssignmentTree) tree).getVariable()); - - case ARRAY_ACCESS: - return symbol(((ArrayAccessTree) tree).getExpression()); - - case NEW_CLASS: - return ((JCNewClass) tree).constructor; - - case MEMBER_REFERENCE: - // TreeInfo.symbol, which is used in the default case, didn't handle - // member references until JDK8u20. So handle it here. - return ((JCMemberReference) tree).sym; - - default: - return TreeInfo.symbol((JCTree) tree); - } - } - - /** - * Determines whether or not the node referred to by the given {@link TreePath} is an anonymous - * constructor (the constructor for an anonymous class. - * - * @param method the {@link TreePath} for a node that may be an anonymous constructor - * @return true if the given path points to an anonymous constructor, false if it does not - */ - public static boolean isAnonymousConstructor(final MethodTree method) { - /*@Nullable*/ Element e = InternalUtils.symbol(method); - if (e == null || !(e instanceof Symbol)) { - return false; - } - - if ((((/*@NonNull*/ Symbol) e).flags() & Flags.ANONCONSTR) != 0) { - return true; - } - - return false; - } - - /** - * indicates whether it should return the constructor that gets invoked in cases of anonymous - * classes - */ - private static final boolean RETURN_INVOKE_CONSTRUCTOR = true; - - /** - * Determines the symbol for a constructor given an invocation via {@code new}. - * - *

If the tree is a declaration of an anonymous class, then method returns constructor that - * gets invoked in the extended class, rather than the anonymous constructor implicitly added by - * the constructor (JLS 15.9.5.1) - * - * @param tree the constructor invocation - * @return the {@link ExecutableElement} corresponding to the constructor call in {@code tree} - */ - public static ExecutableElement constructor(NewClassTree tree) { - - if (!(tree instanceof JCTree.JCNewClass)) { - ErrorReporter.errorAbort("InternalUtils.constructor: not a javac internal tree"); - return null; // dead code - } - - JCNewClass newClassTree = (JCNewClass) tree; - - if (RETURN_INVOKE_CONSTRUCTOR && tree.getClassBody() != null) { - // anonymous constructor bodies should contain exactly one statement - // in the form: - // super(arg1, ...) - // or - // o.super(arg1, ...) - // - // which is a method invocation (!) to the actual constructor - - // the method call is guaranteed to return nonnull - JCMethodDecl anonConstructor = - (JCMethodDecl) TreeInfo.declarationFor(newClassTree.constructor, newClassTree); - assert anonConstructor != null; - assert anonConstructor.body.stats.size() == 1; - JCExpressionStatement stmt = (JCExpressionStatement) anonConstructor.body.stats.head; - JCTree.JCMethodInvocation superInvok = (JCMethodInvocation) stmt.expr; - return (ExecutableElement) TreeInfo.symbol(superInvok.meth); - } - - Element e = newClassTree.constructor; - - assert e instanceof ExecutableElement; - - return (ExecutableElement) e; - } - - public static final List annotationsFromTypeAnnotationTrees( - List annos) { - List annotations = new ArrayList(annos.size()); - for (AnnotationTree anno : annos) { - annotations.add(annotationFromAnnotationTree(anno)); - } - return annotations; - } - - public static AnnotationMirror annotationFromAnnotationTree(AnnotationTree tree) { - return ((JCAnnotation) tree).attribute; - } - - public static final List annotationsFromTree( - AnnotatedTypeTree node) { - return annotationsFromTypeAnnotationTrees(((JCAnnotatedType) node).annotations); - } - - public static final List annotationsFromTree( - TypeParameterTree node) { - return annotationsFromTypeAnnotationTrees(((JCTypeParameter) node).annotations); - } - - public static final List annotationsFromArrayCreation( - NewArrayTree node, int level) { - - assert node instanceof JCNewArray; - final JCNewArray newArray = ((JCNewArray) node); - - if (level == -1) { - return annotationsFromTypeAnnotationTrees(newArray.annotations); - } - - if (newArray.dimAnnotations.length() > 0 - && (level >= 0) - && (level < newArray.dimAnnotations.size())) - return annotationsFromTypeAnnotationTrees(newArray.dimAnnotations.get(level)); - - return Collections.emptyList(); - } - - public static TypeMirror typeOf(Tree tree) { - return ((JCTree) tree).type; - } - - /** Returns whether a TypeVariable represents a captured type. */ - public static boolean isCaptured(TypeVariable typeVar) { - return ((Type.TypeVar) TypeAnnotationUtils.unannotatedType(typeVar)).isCaptured(); - } - - /** If typeVar is a captured wildcard, returns that wildcard; otherwise returns null. */ - public static WildcardType getCapturedWildcard(TypeVariable typeVar) { - if (isCaptured(typeVar)) { - return ((CapturedType) TypeAnnotationUtils.unannotatedType(typeVar)).wildcard; - } - return null; - } - - /** Returns whether a TypeMirror represents a class type. */ - public static boolean isClassType(TypeMirror type) { - return (type instanceof Type.ClassType); - } - - /** - * Returns the least upper bound of two {@link TypeMirror}s, ignoring any annotations on the - * types. - * - *

Wrapper around Types.lub to add special handling for null types, primitives, and - * wildcards. - * - * @param processingEnv the {@link ProcessingEnvironment} to use - * @param tm1 a {@link TypeMirror} - * @param tm2 a {@link TypeMirror} - * @return the least upper bound of {@code tm1} and {@code tm2}. - */ - public static TypeMirror leastUpperBound( - ProcessingEnvironment processingEnv, TypeMirror tm1, TypeMirror tm2) { - Type t1 = TypeAnnotationUtils.unannotatedType(tm1); - Type t2 = TypeAnnotationUtils.unannotatedType(tm2); - JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv; - Types types = Types.instance(javacEnv.getContext()); - if (types.isSameType(t1, t2)) { - // Special case if the two types are equal. - return t1; - } - // Handle the 'null' type manually (not done by types.lub). - if (t1.getKind() == TypeKind.NULL) { - return t2; - } - if (t2.getKind() == TypeKind.NULL) { - return t1; - } - if (t1.getKind() == TypeKind.WILDCARD) { - WildcardType wc1 = (WildcardType) t1; - Type bound = (Type) wc1.getExtendsBound(); - if (bound == null) { - // Implicit upper bound of java.lang.Object - Elements elements = processingEnv.getElementUtils(); - return elements.getTypeElement("java.lang.Object").asType(); - } - t1 = bound; - } - if (t2.getKind() == TypeKind.WILDCARD) { - WildcardType wc2 = (WildcardType) t2; - Type bound = (Type) wc2.getExtendsBound(); - if (bound == null) { - // Implicit upper bound of java.lang.Object - Elements elements = processingEnv.getElementUtils(); - return elements.getTypeElement("java.lang.Object").asType(); - } - t2 = bound; - } - // Special case for primitives. - if (TypesUtils.isPrimitive(t1) || TypesUtils.isPrimitive(t2)) { - if (types.isAssignable(t1, t2)) { - return t2; - } else if (types.isAssignable(t2, t1)) { - return t1; - } else { - Elements elements = processingEnv.getElementUtils(); - return elements.getTypeElement("java.lang.Object").asType(); - } - } - return types.lub(t1, t2); - } - - /** - * Returns the greatest lower bound of two {@link TypeMirror}s, ignoring any annotations on the - * types. - * - *

Wrapper around Types.glb to add special handling for null types, primitives, and - * wildcards. - * - * @param processingEnv the {@link ProcessingEnvironment} to use - * @param tm1 a {@link TypeMirror} - * @param tm2 a {@link TypeMirror} - * @return the greatest lower bound of {@code tm1} and {@code tm2}. - */ - public static TypeMirror greatestLowerBound( - ProcessingEnvironment processingEnv, TypeMirror tm1, TypeMirror tm2) { - Type t1 = TypeAnnotationUtils.unannotatedType(tm1); - Type t2 = TypeAnnotationUtils.unannotatedType(tm2); - JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv; - Types types = Types.instance(javacEnv.getContext()); - if (types.isSameType(t1, t2)) { - // Special case if the two types are equal. - return t1; - } - // Handle the 'null' type manually. - if (t1.getKind() == TypeKind.NULL) { - return t1; - } - if (t2.getKind() == TypeKind.NULL) { - return t2; - } - // Special case for primitives. - if (TypesUtils.isPrimitive(t1) || TypesUtils.isPrimitive(t2)) { - if (types.isAssignable(t1, t2)) { - return t1; - } else if (types.isAssignable(t2, t1)) { - return t2; - } else { - // Javac types.glb returns TypeKind.Error when the GLB does - // not exist, but we can't create one. Use TypeKind.NONE - // instead. - return processingEnv.getTypeUtils().getNoType(TypeKind.NONE); - } - } - if (t1.getKind() == TypeKind.WILDCARD) { - return t2; - } - if (t2.getKind() == TypeKind.WILDCARD) { - return t1; - } - - // If neither type is a primitive type, null type, or wildcard - // and if the types are not the same, use javac types.glb - return types.glb(t1, t2); - } - - /** - * Returns the return type of a method, where the "raw" return type of that method is given - * (i.e., the return type might still contain unsubstituted type variables), given the receiver - * of the method call. - */ - public static TypeMirror substituteMethodReturnType( - TypeMirror methodType, TypeMirror substitutedReceiverType) { - if (methodType.getKind() != TypeKind.TYPEVAR) { - return methodType; - } - // TODO: find a nicer way to substitute type variables - String t = TypeAnnotationUtils.unannotatedType(methodType).toString(); - Type finalReceiverType = (Type) substitutedReceiverType; - int i = 0; - for (TypeSymbol typeParam : finalReceiverType.tsym.getTypeParameters()) { - if (t.equals(typeParam.toString())) { - return finalReceiverType.getTypeArguments().get(i); - } - i++; - } - assert false; - return null; - } - - /** - * Helper function to extract the javac Context from the javac processing environment. - * - * @param env the processing environment - * @return the javac Context - */ - public static Context getJavacContext(ProcessingEnvironment env) { - return ((JavacProcessingEnvironment) env).getContext(); - } - - /** - * Returns the type element for {@code type} if {@code type} is a class, interface, annotation - * type, or enum. Otherwise, returns null. - * - * @param type whose element is returned - * @return the type element for {@code type} if {@code type} is a class, interface, annotation - * type, or enum; otherwise, returns null - */ - public static TypeElement getTypeElement(TypeMirror type) { - Element element = ((Type) type).asElement(); - switch (element.getKind()) { - case ANNOTATION_TYPE: - case CLASS: - case ENUM: - case INTERFACE: - return (TypeElement) element; - default: - return null; - } - } - - /** - * Obtain the class loader for {@code clazz}. If that is not available, return the system class - * loader. - * - * @param clazz the class whose class loader to find - * @return the class loader used to {@code clazz}, or the system class loader, or null if both - * are unavailable - */ - public static ClassLoader getClassLoaderForClass(Class clazz) { - ClassLoader classLoader = clazz.getClassLoader(); - return classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader; - } - - /** - * Compares tree1 to tree2 by the position at which a diagnostic (e.g., an error message) for - * the tree should be printed. - */ - public static int compareDiagnosticPosition(Tree tree1, Tree tree2) { - DiagnosticPosition pos1 = (DiagnosticPosition) tree1; - DiagnosticPosition pos2 = (DiagnosticPosition) tree2; - - int preferred = Integer.compare(pos1.getPreferredPosition(), pos2.getPreferredPosition()); - if (preferred != 0) { - return preferred; - } - - return Integer.compare(pos1.getStartPosition(), pos2.getStartPosition()); - } - - /** - * Returns whether or not {@code type} is a functional interface type (as defined in JLS 9.8). - * - * @param type possible functional interface type - * @param env ProcessingEnvironment - * @return whether or not {@code type} is a functional interface type (as defined in JLS 9.8) - */ - public static boolean isFunctionalInterface(TypeMirror type, ProcessingEnvironment env) { - Context ctx = ((JavacProcessingEnvironment) env).getContext(); - com.sun.tools.javac.code.Types javacTypes = com.sun.tools.javac.code.Types.instance(ctx); - return javacTypes.isFunctionalInterface((Type) type); - } - - /** - * The type of the lambda or method reference tree is a functional interface type. This method - * returns the single abstract method declared by that functional interface. (The type of this - * method is referred to as the function type.) - * - * @param tree lambda or member reference tree - * @param env ProcessingEnvironment - * @return the single abstract method declared by the type of the tree - */ - public static Symbol findFunction(Tree tree, ProcessingEnvironment env) { - Context ctx = ((JavacProcessingEnvironment) env).getContext(); - com.sun.tools.javac.code.Types javacTypes = com.sun.tools.javac.code.Types.instance(ctx); - return javacTypes.findDescriptorSymbol(((Type) typeOf(tree)).asElement()); - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java deleted file mode 100644 index 161af826058f78..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.checkerframework.javacutil; - -/*>>> -import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectFree; -*/ - -/** - * Simple pair class for multiple returns. - * - *

TODO: as class is immutable, use @Covariant annotation. - */ -public class Pair { - public final V1 first; - public final V2 second; - - private Pair(V1 v1, V2 v2) { - this.first = v1; - this.second = v2; - } - - public static Pair of(V1 v1, V2 v2) { - return new Pair(v1, v2); - } - - /*@SideEffectFree*/ - @Override - public String toString() { - return "Pair(" + first + ", " + second + ")"; - } - - private int hashCode = -1; - - /*@Pure*/ - @Override - public int hashCode() { - if (hashCode == -1) { - hashCode = 31; - if (first != null) { - hashCode += 17 * first.hashCode(); - } - if (second != null) { - hashCode += 17 * second.hashCode(); - } - } - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof Pair)) { - return false; - } - @SuppressWarnings("unchecked") - Pair other = (Pair) o; - if (this.first == null) { - if (other.first != null) return false; - } else { - if (!this.first.equals(other.first)) return false; - } - if (this.second == null) { - if (other.second != null) return false; - } else { - if (!this.second.equals(other.second)) return false; - } - - return true; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java deleted file mode 100644 index 361c6aef99c6d2..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java +++ /dev/null @@ -1,397 +0,0 @@ -package org.checkerframework.javacutil; - -import static com.sun.tools.javac.code.Kinds.PCK; -import static com.sun.tools.javac.code.Kinds.TYP; -import static com.sun.tools.javac.code.Kinds.VAR; - -import com.sun.source.util.TreePath; -import com.sun.source.util.Trees; -import com.sun.tools.javac.api.JavacScope; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.ClassSymbol; -import com.sun.tools.javac.code.Symbol.PackageSymbol; -import com.sun.tools.javac.code.Symbol.TypeSymbol; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.comp.AttrContext; -import com.sun.tools.javac.comp.DeferredAttr; -import com.sun.tools.javac.comp.Env; -import com.sun.tools.javac.comp.Resolve; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Name; -import com.sun.tools.javac.util.Names; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; - -/** A Utility class to find symbols corresponding to string references. */ -public class Resolver { - private final Resolve resolve; - private final Names names; - private final Trees trees; - private final Log log; - - private static final Method FIND_METHOD; - private static final Method FIND_VAR; - private static final Method FIND_IDENT; - private static final Method FIND_IDENT_IN_TYPE; - private static final Method FIND_IDENT_IN_PACKAGE; - private static final Method FIND_TYPE; - - private static final Class ACCESSERROR; - // Note that currently access(...) is defined in InvalidSymbolError, a superclass of AccessError - private static final Method ACCESSERROR_ACCESS; - - static { - try { - FIND_METHOD = - Resolve.class.getDeclaredMethod( - "findMethod", - Env.class, - Type.class, - Name.class, - List.class, - List.class, - boolean.class, - boolean.class, - boolean.class); - FIND_METHOD.setAccessible(true); - - FIND_VAR = Resolve.class.getDeclaredMethod("findVar", Env.class, Name.class); - FIND_VAR.setAccessible(true); - - FIND_IDENT = - Resolve.class.getDeclaredMethod("findIdent", Env.class, Name.class, int.class); - FIND_IDENT.setAccessible(true); - - FIND_IDENT_IN_TYPE = - Resolve.class.getDeclaredMethod( - "findIdentInType", Env.class, Type.class, Name.class, int.class); - FIND_IDENT_IN_TYPE.setAccessible(true); - - FIND_IDENT_IN_PACKAGE = - Resolve.class.getDeclaredMethod( - "findIdentInPackage", - Env.class, - TypeSymbol.class, - Name.class, - int.class); - FIND_IDENT_IN_PACKAGE.setAccessible(true); - - FIND_TYPE = Resolve.class.getDeclaredMethod("findType", Env.class, Name.class); - FIND_TYPE.setAccessible(true); - } catch (Exception e) { - Error err = - new AssertionError( - "Compiler 'Resolve' class doesn't contain required 'find' method"); - err.initCause(e); - throw err; - } - - try { - ACCESSERROR = Class.forName("com.sun.tools.javac.comp.Resolve$AccessError"); - ACCESSERROR_ACCESS = ACCESSERROR.getMethod("access", Name.class, TypeSymbol.class); - ACCESSERROR_ACCESS.setAccessible(true); - } catch (ClassNotFoundException e) { - ErrorReporter.errorAbort( - "Compiler 'Resolve$AccessError' class could not be retrieved.", e); - // Unreachable code - needed so the compiler does not warn about a possibly uninitialized final field. - throw new AssertionError(); - } catch (NoSuchMethodException e) { - ErrorReporter.errorAbort( - "Compiler 'Resolve$AccessError' class doesn't contain required 'access' method", - e); - // Unreachable code - needed so the compiler does not warn about a possibly uninitialized final field. - throw new AssertionError(); - } - } - - public Resolver(ProcessingEnvironment env) { - Context context = ((JavacProcessingEnvironment) env).getContext(); - this.resolve = Resolve.instance(context); - this.names = Names.instance(context); - this.trees = Trees.instance(env); - this.log = Log.instance(context); - } - - /** - * Determine the environment for the given path. - * - * @param path the tree path to the local scope - * @return the corresponding attribution environment - */ - public Env getEnvForPath(TreePath path) { - TreePath iter = path; - JavacScope scope = null; - while (scope == null && iter != null) { - try { - scope = (JavacScope) trees.getScope(iter); - } catch (Throwable t) { - // Work around Issue #1059 by skipping through the TreePath until something - // doesn't crash. This probably returns the class scope, so users might not - // get the variables they expect. But that is better than crashing. - iter = iter.getParentPath(); - } - } - if (scope != null) { - return scope.getEnv(); - } else { - ErrorReporter.errorAbort( - "Could not determine any possible scope for path: " + path.getLeaf()); - return null; - } - } - - /** - * Finds the package with name {@code name}. - * - * @param name the name of the package - * @param path the tree path to the local scope - * @return the {@code PackageSymbol} for the package if it is found, {@code null} otherwise - */ - public PackageSymbol findPackage(String name, TreePath path) { - Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log); - try { - Env env = getEnvForPath(path); - Element res = - wrapInvocationOnResolveInstance(FIND_IDENT, env, names.fromString(name), PCK); - // findIdent will return a PackageSymbol even for a symbol that is not a package, - // such as a.b.c.MyClass.myStaticField. "exists()" must be called on it to ensure - // that it exists. - if (res.getKind() == ElementKind.PACKAGE) { - PackageSymbol ps = (PackageSymbol) res; - return ps.exists() ? ps : null; - } else { - return null; - } - } finally { - log.popDiagnosticHandler(discardDiagnosticHandler); - } - } - - /** - * Finds the field with name {@code name} in a given type. - * - *

The method adheres to all the rules of Java's scoping (while also considering the imports) - * for name resolution. - * - * @param name the name of the field - * @param type the type of the receiver (i.e., the type in which to look for the field). - * @param path the tree path to the local scope - * @return the element for the field - */ - public VariableElement findField(String name, TypeMirror type, TreePath path) { - Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log); - try { - Env env = getEnvForPath(path); - Element res = - wrapInvocationOnResolveInstance( - FIND_IDENT_IN_TYPE, env, type, names.fromString(name), VAR); - if (res.getKind() == ElementKind.FIELD) { - return (VariableElement) res; - } else if (res.getKind() == ElementKind.OTHER && ACCESSERROR.isInstance(res)) { - // Return the inaccessible field that was found - return (VariableElement) wrapInvocation(res, ACCESSERROR_ACCESS, null, null); - } else { - // Most likely didn't find the field and the Element is a SymbolNotFoundError - return null; - } - } finally { - log.popDiagnosticHandler(discardDiagnosticHandler); - } - } - - /** - * Finds the local variable with name {@code name} in the given scope. - * - * @param name the name of the local variable - * @param path the tree path to the local scope - * @return the element for the local variable - */ - public VariableElement findLocalVariableOrParameterOrField(String name, TreePath path) { - Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log); - try { - Env env = getEnvForPath(path); - Element res = wrapInvocationOnResolveInstance(FIND_VAR, env, names.fromString(name)); - if (res.getKind() == ElementKind.LOCAL_VARIABLE - || res.getKind() == ElementKind.PARAMETER - || res.getKind() == ElementKind.FIELD) { - return (VariableElement) res; - } else { - // Most likely didn't find the variable and the Element is a SymbolNotFoundError - return null; - } - } finally { - log.popDiagnosticHandler(discardDiagnosticHandler); - } - } - - /** - * Finds the class literal with name {@code name}. - * - *

The method adheres to all the rules of Java's scoping (while also considering the imports) - * for name resolution. - * - * @param name the name of the class - * @param path the tree path to the local scope - * @return the element for the class - */ - public Element findClass(String name, TreePath path) { - Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log); - try { - Env env = getEnvForPath(path); - return wrapInvocationOnResolveInstance(FIND_TYPE, env, names.fromString(name)); - } finally { - log.popDiagnosticHandler(discardDiagnosticHandler); - } - } - - /** - * Finds the class with name {@code name} in a given package. - * - * @param name the name of the class - * @param pck the PackageSymbol for the package - * @param path the tree path to the local scope - * @return the {@code ClassSymbol} for the class if it is found, {@code null} otherwise - */ - public ClassSymbol findClassInPackage(String name, PackageSymbol pck, TreePath path) { - Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log); - try { - Env env = getEnvForPath(path); - Element res = - wrapInvocationOnResolveInstance( - FIND_IDENT_IN_PACKAGE, env, pck, names.fromString(name), TYP); - if (res.getKind() == ElementKind.CLASS) { - return (ClassSymbol) res; - } else { - return null; - } - } finally { - log.popDiagnosticHandler(discardDiagnosticHandler); - } - } - - /** - * Finds the method element for a given name and list of expected parameter types. - * - *

The method adheres to all the rules of Java's scoping (while also considering the imports) - * for name resolution. - * - * @param methodName name of the method to find - * @param receiverType type of the receiver of the method - * @param path tree path - * @return the method element (if found) - */ - public Element findMethod( - String methodName, - TypeMirror receiverType, - TreePath path, - java.util.List argumentTypes) { - Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log); - try { - Env env = getEnvForPath(path); - - Type site = (Type) receiverType; - Name name = names.fromString(methodName); - List argtypes = List.nil(); - for (TypeMirror a : argumentTypes) { - argtypes = argtypes.append((Type) a); - } - List typeargtypes = List.nil(); - boolean allowBoxing = true; - boolean useVarargs = false; - boolean operator = true; - - try { - // For some reason we have to set our own method context, which is rather ugly. - // TODO: find a nicer way to do this. - Object methodContext = buildMethodContext(); - Object oldContext = getField(resolve, "currentResolutionContext"); - setField(resolve, "currentResolutionContext", methodContext); - Element result = - wrapInvocationOnResolveInstance( - FIND_METHOD, - env, - site, - name, - argtypes, - typeargtypes, - allowBoxing, - useVarargs, - operator); - setField(resolve, "currentResolutionContext", oldContext); - return result; - } catch (Throwable t) { - Error err = new AssertionError("Unexpected Reflection error"); - err.initCause(t); - throw err; - } - } finally { - log.popDiagnosticHandler(discardDiagnosticHandler); - } - } - - /** Build an instance of {@code Resolve$MethodResolutionContext}. */ - protected Object buildMethodContext() - throws ClassNotFoundException, InstantiationException, IllegalAccessException, - InvocationTargetException, NoSuchFieldException { - // Class is not accessible, instantiate reflectively. - Class methCtxClss = - Class.forName("com.sun.tools.javac.comp.Resolve$MethodResolutionContext"); - Constructor constructor = methCtxClss.getDeclaredConstructors()[0]; - constructor.setAccessible(true); - Object methodContext = constructor.newInstance(resolve); - // we need to also initialize the fields attrMode and step - setField(methodContext, "attrMode", DeferredAttr.AttrMode.CHECK); - @SuppressWarnings("rawtypes") - List phases = (List) getField(resolve, "methodResolutionSteps"); - setField(methodContext, "step", phases.get(1)); - return methodContext; - } - - /** Reflectively set a field. */ - private void setField(Object receiver, String fieldName, Object value) - throws NoSuchFieldException, IllegalAccessException { - Field f = receiver.getClass().getDeclaredField(fieldName); - f.setAccessible(true); - f.set(receiver, value); - } - - /** Reflectively get the value of a field. */ - private Object getField(Object receiver, String fieldName) - throws NoSuchFieldException, IllegalAccessException { - Field f = receiver.getClass().getDeclaredField(fieldName); - f.setAccessible(true); - return f.get(receiver); - } - - private Symbol wrapInvocationOnResolveInstance(Method method, Object... args) { - return wrapInvocation(resolve, method, args); - } - - private Symbol wrapInvocation(Object receiver, Method method, Object... args) { - try { - return (Symbol) method.invoke(receiver, args); - } catch (IllegalAccessException e) { - Error err = new AssertionError("Unexpected Reflection error"); - err.initCause(e); - throw err; - } catch (IllegalArgumentException e) { - Error err = new AssertionError("Unexpected Reflection error"); - err.initCause(e); - throw err; - } catch (InvocationTargetException e) { - Error err = new AssertionError("Unexpected Reflection error"); - err.initCause(e); - throw err; - } - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java deleted file mode 100644 index 4da97b400d04e6..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java +++ /dev/null @@ -1,1020 +0,0 @@ -package org.checkerframework.javacutil; - -/*>>> -import org.checkerframework.checker.nullness.qual.*; -*/ - -import com.sun.source.tree.AnnotatedTypeTree; -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.BlockTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.CompoundAssignmentTree; -import com.sun.source.tree.ConditionalExpressionTree; -import com.sun.source.tree.ExpressionStatementTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.MethodTree; -import com.sun.source.tree.NewClassTree; -import com.sun.source.tree.ParameterizedTypeTree; -import com.sun.source.tree.ParenthesizedTree; -import com.sun.source.tree.PrimitiveTypeTree; -import com.sun.source.tree.StatementTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.tree.TypeCastTree; -import com.sun.source.tree.VariableTree; -import com.sun.source.util.TreePath; -import com.sun.source.util.Trees; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.tree.JCTree; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.ElementFilter; - -/** A utility class made for helping to analyze a given {@code Tree}. */ -// TODO: This class needs significant restructuring -public final class TreeUtils { - - // Class cannot be instantiated. - private TreeUtils() { - throw new AssertionError("Class TreeUtils cannot be instantiated."); - } - - /** - * Checks if the provided method is a constructor method or no. - * - * @param tree a tree defining the method - * @return true iff tree describes a constructor - */ - public static boolean isConstructor(final MethodTree tree) { - return tree.getName().contentEquals(""); - } - - /** - * Checks if the method invocation is a call to super. - * - * @param tree a tree defining a method invocation - * @return true iff tree describes a call to super - */ - public static boolean isSuperCall(MethodInvocationTree tree) { - return isNamedMethodCall("super", tree); - } - - /** - * Checks if the method invocation is a call to this. - * - * @param tree a tree defining a method invocation - * @return true iff tree describes a call to this - */ - public static boolean isThisCall(MethodInvocationTree tree) { - return isNamedMethodCall("this", tree); - } - - protected static boolean isNamedMethodCall(String name, MethodInvocationTree tree) { - /*@Nullable*/ ExpressionTree mst = tree.getMethodSelect(); - assert mst != null; /*nninvariant*/ - - if (mst.getKind() == Tree.Kind.IDENTIFIER) { - return ((IdentifierTree) mst).getName().contentEquals(name); - } - - if (mst.getKind() == Tree.Kind.MEMBER_SELECT) { - MemberSelectTree selectTree = (MemberSelectTree) mst; - - if (selectTree.getExpression().getKind() != Tree.Kind.IDENTIFIER) { - return false; - } - - return ((IdentifierTree) selectTree.getExpression()).getName().contentEquals(name); - } - - return false; - } - - /** - * Returns true if the tree is a tree that 'looks like' either an access of a field or an - * invocation of a method that are owned by the same accessing instance. - * - *

It would only return true if the access tree is of the form: - * - *

-     *   field
-     *   this.field
-     *
-     *   method()
-     *   this.method()
-     * 
- * - * It does not perform any semantical check to differentiate between fields and local variables; - * local methods or imported static methods. - * - * @param tree expression tree representing an access to object member - * @return {@code true} iff the member is a member of {@code this} instance - */ - public static boolean isSelfAccess(final ExpressionTree tree) { - ExpressionTree tr = TreeUtils.skipParens(tree); - // If method invocation check the method select - if (tr.getKind() == Tree.Kind.ARRAY_ACCESS) { - return false; - } - - if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) { - tr = ((MethodInvocationTree) tree).getMethodSelect(); - } - tr = TreeUtils.skipParens(tr); - if (tr.getKind() == Tree.Kind.TYPE_CAST) { - tr = ((TypeCastTree) tr).getExpression(); - } - tr = TreeUtils.skipParens(tr); - - if (tr.getKind() == Tree.Kind.IDENTIFIER) { - return true; - } - - if (tr.getKind() == Tree.Kind.MEMBER_SELECT) { - tr = ((MemberSelectTree) tr).getExpression(); - if (tr.getKind() == Tree.Kind.IDENTIFIER) { - Name ident = ((IdentifierTree) tr).getName(); - return ident.contentEquals("this") || ident.contentEquals("super"); - } - } - - return false; - } - - /** - * Gets the first enclosing tree in path, of the specified kind. - * - * @param path the path defining the tree node - * @param kind the kind of the desired tree - * @return the enclosing tree of the given type as given by the path - */ - public static Tree enclosingOfKind(final TreePath path, final Tree.Kind kind) { - return enclosingOfKind(path, EnumSet.of(kind)); - } - - /** - * Gets the first enclosing tree in path, with any one of the specified kinds. - * - * @param path the path defining the tree node - * @param kinds the set of kinds of the desired tree - * @return the enclosing tree of the given type as given by the path - */ - public static Tree enclosingOfKind(final TreePath path, final Set kinds) { - TreePath p = path; - - while (p != null) { - Tree leaf = p.getLeaf(); - assert leaf != null; /*nninvariant*/ - if (kinds.contains(leaf.getKind())) { - return leaf; - } - p = p.getParentPath(); - } - - return null; - } - - /** - * Gets path to the first enclosing class tree, where class is defined by the classTreeKinds - * method. - * - * @param path the path defining the tree node - * @return the path to the enclosing class tree - */ - public static TreePath pathTillClass(final TreePath path) { - return pathTillOfKind(path, classTreeKinds()); - } - - /** - * Gets path to the first enclosing tree of the specified kind. - * - * @param path the path defining the tree node - * @param kind the kind of the desired tree - * @return the path to the enclosing tree of the given type - */ - public static TreePath pathTillOfKind(final TreePath path, final Tree.Kind kind) { - return pathTillOfKind(path, EnumSet.of(kind)); - } - - /** - * Gets path to the first enclosing tree with any one of the specified kinds. - * - * @param path the path defining the tree node - * @param kinds the set of kinds of the desired tree - * @return the path to the enclosing tree of the given type - */ - public static TreePath pathTillOfKind(final TreePath path, final Set kinds) { - TreePath p = path; - - while (p != null) { - Tree leaf = p.getLeaf(); - assert leaf != null; /*nninvariant*/ - if (kinds.contains(leaf.getKind())) { - return p; - } - p = p.getParentPath(); - } - - return null; - } - - /** - * Gets the first enclosing tree in path, of the specified class - * - * @param path the path defining the tree node - * @param treeClass the class of the desired tree - * @return the enclosing tree of the given type as given by the path - */ - public static T enclosingOfClass( - final TreePath path, final Class treeClass) { - TreePath p = path; - - while (p != null) { - Tree leaf = p.getLeaf(); - if (treeClass.isInstance(leaf)) { - return treeClass.cast(leaf); - } - p = p.getParentPath(); - } - - return null; - } - - /** - * Gets the enclosing class of the tree node defined by the given {@link TreePath}. It returns a - * {@link Tree}, from which {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be - * obtained. - * - * @param path the path defining the tree node - * @return the enclosing class (or interface) as given by the path, or null if one does not - * exist - */ - public static /*@Nullable*/ ClassTree enclosingClass(final /*@Nullable*/ TreePath path) { - return (ClassTree) enclosingOfKind(path, classTreeKinds()); - } - - /** - * Gets the enclosing variable of a tree node defined by the given {@link TreePath}. - * - * @param path the path defining the tree node - * @return the enclosing variable as given by the path, or null if one does not exist - */ - public static VariableTree enclosingVariable(final TreePath path) { - return (VariableTree) enclosingOfKind(path, Tree.Kind.VARIABLE); - } - - /** - * Gets the enclosing method of the tree node defined by the given {@link TreePath}. It returns - * a {@link Tree}, from which an {@code checkers.types.AnnotatedTypeMirror} or {@link Element} - * can be obtained. - * - * @param path the path defining the tree node - * @return the enclosing method as given by the path, or null if one does not exist - */ - public static /*@Nullable*/ MethodTree enclosingMethod(final /*@Nullable*/ TreePath path) { - return (MethodTree) enclosingOfKind(path, Tree.Kind.METHOD); - } - - public static /*@Nullable*/ BlockTree enclosingTopLevelBlock(TreePath path) { - TreePath parpath = path.getParentPath(); - while (parpath != null && !classTreeKinds.contains(parpath.getLeaf().getKind())) { - path = parpath; - parpath = parpath.getParentPath(); - } - if (path.getLeaf().getKind() == Tree.Kind.BLOCK) { - return (BlockTree) path.getLeaf(); - } - return null; - } - - /** - * If the given tree is a parenthesized tree, it returns the enclosed non-parenthesized tree. - * Otherwise, it returns the same tree. - * - * @param tree an expression tree - * @return the outermost non-parenthesized tree enclosed by the given tree - */ - public static ExpressionTree skipParens(final ExpressionTree tree) { - ExpressionTree t = tree; - while (t.getKind() == Tree.Kind.PARENTHESIZED) { - t = ((ParenthesizedTree) t).getExpression(); - } - return t; - } - - /** - * Returns the tree with the assignment context for the treePath leaf node. (Does not handle - * pseudo-assignment of an argument to a parameter or a receiver expression to a receiver.) - * - *

The assignment context for the {@code treePath} is the leaf of its parent, if the parent - * is one of the following trees: - * - *

    - *
  • AssignmentTree - *
  • CompoundAssignmentTree - *
  • MethodInvocationTree - *
  • NewArrayTree - *
  • NewClassTree - *
  • ReturnTree - *
  • VariableTree - *
- * - * If the parent is a ConditionalExpressionTree we need to distinguish two cases: If the leaf is - * either the then or else branch of the ConditionalExpressionTree, then recurse on the parent. - * If the leaf is the condition of the ConditionalExpressionTree, then return null to not - * consider this assignment context. - * - *

If the leaf is a ParenthesizedTree, then recurse on the parent. - * - *

Otherwise, null is returned. - * - * @return the assignment context as described - */ - public static Tree getAssignmentContext(final TreePath treePath) { - TreePath parentPath = treePath.getParentPath(); - - if (parentPath == null) { - return null; - } - - Tree parent = parentPath.getLeaf(); - switch (parent.getKind()) { - case PARENTHESIZED: - return getAssignmentContext(parentPath); - case CONDITIONAL_EXPRESSION: - ConditionalExpressionTree cet = (ConditionalExpressionTree) parent; - if (cet.getCondition() == treePath.getLeaf()) { - // The assignment context for the condition is simply boolean. - // No point in going on. - return null; - } - // Otherwise use the context of the ConditionalExpressionTree. - return getAssignmentContext(parentPath); - case ASSIGNMENT: - case METHOD_INVOCATION: - case NEW_ARRAY: - case NEW_CLASS: - case RETURN: - case VARIABLE: - return parent; - default: - // 11 Tree.Kinds are CompoundAssignmentTrees, - // so use instanceof rather than listing all 11. - if (parent instanceof CompoundAssignmentTree) { - return parent; - } - return null; - } - } - - /** - * Gets the element for a class corresponding to a declaration. - * - * @return the element for the given class - */ - public static final TypeElement elementFromDeclaration(ClassTree node) { - TypeElement elt = (TypeElement) InternalUtils.symbol(node); - return elt; - } - - /** - * Gets the element for a method corresponding to a declaration. - * - * @return the element for the given method - */ - public static final ExecutableElement elementFromDeclaration(MethodTree node) { - ExecutableElement elt = (ExecutableElement) InternalUtils.symbol(node); - return elt; - } - - /** - * Gets the element for a variable corresponding to its declaration. - * - * @return the element for the given variable - */ - public static final VariableElement elementFromDeclaration(VariableTree node) { - VariableElement elt = (VariableElement) InternalUtils.symbol(node); - return elt; - } - - /** - * Gets the element for the declaration corresponding to this use of an element. To get the - * element for a declaration, use {@link Trees#getElement(TreePath)} instead. - * - *

TODO: remove this method, as it really doesn't do anything. - * - * @param node the tree corresponding to a use of an element - * @return the element for the corresponding declaration - */ - public static final Element elementFromUse(ExpressionTree node) { - return InternalUtils.symbol(node); - } - - // Specialization for return type. - // Might return null if element wasn't found. - public static final ExecutableElement elementFromUse(MethodInvocationTree node) { - Element el = elementFromUse((ExpressionTree) node); - if (el instanceof ExecutableElement) { - return (ExecutableElement) el; - } else { - return null; - } - } - - // Specialization for return type. - public static final ExecutableElement elementFromUse(NewClassTree node) { - return (ExecutableElement) elementFromUse((ExpressionTree) node); - } - - /** - * Determine whether the given ExpressionTree has an underlying element. - * - * @param node the ExpressionTree to test - * @return whether the tree refers to an identifier, member select, or method invocation - */ - public static final boolean isUseOfElement(ExpressionTree node) { - node = TreeUtils.skipParens(node); - switch (node.getKind()) { - case IDENTIFIER: - case MEMBER_SELECT: - case METHOD_INVOCATION: - case NEW_CLASS: - return true; - default: - return false; - } - } - - /** @return the name of the invoked method */ - public static final Name methodName(MethodInvocationTree node) { - ExpressionTree expr = node.getMethodSelect(); - if (expr.getKind() == Tree.Kind.IDENTIFIER) { - return ((IdentifierTree) expr).getName(); - } else if (expr.getKind() == Tree.Kind.MEMBER_SELECT) { - return ((MemberSelectTree) expr).getIdentifier(); - } - ErrorReporter.errorAbort("TreeUtils.methodName: cannot be here: " + node); - return null; // dead code - } - - /** - * @return true if the first statement in the body is a self constructor invocation within a - * constructor - */ - public static final boolean containsThisConstructorInvocation(MethodTree node) { - if (!TreeUtils.isConstructor(node) || node.getBody().getStatements().isEmpty()) - return false; - - StatementTree st = node.getBody().getStatements().get(0); - if (!(st instanceof ExpressionStatementTree) - || !(((ExpressionStatementTree) st).getExpression() - instanceof MethodInvocationTree)) { - return false; - } - - MethodInvocationTree invocation = - (MethodInvocationTree) ((ExpressionStatementTree) st).getExpression(); - - return "this".contentEquals(TreeUtils.methodName(invocation)); - } - - public static final Tree firstStatement(Tree tree) { - Tree first; - if (tree.getKind() == Tree.Kind.BLOCK) { - BlockTree block = (BlockTree) tree; - if (block.getStatements().isEmpty()) { - first = block; - } else { - first = block.getStatements().iterator().next(); - } - } else { - first = tree; - } - return first; - } - - /** - * Determine whether the given class contains an explicit constructor. - * - * @param node a class tree - * @return true, iff there is an explicit constructor - */ - public static boolean hasExplicitConstructor(ClassTree node) { - TypeElement elem = TreeUtils.elementFromDeclaration(node); - - for (ExecutableElement ee : ElementFilter.constructorsIn(elem.getEnclosedElements())) { - MethodSymbol ms = (MethodSymbol) ee; - long mod = ms.flags(); - - if ((mod & Flags.SYNTHETIC) == 0) { - return true; - } - } - return false; - } - - /** - * Returns true if the tree is of a diamond type. In contrast to the implementation in TreeInfo, - * this version works on Trees. - * - * @see com.sun.tools.javac.tree.TreeInfo#isDiamond(JCTree) - */ - public static final boolean isDiamondTree(Tree tree) { - switch (tree.getKind()) { - case ANNOTATED_TYPE: - return isDiamondTree(((AnnotatedTypeTree) tree).getUnderlyingType()); - case PARAMETERIZED_TYPE: - return ((ParameterizedTypeTree) tree).getTypeArguments().isEmpty(); - case NEW_CLASS: - return isDiamondTree(((NewClassTree) tree).getIdentifier()); - default: - return false; - } - } - - /** Returns true if the tree represents a {@code String} concatenation operation */ - public static final boolean isStringConcatenation(Tree tree) { - return (tree.getKind() == Tree.Kind.PLUS - && TypesUtils.isString(InternalUtils.typeOf(tree))); - } - - /** Returns true if the compound assignment tree is a string concatenation */ - public static final boolean isStringCompoundConcatenation(CompoundAssignmentTree tree) { - return (tree.getKind() == Tree.Kind.PLUS_ASSIGNMENT - && TypesUtils.isString(InternalUtils.typeOf(tree))); - } - - /** - * Returns true if the node is a constant-time expression. - * - *

A tree is a constant-time expression if it is: - * - *

    - *
  1. a literal tree - *
  2. a reference to a final variable initialized with a compile time constant - *
  3. a String concatenation of two compile time constants - *
- */ - public static boolean isCompileTimeString(ExpressionTree node) { - ExpressionTree tree = TreeUtils.skipParens(node); - if (tree instanceof LiteralTree) { - return true; - } - - if (TreeUtils.isUseOfElement(tree)) { - Element elt = TreeUtils.elementFromUse(tree); - return ElementUtils.isCompileTimeConstant(elt); - } else if (TreeUtils.isStringConcatenation(tree)) { - BinaryTree binOp = (BinaryTree) tree; - return isCompileTimeString(binOp.getLeftOperand()) - && isCompileTimeString(binOp.getRightOperand()); - } else { - return false; - } - } - - /** Returns the receiver tree of a field access or a method invocation */ - public static ExpressionTree getReceiverTree(ExpressionTree expression) { - ExpressionTree receiver = TreeUtils.skipParens(expression); - - if (!(receiver.getKind() == Tree.Kind.METHOD_INVOCATION - || receiver.getKind() == Tree.Kind.MEMBER_SELECT - || receiver.getKind() == Tree.Kind.IDENTIFIER - || receiver.getKind() == Tree.Kind.ARRAY_ACCESS)) { - // No receiver tree for anything but these four kinds. - return null; - } - - if (receiver.getKind() == Tree.Kind.METHOD_INVOCATION) { - // Trying to handle receiver calls to trees of the form - // ((m).getArray()) - // returns the type of 'm' in this case - receiver = ((MethodInvocationTree) receiver).getMethodSelect(); - - if (receiver.getKind() == Tree.Kind.IDENTIFIER) { - // It's a method call "m(foo)" without an explicit receiver - return null; - } else if (receiver.getKind() == Tree.Kind.MEMBER_SELECT) { - receiver = ((MemberSelectTree) receiver).getExpression(); - } else { - // Otherwise, e.g. a NEW_CLASS: nothing to do. - } - } else if (receiver.getKind() == Tree.Kind.IDENTIFIER) { - // It's a field access on implicit this or a local variable/parameter. - return null; - } else if (receiver.getKind() == Tree.Kind.ARRAY_ACCESS) { - return TreeUtils.skipParens(((ArrayAccessTree) receiver).getExpression()); - } else if (receiver.getKind() == Tree.Kind.MEMBER_SELECT) { - receiver = ((MemberSelectTree) receiver).getExpression(); - // Avoid int.class - if (receiver instanceof PrimitiveTypeTree) { - return null; - } - } - - // Receiver is now really just the receiver tree. - return TreeUtils.skipParens(receiver); - } - - // TODO: What about anonymous classes? - // Adding Tree.Kind.NEW_CLASS here doesn't work, because then a - // tree gets cast to ClassTree when it is actually a NewClassTree, - // for example in enclosingClass above. - private static final Set classTreeKinds = - EnumSet.of( - Tree.Kind.CLASS, - Tree.Kind.ENUM, - Tree.Kind.INTERFACE, - Tree.Kind.ANNOTATION_TYPE); - - public static Set classTreeKinds() { - return classTreeKinds; - } - - /** - * Is the given tree kind a class, i.e. a class, enum, interface, or annotation type. - * - * @param tree the tree to test - * @return true, iff the given kind is a class kind - */ - public static boolean isClassTree(Tree tree) { - return classTreeKinds().contains(tree.getKind()); - } - - private static final Set typeTreeKinds = - EnumSet.of( - Tree.Kind.PRIMITIVE_TYPE, - Tree.Kind.PARAMETERIZED_TYPE, - Tree.Kind.TYPE_PARAMETER, - Tree.Kind.ARRAY_TYPE, - Tree.Kind.UNBOUNDED_WILDCARD, - Tree.Kind.EXTENDS_WILDCARD, - Tree.Kind.SUPER_WILDCARD, - Tree.Kind.ANNOTATED_TYPE); - - public static Set typeTreeKinds() { - return typeTreeKinds; - } - - /** - * Is the given tree a type instantiation? - * - *

TODO: this is an under-approximation: e.g. an identifier could be either a type use or an - * expression. How can we distinguish. - * - * @param tree the tree to test - * @return true, iff the given tree is a type - */ - public static boolean isTypeTree(Tree tree) { - return typeTreeKinds().contains(tree.getKind()); - } - - /** - * Returns true if the given element is an invocation of the method, or of any method that - * overrides that one. - */ - public static boolean isMethodInvocation( - Tree tree, ExecutableElement method, ProcessingEnvironment env) { - if (!(tree instanceof MethodInvocationTree)) { - return false; - } - MethodInvocationTree methInvok = (MethodInvocationTree) tree; - ExecutableElement invoked = TreeUtils.elementFromUse(methInvok); - return ElementUtils.isMethod(invoked, method, env); - } - - /** - * Returns the ExecutableElement for a method declaration of methodName, in class typeName, with - * params parameters. - * - *

TODO: to precisely resolve method overloading, we should use parameter types and not just - * the number of parameters! - */ - public static ExecutableElement getMethod( - String typeName, String methodName, int params, ProcessingEnvironment env) { - TypeElement typeElt = env.getElementUtils().getTypeElement(typeName); - for (ExecutableElement exec : ElementFilter.methodsIn(typeElt.getEnclosedElements())) { - if (exec.getSimpleName().contentEquals(methodName) - && exec.getParameters().size() == params) { - return exec; - } - } - ErrorReporter.errorAbort("TreeUtils.getMethod: shouldn't be here!"); - return null; // dead code - } - - public static List getMethodList( - String typeName, String methodName, int params, ProcessingEnvironment env) { - List methods = new ArrayList<>(); - TypeElement typeElement = env.getElementUtils().getTypeElement(typeName); - for (ExecutableElement exec : ElementFilter.methodsIn(typeElement.getEnclosedElements())) { - if (exec.getSimpleName().contentEquals(methodName) - && exec.getParameters().size() == params) { - methods.add(exec); - } - } - return methods; - } - - /** - * Determine whether the given expression is either "this" or an outer "C.this". - * - *

TODO: Should this also handle "super"? - */ - public static final boolean isExplicitThisDereference(ExpressionTree tree) { - if (tree.getKind() == Tree.Kind.IDENTIFIER - && ((IdentifierTree) tree).getName().contentEquals("this")) { - // Explicit this reference "this" - return true; - } - - if (tree.getKind() != Tree.Kind.MEMBER_SELECT) { - return false; - } - - MemberSelectTree memSelTree = (MemberSelectTree) tree; - if (memSelTree.getIdentifier().contentEquals("this")) { - // Outer this reference "C.this" - return true; - } - return false; - } - - /** - * Determine whether {@code tree} is a class literal, such as - * - *

-     *   Object . class
-     * 
- * - * @return true iff if tree is a class literal - */ - public static boolean isClassLiteral(Tree tree) { - if (tree.getKind() != Tree.Kind.MEMBER_SELECT) { - return false; - } - return "class".equals(((MemberSelectTree) tree).getIdentifier().toString()); - } - - /** - * Determine whether {@code tree} is a field access expressions, such as - * - *
-     *   f
-     *   obj . f
-     * 
- * - * @return true iff if tree is a field access expression (implicit or explicit) - */ - public static boolean isFieldAccess(Tree tree) { - if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) { - // explicit field access - MemberSelectTree memberSelect = (MemberSelectTree) tree; - Element el = TreeUtils.elementFromUse(memberSelect); - return el.getKind().isField(); - } else if (tree.getKind().equals(Tree.Kind.IDENTIFIER)) { - // implicit field access - IdentifierTree ident = (IdentifierTree) tree; - Element el = TreeUtils.elementFromUse(ident); - return el.getKind().isField() - && !ident.getName().contentEquals("this") - && !ident.getName().contentEquals("super"); - } - return false; - } - - /** - * Compute the name of the field that the field access {@code tree} accesses. Requires {@code - * tree} to be a field access, as determined by {@code isFieldAccess}. - * - * @return the name of the field accessed by {@code tree}. - */ - public static String getFieldName(Tree tree) { - assert isFieldAccess(tree); - if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) { - MemberSelectTree mtree = (MemberSelectTree) tree; - return mtree.getIdentifier().toString(); - } else { - IdentifierTree itree = (IdentifierTree) tree; - return itree.getName().toString(); - } - } - - /** - * Determine whether {@code tree} refers to a method element, such as - * - *
-     *   m(...)
-     *   obj . m(...)
-     * 
- * - * @return true iff if tree is a method access expression (implicit or explicit) - */ - public static boolean isMethodAccess(Tree tree) { - if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) { - // explicit method access - MemberSelectTree memberSelect = (MemberSelectTree) tree; - Element el = TreeUtils.elementFromUse(memberSelect); - return el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR; - } else if (tree.getKind().equals(Tree.Kind.IDENTIFIER)) { - // implicit method access - IdentifierTree ident = (IdentifierTree) tree; - // The field "super" and "this" are also legal methods - if (ident.getName().contentEquals("super") || ident.getName().contentEquals("this")) { - return true; - } - Element el = TreeUtils.elementFromUse(ident); - return el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR; - } - return false; - } - - /** - * Compute the name of the method that the method access {@code tree} accesses. Requires {@code - * tree} to be a method access, as determined by {@code isMethodAccess}. - * - * @return the name of the method accessed by {@code tree}. - */ - public static String getMethodName(Tree tree) { - assert isMethodAccess(tree); - if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) { - MemberSelectTree mtree = (MemberSelectTree) tree; - return mtree.getIdentifier().toString(); - } else { - IdentifierTree itree = (IdentifierTree) tree; - return itree.getName().toString(); - } - } - - /** - * @return {@code true} if and only if {@code tree} can have a type annotation. - *

TODO: is this implementation precise enough? E.g. does a .class literal work - * correctly? - */ - public static boolean canHaveTypeAnnotation(Tree tree) { - return ((JCTree) tree).type != null; - } - - /** - * Returns true if and only if the given {@code tree} represents a field access of the given - * {@link VariableElement}. - */ - public static boolean isSpecificFieldAccess(Tree tree, VariableElement var) { - if (tree instanceof MemberSelectTree) { - MemberSelectTree memSel = (MemberSelectTree) tree; - Element field = TreeUtils.elementFromUse(memSel); - return field.equals(var); - } else if (tree instanceof IdentifierTree) { - IdentifierTree idTree = (IdentifierTree) tree; - Element field = TreeUtils.elementFromUse(idTree); - return field.equals(var); - } else { - return false; - } - } - - /** - * Returns the VariableElement for a field declaration. - * - * @param typeName the class where the field is declared - * @param fieldName the name of the field - * @param env the processing environment - * @return the VariableElement for typeName.fieldName - */ - public static VariableElement getField( - String typeName, String fieldName, ProcessingEnvironment env) { - TypeElement mapElt = env.getElementUtils().getTypeElement(typeName); - for (VariableElement var : ElementFilter.fieldsIn(mapElt.getEnclosedElements())) { - if (var.getSimpleName().contentEquals(fieldName)) { - return var; - } - } - ErrorReporter.errorAbort("TreeUtils.getField: shouldn't be here!"); - return null; // dead code - } - - /** - * Determine whether the given tree represents an ExpressionTree. - * - *

TODO: is there a nicer way than an instanceof? - * - * @param tree the Tree to test - * @return whether the tree is an ExpressionTree - */ - public static boolean isExpressionTree(Tree tree) { - return tree instanceof ExpressionTree; - } - - /** - * @param node the method invocation to check - * @return true if this is a super call to the {@link Enum} constructor - */ - public static boolean isEnumSuper(MethodInvocationTree node) { - ExecutableElement ex = TreeUtils.elementFromUse(node); - Name name = ElementUtils.getQualifiedClassName(ex); - boolean correctClass = "java.lang.Enum".contentEquals(name); - boolean correctMethod = "".contentEquals(ex.getSimpleName()); - return correctClass && correctMethod; - } - - /** - * Determine whether the given tree represents a declaration of a type (including type - * parameters). - * - * @param node the Tree to test - * @return true if the tree is a type declaration - */ - public static boolean isTypeDeclaration(Tree node) { - switch (node.getKind()) { - // These tree kinds are always declarations. Uses of the declared - // types have tree kind IDENTIFIER. - case ANNOTATION_TYPE: - case CLASS: - case ENUM: - case INTERFACE: - case TYPE_PARAMETER: - return true; - - default: - return false; - } - } - - /** - * @see Object#getClass() - * @return true iff invocationTree is an instance of getClass() - */ - public static boolean isGetClassInvocation(MethodInvocationTree invocationTree) { - final Element declarationElement = elementFromUse(invocationTree); - String ownerName = - ElementUtils.getQualifiedClassName(declarationElement.getEnclosingElement()) - .toString(); - return ownerName.equals("java.lang.Object") - && declarationElement.getSimpleName().toString().equals("getClass"); - } - - /** - * Returns whether or not the leaf of the tree path is in a static scope. - * - * @param path TreePath whose leaf may or may not be in static scope - * @return returns whether or not the leaf of the tree path is in a static scope - */ - public static boolean isTreeInStaticScope(TreePath path) { - MethodTree enclosingMethod = TreeUtils.enclosingMethod(path); - - if (enclosingMethod != null) { - return enclosingMethod.getModifiers().getFlags().contains(Modifier.STATIC); - } - // no enclosing method, check for static or initializer block - BlockTree block = enclosingTopLevelBlock(path); - if (block != null) { - return block.isStatic(); - } - - // check if its in a variable initializer - Tree t = enclosingVariable(path); - if (t != null) { - return ((VariableTree) t).getModifiers().getFlags().contains((Modifier.STATIC)); - } - ClassTree classTree = enclosingClass(path); - if (classTree != null) { - return classTree.getModifiers().getFlags().contains((Modifier.STATIC)); - } - return false; - } - - /** - * Returns whether or not tree is an access of array length. - * - * @param tree tree to check - * @return true if tree is an access of array length - */ - public static boolean isArrayLengthAccess(Tree tree) { - if (tree.getKind() == Kind.MEMBER_SELECT - && isFieldAccess(tree) - && getFieldName(tree).equals("length")) { - ExpressionTree expressionTree = ((MemberSelectTree) tree).getExpression(); - if (InternalUtils.typeOf(expressionTree).getKind() == TypeKind.ARRAY) { - return true; - } - } - return false; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java deleted file mode 100644 index b925f91b04ffbb..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java +++ /dev/null @@ -1,397 +0,0 @@ -package org.checkerframework.javacutil; - -import com.sun.tools.javac.code.Attribute; -import com.sun.tools.javac.code.Attribute.TypeCompound; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.TargetType; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.TypeAnnotationPosition; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; -import com.sun.tools.javac.util.Pair; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Map; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.AnnotationValueVisitor; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; - -/** - * A collection of helper methods related to type annotation handling. - * - * @see AnnotationUtils - */ -public class TypeAnnotationUtils { - - // Class cannot be instantiated. - private TypeAnnotationUtils() { - throw new AssertionError("Class TypeAnnotationUtils cannot be instantiated."); - } - - /** - * Check whether a TypeCompound is contained in a list of TypeCompounds. - * - * @param list the input list of TypeCompounds - * @param tc the TypeCompound to find - * @return true, iff a TypeCompound equal to tc is contained in list - */ - public static boolean isTypeCompoundContained( - Types types, List list, TypeCompound tc) { - for (Attribute.TypeCompound rawat : list) { - if (contentEquals(rawat.type.tsym.name, tc.type.tsym.name) - // TODO: in previous line, it would be nicer to use reference equality: - // rawat.type == tc.type && - // or at least "isSameType": - // types.isSameType(rawat.type, tc.type) && - // but each fails in some cases. - && rawat.values.equals(tc.values) - && isSameTAPositionExceptTreePos(rawat.position, tc.position)) { - return true; - } - } - return false; - } - - private static boolean contentEquals(Name n1, Name n2) { - // Views of underlying bytes, not copies as with Name#contentEquals - ByteBuffer b1 = ByteBuffer.wrap(n1.getByteArray(), n1.getByteOffset(), n1.getByteLength()); - ByteBuffer b2 = ByteBuffer.wrap(n2.getByteArray(), n2.getByteOffset(), n2.getByteLength()); - - return b1.equals(b2); - } - - /** - * Compare two TypeAnnotationPositions for equality. - * - * @param p1 the first position - * @param p2 the second position - * @return true, iff the two positions are equal - */ - public static boolean isSameTAPosition(TypeAnnotationPosition p1, TypeAnnotationPosition p2) { - return isSameTAPositionExceptTreePos(p1, p2) && p1.pos == p2.pos; - } - - public static boolean isSameTAPositionExceptTreePos( - TypeAnnotationPosition p1, TypeAnnotationPosition p2) { - return p1.isValidOffset == p2.isValidOffset - && p1.bound_index == p2.bound_index - && p1.exception_index == p2.exception_index - && p1.location.equals(p2.location) - && Arrays.equals(p1.lvarIndex, p2.lvarIndex) - && Arrays.equals(p1.lvarLength, p2.lvarLength) - && Arrays.equals(p1.lvarOffset, p2.lvarOffset) - && p1.offset == p2.offset - && p1.onLambda == p2.onLambda - && p1.parameter_index == p2.parameter_index - && p1.type == p2.type - && p1.type_index == p2.type_index; - } - - /** - * Returns a newly created Attribute.Compound corresponding to an argument AnnotationMirror. - * - * @param am an AnnotationMirror, which may be part of an AST or an internally created subclass - * @return a new Attribute.Compound corresponding to the AnnotationMirror - */ - public static Attribute.Compound createCompoundFromAnnotationMirror( - ProcessingEnvironment env, AnnotationMirror am) { - // Create a new Attribute to match the AnnotationMirror. - List> values = List.nil(); - for (Map.Entry entry : - am.getElementValues().entrySet()) { - Attribute attribute = - attributeFromAnnotationValue(env, entry.getKey(), entry.getValue()); - values = values.append(new Pair<>((Symbol.MethodSymbol) entry.getKey(), attribute)); - } - return new Attribute.Compound((Type.ClassType) am.getAnnotationType(), values); - } - - /** - * Returns a newly created Attribute.TypeCompound corresponding to an argument AnnotationMirror. - * - * @param am an AnnotationMirror, which may be part of an AST or an internally created subclass - * @param tapos the type annotation position to use - * @return a new Attribute.TypeCompound corresponding to the AnnotationMirror - */ - public static Attribute.TypeCompound createTypeCompoundFromAnnotationMirror( - ProcessingEnvironment env, AnnotationMirror am, TypeAnnotationPosition tapos) { - // Create a new Attribute to match the AnnotationMirror. - List> values = List.nil(); - for (Map.Entry entry : - am.getElementValues().entrySet()) { - Attribute attribute = - attributeFromAnnotationValue(env, entry.getKey(), entry.getValue()); - values = values.append(new Pair<>((Symbol.MethodSymbol) entry.getKey(), attribute)); - } - return new Attribute.TypeCompound((Type.ClassType) am.getAnnotationType(), values, tapos); - } - - /** - * Returns a newly created Attribute corresponding to an argument AnnotationValue. - * - * @param meth the ExecutableElement that is assigned the value, needed for empty arrays - * @param av an AnnotationValue, which may be part of an AST or an internally created subclass - * @return a new Attribute corresponding to the AnnotationValue - */ - public static Attribute attributeFromAnnotationValue( - ProcessingEnvironment env, ExecutableElement meth, AnnotationValue av) { - return av.accept(new AttributeCreator(env, meth), null); - } - - private static class AttributeCreator implements AnnotationValueVisitor { - private final ProcessingEnvironment processingEnv; - private final Types modelTypes; - private final Elements elements; - private final com.sun.tools.javac.code.Types javacTypes; - - private final ExecutableElement meth; - - public AttributeCreator(ProcessingEnvironment env, ExecutableElement meth) { - this.processingEnv = env; - Context context = ((JavacProcessingEnvironment) env).getContext(); - this.elements = env.getElementUtils(); - this.modelTypes = env.getTypeUtils(); - this.javacTypes = com.sun.tools.javac.code.Types.instance(context); - - this.meth = meth; - } - - @Override - public Attribute visit(AnnotationValue av, Void p) { - return av.accept(this, p); - } - - @Override - public Attribute visit(AnnotationValue av) { - return visit(av, null); - } - - @Override - public Attribute visitBoolean(boolean b, Void p) { - TypeMirror booleanType = modelTypes.getPrimitiveType(TypeKind.BOOLEAN); - return new Attribute.Constant((Type) booleanType, b ? 1 : 0); - } - - @Override - public Attribute visitByte(byte b, Void p) { - TypeMirror byteType = modelTypes.getPrimitiveType(TypeKind.BYTE); - return new Attribute.Constant((Type) byteType, b); - } - - @Override - public Attribute visitChar(char c, Void p) { - TypeMirror charType = modelTypes.getPrimitiveType(TypeKind.CHAR); - return new Attribute.Constant((Type) charType, c); - } - - @Override - public Attribute visitDouble(double d, Void p) { - TypeMirror doubleType = modelTypes.getPrimitiveType(TypeKind.DOUBLE); - return new Attribute.Constant((Type) doubleType, d); - } - - @Override - public Attribute visitFloat(float f, Void p) { - TypeMirror floatType = modelTypes.getPrimitiveType(TypeKind.FLOAT); - return new Attribute.Constant((Type) floatType, f); - } - - @Override - public Attribute visitInt(int i, Void p) { - TypeMirror intType = modelTypes.getPrimitiveType(TypeKind.INT); - return new Attribute.Constant((Type) intType, i); - } - - @Override - public Attribute visitLong(long i, Void p) { - TypeMirror longType = modelTypes.getPrimitiveType(TypeKind.LONG); - return new Attribute.Constant((Type) longType, i); - } - - @Override - public Attribute visitShort(short s, Void p) { - TypeMirror shortType = modelTypes.getPrimitiveType(TypeKind.SHORT); - return new Attribute.Constant((Type) shortType, s); - } - - @Override - public Attribute visitString(String s, Void p) { - TypeMirror stringType = elements.getTypeElement("java.lang.String").asType(); - return new Attribute.Constant((Type) stringType, s); - } - - @Override - public Attribute visitType(TypeMirror t, Void p) { - if (t instanceof Type) { - return new Attribute.Class(javacTypes, (Type) t); - } - - assert false : "Unexpected type of TypeMirror: " + t.getClass(); - return null; - } - - @Override - public Attribute visitEnumConstant(VariableElement c, Void p) { - if (c instanceof Symbol.VarSymbol) { - Symbol.VarSymbol sym = (Symbol.VarSymbol) c; - if (sym.getKind() == ElementKind.ENUM_CONSTANT) { - return new Attribute.Enum(sym.type, sym); - } - } - - assert false : "Unexpected type of VariableElement: " + c.getClass(); - return null; - } - - @Override - public Attribute visitAnnotation(AnnotationMirror a, Void p) { - return createCompoundFromAnnotationMirror(processingEnv, a); - } - - @Override - public Attribute visitArray(java.util.List vals, Void p) { - if (!vals.isEmpty()) { - List valAttrs = List.nil(); - for (AnnotationValue av : vals) { - valAttrs = valAttrs.append(av.accept(this, p)); - } - ArrayType arrayType = modelTypes.getArrayType(valAttrs.get(0).type); - return new Attribute.Array((Type) arrayType, valAttrs); - } else { - return new Attribute.Array((Type) meth.getReturnType(), List.nil()); - } - } - - @Override - public Attribute visitUnknown(AnnotationValue av, Void p) { - assert false : "Unexpected type of AnnotationValue: " + av.getClass(); - return null; - } - } - - public static TypeAnnotationPosition unknownTAPosition() { - return new TypeAnnotationPosition(); - } - - public static TypeAnnotationPosition methodReturnTAPosition(final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.METHOD_RETURN; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition methodReceiverTAPosition(final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.METHOD_RECEIVER; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition methodParameterTAPosition(final int pidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.METHOD_FORMAL_PARAMETER; - tapos.parameter_index = pidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition methodThrowsTAPosition(final int tidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.THROWS; - tapos.type_index = tidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition fieldTAPosition(final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.FIELD; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition classExtendsTAPosition(final int implidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.CLASS_EXTENDS; - tapos.type_index = implidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition typeParameterTAPosition(final int tpidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.CLASS_TYPE_PARAMETER; - tapos.parameter_index = tpidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition methodTypeParameterTAPosition( - final int tpidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.METHOD_TYPE_PARAMETER; - tapos.parameter_index = tpidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition typeParameterBoundTAPosition( - final int tpidx, final int bndidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.CLASS_TYPE_PARAMETER_BOUND; - tapos.parameter_index = tpidx; - tapos.bound_index = bndidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition methodTypeParameterBoundTAPosition( - final int tpidx, final int bndidx, final int pos) { - TypeAnnotationPosition tapos = new TypeAnnotationPosition(); - tapos.type = TargetType.METHOD_TYPE_PARAMETER_BOUND; - tapos.parameter_index = tpidx; - tapos.bound_index = bndidx; - tapos.pos = pos; - return tapos; - } - - public static TypeAnnotationPosition copyTAPosition(final TypeAnnotationPosition tapos) { - TypeAnnotationPosition res = new TypeAnnotationPosition(); - res.isValidOffset = tapos.isValidOffset; - res.bound_index = tapos.bound_index; - res.exception_index = tapos.exception_index; - res.location = List.from(tapos.location); - if (tapos.lvarIndex != null) { - res.lvarIndex = Arrays.copyOf(tapos.lvarIndex, tapos.lvarIndex.length); - } - if (tapos.lvarLength != null) { - res.lvarLength = Arrays.copyOf(tapos.lvarLength, tapos.lvarLength.length); - } - if (tapos.lvarOffset != null) { - res.lvarOffset = Arrays.copyOf(tapos.lvarOffset, tapos.lvarOffset.length); - } - res.offset = tapos.offset; - res.onLambda = tapos.onLambda; - res.parameter_index = tapos.parameter_index; - res.pos = tapos.pos; - res.type = tapos.type; - res.type_index = tapos.type_index; - return res; - } - - public static Type unannotatedType(final TypeMirror in) { - final Type impl = (Type) in; - return impl.unannotatedType(); - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java deleted file mode 100644 index fe7456f6d27990..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java +++ /dev/null @@ -1,452 +0,0 @@ -package org.checkerframework.javacutil; - -import static com.sun.tools.javac.code.TypeTag.WILDCARD; - -import com.sun.tools.javac.code.Symtab; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.TypeTag; -import com.sun.tools.javac.model.JavacTypes; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.util.Context; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.Name; -import javax.lang.model.element.NestingKind; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.WildcardType; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; - -/** A utility class that helps with {@link TypeMirror}s. */ -// TODO: This class needs significant restructuring -public final class TypesUtils { - - // Class cannot be instantiated - private TypesUtils() { - throw new AssertionError("Class TypesUtils cannot be instantiated."); - } - - /** - * Gets the fully qualified name for a provided type. It returns an empty name if type is an - * anonymous type. - * - * @param type the declared type - * @return the name corresponding to that type - */ - public static Name getQualifiedName(DeclaredType type) { - TypeElement element = (TypeElement) type.asElement(); - return element.getQualifiedName(); - } - - /** - * Checks if the type represents a java.lang.Object declared type. - * - * @param type the type - * @return true iff type represents java.lang.Object - */ - public static boolean isObject(TypeMirror type) { - return isDeclaredOfName(type, "java.lang.Object"); - } - - /** - * Checks if the type represents a java.lang.Class declared type. - * - * @param type the type - * @return true iff type represents java.lang.Class - */ - public static boolean isClass(TypeMirror type) { - return isDeclaredOfName(type, "java.lang.Class"); - } - - /** - * Checks if the type represents a java.lang.String declared type. TODO: it would be cleaner to - * use String.class.getCanonicalName(), but the two existing methods above don't do that, I - * guess for performance reasons. - * - * @param type the type - * @return true iff type represents java.lang.String - */ - public static boolean isString(TypeMirror type) { - return isDeclaredOfName(type, "java.lang.String"); - } - - /** - * Checks if the type represents a boolean type, that is either boolean (primitive type) or - * java.lang.Boolean. - * - * @param type the type to test - * @return true iff type represents a boolean type - */ - public static boolean isBooleanType(TypeMirror type) { - return isDeclaredOfName(type, "java.lang.Boolean") - || type.getKind().equals(TypeKind.BOOLEAN); - } - - /** - * Check if the type represent a declared type of the given qualified name - * - * @param type the type - * @return type iff type represents a declared type of the qualified name - */ - public static boolean isDeclaredOfName(TypeMirror type, CharSequence qualifiedName) { - return type.getKind() == TypeKind.DECLARED - && getQualifiedName((DeclaredType) type).contentEquals(qualifiedName); - } - - public static boolean isBoxedPrimitive(TypeMirror type) { - if (type.getKind() != TypeKind.DECLARED) { - return false; - } - - String qualifiedName = getQualifiedName((DeclaredType) type).toString(); - - return (qualifiedName.equals("java.lang.Boolean") - || qualifiedName.equals("java.lang.Byte") - || qualifiedName.equals("java.lang.Character") - || qualifiedName.equals("java.lang.Short") - || qualifiedName.equals("java.lang.Integer") - || qualifiedName.equals("java.lang.Long") - || qualifiedName.equals("java.lang.Double") - || qualifiedName.equals("java.lang.Float")); - } - - /** @return type represents a Throwable type (e.g. Exception, Error) */ - public static boolean isThrowable(TypeMirror type) { - while (type != null && type.getKind() == TypeKind.DECLARED) { - DeclaredType dt = (DeclaredType) type; - TypeElement elem = (TypeElement) dt.asElement(); - Name name = elem.getQualifiedName(); - if ("java.lang.Throwable".contentEquals(name)) { - return true; - } - type = elem.getSuperclass(); - } - return false; - } - - /** - * Returns true iff the argument is an anonymous type. - * - * @return whether the argument is an anonymous type - */ - public static boolean isAnonymous(TypeMirror type) { - return (type instanceof DeclaredType) - && (((TypeElement) ((DeclaredType) type).asElement()) - .getNestingKind() - .equals(NestingKind.ANONYMOUS)); - } - - /** - * Returns true iff the argument is a primitive type. - * - * @return whether the argument is a primitive type - */ - public static boolean isPrimitive(TypeMirror type) { - switch (type.getKind()) { - case BOOLEAN: - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case LONG: - case SHORT: - return true; - default: - return false; - } - } - - /** - * Returns true iff the arguments are both the same primitive types. - * - * @return whether the arguments are the same primitive types - */ - public static boolean areSamePrimitiveTypes(TypeMirror left, TypeMirror right) { - if (!isPrimitive(left) || !isPrimitive(right)) { - return false; - } - - return (left.getKind() == right.getKind()); - } - - /** - * Returns true iff the argument is a primitive numeric type. - * - * @return whether the argument is a primitive numeric type - */ - public static boolean isNumeric(TypeMirror type) { - switch (type.getKind()) { - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case LONG: - case SHORT: - return true; - default: - return false; - } - } - - /** - * Returns true iff the argument is an integral type. - * - * @return whether the argument is an integral type - */ - public static boolean isIntegral(TypeMirror type) { - switch (type.getKind()) { - case BYTE: - case CHAR: - case INT: - case LONG: - case SHORT: - return true; - default: - return false; - } - } - - /** - * Returns true iff the argument is a floating point type. - * - * @return whether the argument is a floating point type - */ - public static boolean isFloating(TypeMirror type) { - switch (type.getKind()) { - case DOUBLE: - case FLOAT: - return true; - default: - return false; - } - } - - /** - * Returns the widened numeric type for an arithmetic operation performed on a value of the left - * type and the right type. Defined in JLS 5.6.2. We return a {@link TypeKind} because creating - * a {@link TypeMirror} requires a {@link Types} object from the {@link - * javax.annotation.processing.ProcessingEnvironment}. - * - * @return the result of widening numeric conversion, or NONE when the conversion cannot be - * performed - */ - public static TypeKind widenedNumericType(TypeMirror left, TypeMirror right) { - if (!isNumeric(left) || !isNumeric(right)) { - return TypeKind.NONE; - } - - TypeKind leftKind = left.getKind(); - TypeKind rightKind = right.getKind(); - - if (leftKind == TypeKind.DOUBLE || rightKind == TypeKind.DOUBLE) { - return TypeKind.DOUBLE; - } - - if (leftKind == TypeKind.FLOAT || rightKind == TypeKind.FLOAT) { - return TypeKind.FLOAT; - } - - if (leftKind == TypeKind.LONG || rightKind == TypeKind.LONG) { - return TypeKind.LONG; - } - - return TypeKind.INT; - } - - /** - * If the argument is a bounded TypeVariable or WildcardType, return its non-variable, - * non-wildcard upper bound. Otherwise, return the type itself. - * - * @param type a type - * @return the non-variable, non-wildcard upper bound of a type, if it has one, or itself if it - * has no bounds - */ - public static TypeMirror upperBound(TypeMirror type) { - do { - if (type instanceof TypeVariable) { - TypeVariable tvar = (TypeVariable) type; - if (tvar.getUpperBound() != null) { - type = tvar.getUpperBound(); - } else { - break; - } - } else if (type instanceof WildcardType) { - WildcardType wc = (WildcardType) type; - if (wc.getExtendsBound() != null) { - type = wc.getExtendsBound(); - } else { - break; - } - } else { - break; - } - } while (true); - return type; - } - - /** - * Get the type parameter for this wildcard from the underlying type's bound field This field is - * sometimes null, in that case this method will return null - * - * @return the TypeParameterElement the wildcard is an argument to - */ - public static TypeParameterElement wildcardToTypeParam(final Type.WildcardType wildcard) { - - final Element typeParamElement; - if (wildcard.bound != null) { - typeParamElement = wildcard.bound.asElement(); - } else { - typeParamElement = null; - } - - return (TypeParameterElement) typeParamElement; - } - - /** - * Version of com.sun.tools.javac.code.Types.wildUpperBound(Type) that works with both jdk8 - * (called upperBound there) and jdk8u. - */ - // TODO: contrast to upperBound. - public static Type wildUpperBound(ProcessingEnvironment env, TypeMirror tm) { - Type t = (Type) tm; - if (t.hasTag(TypeTag.WILDCARD)) { - Context context = ((JavacProcessingEnvironment) env).getContext(); - Type.WildcardType w = (Type.WildcardType) TypeAnnotationUtils.unannotatedType(t); - if (w.isSuperBound()) { - Symtab syms = Symtab.instance(context); - return w.bound == null ? syms.objectType : w.bound.bound; - } else { - return wildUpperBound(env, w.type); - } - } else { - return TypeAnnotationUtils.unannotatedType(t); - } - } - - /** - * Version of com.sun.tools.javac.code.Types.wildLowerBound(Type) that works with both jdk8 - * (called upperBound there) and jdk8u. - */ - public static Type wildLowerBound(ProcessingEnvironment env, TypeMirror tm) { - Type t = (Type) tm; - if (t.hasTag(WILDCARD)) { - Context context = ((JavacProcessingEnvironment) env).getContext(); - Symtab syms = Symtab.instance(context); - Type.WildcardType w = (Type.WildcardType) TypeAnnotationUtils.unannotatedType(t); - return w.isExtendsBound() ? syms.botType : wildLowerBound(env, w.type); - } else { - return TypeAnnotationUtils.unannotatedType(t); - } - } - /** Returns the {@link TypeMirror} for a given {@link Class}. */ - public static TypeMirror typeFromClass(Types types, Elements elements, Class clazz) { - if (clazz == void.class) { - return types.getNoType(TypeKind.VOID); - } else if (clazz.isPrimitive()) { - String primitiveName = clazz.getName().toUpperCase(); - TypeKind primitiveKind = TypeKind.valueOf(primitiveName); - return types.getPrimitiveType(primitiveKind); - } else if (clazz.isArray()) { - TypeMirror componentType = typeFromClass(types, elements, clazz.getComponentType()); - return types.getArrayType(componentType); - } else { - TypeElement element = elements.getTypeElement(clazz.getCanonicalName()); - if (element == null) { - ErrorReporter.errorAbort("Unrecognized class: " + clazz); - return null; // dead code - } - return element.asType(); - } - } - - /** Returns an {@link ArrayType} with elements of type {@code componentType}. */ - public static ArrayType createArrayType(Types types, TypeMirror componentType) { - JavacTypes t = (JavacTypes) types; - return t.getArrayType(componentType); - } - - /** - * Returns true if declaredType is a Class that is used to box primitive type (e.g. - * declaredType=java.lang.Double and primitiveType=22.5d ) - */ - public static boolean isBoxOf(TypeMirror declaredType, TypeMirror primitiveType) { - if (declaredType.getKind() != TypeKind.DECLARED) { - return false; - } - - final String qualifiedName = getQualifiedName((DeclaredType) declaredType).toString(); - switch (primitiveType.getKind()) { - case BOOLEAN: - return qualifiedName.equals("java.lang.Boolean"); - case BYTE: - return qualifiedName.equals("java.lang.Byte"); - case CHAR: - return qualifiedName.equals("java.lang.Character"); - case DOUBLE: - return qualifiedName.equals("java.lang.Double"); - case FLOAT: - return qualifiedName.equals("java.lang.Float"); - case INT: - return qualifiedName.equals("java.lang.Integer"); - case LONG: - return qualifiedName.equals("java.lang.Long"); - case SHORT: - return qualifiedName.equals("java.lang.Short"); - - default: - return false; - } - } - - /** - * Given a bounded type (wildcard or typevar) get the concrete type of its upper bound. If the - * bounded type extends other bounded types, this method will iterate through their bounds until - * a class, interface, or intersection is found. - * - * @return a type that is not a wildcard or typevar, or null if this type is an unbounded - * wildcard - */ - public static TypeMirror findConcreteUpperBound(final TypeMirror boundedType) { - TypeMirror effectiveUpper = boundedType; - outerLoop: - while (true) { - switch (effectiveUpper.getKind()) { - case WILDCARD: - effectiveUpper = - ((javax.lang.model.type.WildcardType) effectiveUpper).getExtendsBound(); - if (effectiveUpper == null) { - return null; - } - break; - - case TYPEVAR: - effectiveUpper = ((TypeVariable) effectiveUpper).getUpperBound(); - break; - - default: - break outerLoop; - } - } - return effectiveUpper; - } - - /** - * Returns true if the erased type of subtype is a subtype of the erased type of supertype. - * - * @param types Types - * @param subtype possible subtype - * @param supertype possible supertype - * @return true if the erased type of subtype is a subtype of the erased type of supertype - */ - public static boolean isErasedSubtype(Types types, TypeMirror subtype, TypeMirror supertype) { - return types.isSubtype(types.erasure(subtype), types.erasure(supertype)); - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java deleted file mode 100644 index 01f35485e53563..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.checkerframework.javacutil.dist; - -import com.sun.javadoc.Tag; -import com.sun.tools.doclets.Taglet; -import java.util.Map; - -/** - * A taglet for processing the {@code @checker_framework.manual} javadoc block tag, which inserts - * references to the Checker Framework manual into javadoc. - * - *

The {@code @checker_framework.manual} tag is used as follows: - * - *

    - *
  • {@code @checker_framework.manual #} expands to a top-level link to the Checker Framework - * manual - *
  • {@code @checker_framework.manual #anchor text} expands to a link with some text to a - * particular part of the manual - *
- */ -public class ManualTaglet implements Taglet { - - @Override - public String getName() { - return "checker_framework.manual"; - } - - @Override - public boolean inConstructor() { - return true; - } - - @Override - public boolean inField() { - return true; - } - - @Override - public boolean inMethod() { - return true; - } - - @Override - public boolean inOverview() { - return true; - } - - @Override - public boolean inPackage() { - return true; - } - - @Override - public boolean inType() { - return true; - } - - @Override - public boolean isInlineTag() { - return false; - } - - /** - * Formats a link, given an array of tokens. - * - * @param parts the array of tokens - * @return a link to the manual top-level if the array size is one, or a link to a part of the - * manual if it's larger than one - */ - private String formatLink(String[] parts) { - String anchor, text; - if (parts.length < 2) { - anchor = ""; - text = "Checker Framework"; - } else { - anchor = parts[0]; - text = parts[1]; - } - return String.format( - "
%s", anchor, text); - } - - /** - * Formats the {@code @checker_framework.manual} tag, prepending the tag header to the tag - * content. - * - * @param text the tag content - * @return the formatted tag - */ - private String formatHeader(String text) { - return String.format("

This map is used by {@link CFGTranslationPhaseOne#addToLookupMap(Node)} to associate a - * {@code ParenthesizedTree} with the dataflow {@code Node} that was used during inference. - * This map is necessary because dataflow does not create a {@code Node} for a {@code - * ParenthesizedTree.} - */ - private final Map parenMapping = new HashMap<>(); - - @Override - public Node visitParenthesized(ParenthesizedTree tree, Void p) { - parenMapping.put(tree.getExpression(), tree); - return scan(tree.getExpression(), p); - } - - @Override - public Node visitReturn(ReturnTree tree, Void p) { - ExpressionTree ret = tree.getExpression(); - // TODO: also have a return-node if nothing is returned - ReturnNode result = null; - if (ret != null) { - Node node = scan(ret, p); - Tree enclosing = - TreeUtils.enclosingOfKind( - getCurrentPath(), - new HashSet( - Arrays.asList(Kind.METHOD, Kind.LAMBDA_EXPRESSION))); - if (enclosing.getKind() == Kind.LAMBDA_EXPRESSION) { - LambdaExpressionTree lambdaTree = (LambdaExpressionTree) enclosing; - TreePath lambdaTreePath = - TreePath.getPath(getCurrentPath().getCompilationUnit(), lambdaTree); - Context ctx = ((JavacProcessingEnvironment) env).getContext(); - Element overriddenElement = - com.sun.tools.javac.code.Types.instance(ctx) - .findDescriptorSymbol( - ((Type) trees.getTypeMirror(lambdaTreePath)).tsym); - - result = - new ReturnNode( - tree, - node, - env.getTypeUtils(), - lambdaTree, - (MethodSymbol) overriddenElement); - } else { - result = new ReturnNode(tree, node, env.getTypeUtils(), (MethodTree) enclosing); - } - returnNodes.add(result); - extendWithNode(result); - } - extendWithExtendedNode(new UnconditionalJump(regularExitLabel)); - // TODO: return statements should also flow to an enclosing finally block - return result; - } - - @Override - public Node visitMemberSelect(MemberSelectTree tree, Void p) { - Node expr = scan(tree.getExpression(), p); - if (!TreeUtils.isFieldAccess(tree)) { - // Could be a selector of a class or package - Node result = null; - Element element = TreeUtils.elementFromUse(tree); - switch (element.getKind()) { - case ANNOTATION_TYPE: - case CLASS: - case ENUM: - case INTERFACE: - result = extendWithNode(new ClassNameNode(tree, expr)); - break; - case PACKAGE: - result = extendWithNode(new PackageNameNode(tree, (PackageNameNode) expr)); - break; - default: - assert false : "Unexpected element kind: " + element.getKind(); - return null; - } - return result; - } - - Node node = new FieldAccessNode(tree, expr); - - Element element = TreeUtils.elementFromUse(tree); - if (ElementUtils.isStatic(element) - || expr instanceof ImplicitThisLiteralNode - || expr instanceof ExplicitThisLiteralNode) { - // No NullPointerException can be thrown, use normal node - extendWithNode(node); - } else { - TypeElement npeElement = elements.getTypeElement("java.lang.NullPointerException"); - extendWithNodeWithException(node, npeElement.asType()); - } - - return node; - } - - @Override - public Node visitEmptyStatement(EmptyStatementTree tree, Void p) { - return null; - } - - @Override - public Node visitSynchronized(SynchronizedTree tree, Void p) { - // see JLS 14.19 - - Node synchronizedExpr = scan(tree.getExpression(), p); - SynchronizedNode synchronizedStartNode = - new SynchronizedNode(tree, synchronizedExpr, true, env.getTypeUtils()); - extendWithNode(synchronizedStartNode); - scan(tree.getBlock(), p); - SynchronizedNode synchronizedEndNode = - new SynchronizedNode(tree, synchronizedExpr, false, env.getTypeUtils()); - extendWithNode(synchronizedEndNode); - - return null; - } - - @Override - public Node visitThrow(ThrowTree tree, Void p) { - Node expression = scan(tree.getExpression(), p); - TypeMirror exception = expression.getType(); - ThrowNode throwsNode = new ThrowNode(tree, expression, env.getTypeUtils()); - NodeWithExceptionsHolder exNode = extendWithNodeWithException(throwsNode, exception); - exNode.setTerminatesExecution(true); - return throwsNode; - } - - @Override - public Node visitCompilationUnit(CompilationUnitTree tree, Void p) { - assert false : "CompilationUnitTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitTry(TryTree tree, Void p) { - List catches = tree.getCatches(); - BlockTree finallyBlock = tree.getFinallyBlock(); - - extendWithNode(new MarkerNode(tree, "start of try statement", env.getTypeUtils())); - - // TODO: Should we handle try-with-resources blocks by also generating code - // for automatically closing the resources? - List resources = tree.getResources(); - for (Tree resource : resources) { - scan(resource, p); - } - - List> catchLabels = new ArrayList<>(); - for (CatchTree c : catches) { - TypeMirror type = InternalUtils.typeOf(c.getParameter().getType()); - assert type != null : "exception parameters must have a type"; - catchLabels.add(Pair.of(type, new Label())); - } - - Label finallyLabel = null; - if (finallyBlock != null) { - finallyLabel = new Label(); - tryStack.pushFrame(new TryFinallyFrame(finallyLabel)); - } - - Label doneLabel = new Label(); - - tryStack.pushFrame(new TryCatchFrame(types, catchLabels)); - - scan(tree.getBlock(), p); - extendWithExtendedNode(new UnconditionalJump(firstNonNull(finallyLabel, doneLabel))); - - tryStack.popFrame(); - - int catchIndex = 0; - for (CatchTree c : catches) { - addLabelForNextNode(catchLabels.get(catchIndex).second); - scan(c, p); - catchIndex++; - extendWithExtendedNode( - new UnconditionalJump(firstNonNull(finallyLabel, doneLabel))); - } - - if (finallyLabel != null) { - tryStack.popFrame(); - addLabelForNextNode(finallyLabel); - scan(finallyBlock, p); - - TypeMirror throwableType = elements.getTypeElement("java.lang.Throwable").asType(); - extendWithNodeWithException( - new MarkerNode(tree, "end of finally block", env.getTypeUtils()), - throwableType); - } - - addLabelForNextNode(doneLabel); - - return null; - } - - @Override - public Node visitParameterizedType(ParameterizedTypeTree tree, Void p) { - return extendWithNode(new ParameterizedTypeNode(tree)); - } - - @Override - public Node visitUnionType(UnionTypeTree tree, Void p) { - assert false : "UnionTypeTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitArrayType(ArrayTypeTree tree, Void p) { - return extendWithNode(new ArrayTypeNode(tree)); - } - - @Override - public Node visitTypeCast(TypeCastTree tree, Void p) { - final Node operand = scan(tree.getExpression(), p); - final TypeMirror type = InternalUtils.typeOf(tree.getType()); - final Node node = new TypeCastNode(tree, operand, type); - final TypeElement cceElement = elements.getTypeElement("java.lang.ClassCastException"); - - extendWithNodeWithException(node, cceElement.asType()); - return node; - } - - @Override - public Node visitPrimitiveType(PrimitiveTypeTree tree, Void p) { - return extendWithNode(new PrimitiveTypeNode(tree)); - } - - @Override - public Node visitTypeParameter(TypeParameterTree tree, Void p) { - assert false : "TypeParameterTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitInstanceOf(InstanceOfTree tree, Void p) { - Node operand = scan(tree.getExpression(), p); - TypeMirror refType = InternalUtils.typeOf(tree.getType()); - InstanceOfNode node = new InstanceOfNode(tree, operand, refType, types); - extendWithNode(node); - return node; - } - - @Override - public Node visitUnary(UnaryTree tree, Void p) { - Node result = null; - Tree.Kind kind = tree.getKind(); - switch (kind) { - case BITWISE_COMPLEMENT: - case UNARY_MINUS: - case UNARY_PLUS: - { - // see JLS 15.14 and 15.15 - Node expr = scan(tree.getExpression(), p); - expr = unaryNumericPromotion(expr); - - // TypeMirror exprType = InternalUtils.typeOf(tree); - - switch (kind) { - case BITWISE_COMPLEMENT: - result = extendWithNode(new BitwiseComplementNode(tree, expr)); - break; - case UNARY_MINUS: - result = extendWithNode(new NumericalMinusNode(tree, expr)); - break; - case UNARY_PLUS: - result = extendWithNode(new NumericalPlusNode(tree, expr)); - break; - default: - assert false; - break; - } - break; - } - - case LOGICAL_COMPLEMENT: - { - // see JLS 15.15.6 - Node expr = scan(tree.getExpression(), p); - result = extendWithNode(new ConditionalNotNode(tree, unbox(expr))); - break; - } - - case POSTFIX_DECREMENT: - case POSTFIX_INCREMENT: - { - ExpressionTree exprTree = tree.getExpression(); - TypeMirror exprType = InternalUtils.typeOf(exprTree); - TypeMirror oneType = types.getPrimitiveType(TypeKind.INT); - Node expr = scan(exprTree, p); - - TypeMirror promotedType = binaryPromotedType(exprType, oneType); - - LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1)); - handleArtificialTree(oneTree); - - Node exprRHS = binaryNumericPromotion(expr, promotedType); - Node one = new IntegerLiteralNode(oneTree); - one.setInSource(false); - extendWithNode(one); - one = binaryNumericPromotion(one, promotedType); - - BinaryTree operTree = - treeBuilder.buildBinary( - promotedType, - (kind == Tree.Kind.POSTFIX_INCREMENT - ? Tree.Kind.PLUS - : Tree.Kind.MINUS), - exprTree, - oneTree); - handleArtificialTree(operTree); - Node operNode; - if (kind == Tree.Kind.POSTFIX_INCREMENT) { - operNode = new NumericalAdditionNode(operTree, exprRHS, one); - } else { - assert kind == Tree.Kind.POSTFIX_DECREMENT; - operNode = new NumericalSubtractionNode(operTree, exprRHS, one); - } - extendWithNode(operNode); - - Node narrowed = narrowAndBox(operNode, exprType); - // TODO: By using the assignment as the result of the expression, we - // act like a pre-increment/decrement. Fix this by saving the initial - // value of the expression in a temporary. - AssignmentNode assignNode = new AssignmentNode(tree, expr, narrowed); - extendWithNode(assignNode); - result = assignNode; - break; - } - case PREFIX_DECREMENT: - case PREFIX_INCREMENT: - { - ExpressionTree exprTree = tree.getExpression(); - TypeMirror exprType = InternalUtils.typeOf(exprTree); - TypeMirror oneType = types.getPrimitiveType(TypeKind.INT); - Node expr = scan(exprTree, p); - - TypeMirror promotedType = binaryPromotedType(exprType, oneType); - - LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1)); - handleArtificialTree(oneTree); - - Node exprRHS = binaryNumericPromotion(expr, promotedType); - Node one = new IntegerLiteralNode(oneTree); - one.setInSource(false); - extendWithNode(one); - one = binaryNumericPromotion(one, promotedType); - - BinaryTree operTree = - treeBuilder.buildBinary( - promotedType, - (kind == Tree.Kind.PREFIX_INCREMENT - ? Tree.Kind.PLUS - : Tree.Kind.MINUS), - exprTree, - oneTree); - handleArtificialTree(operTree); - Node operNode; - if (kind == Tree.Kind.PREFIX_INCREMENT) { - operNode = new NumericalAdditionNode(operTree, exprRHS, one); - } else { - assert kind == Tree.Kind.PREFIX_DECREMENT; - operNode = new NumericalSubtractionNode(operTree, exprRHS, one); - } - extendWithNode(operNode); - - Node narrowed = narrowAndBox(operNode, exprType); - AssignmentNode assignNode = new AssignmentNode(tree, expr, narrowed); - extendWithNode(assignNode); - result = assignNode; - break; - } - - case OTHER: - default: - // special node NLLCHK - if (tree.toString().startsWith("<*nullchk*>")) { - Node expr = scan(tree.getExpression(), p); - result = extendWithNode(new NullChkNode(tree, expr)); - break; - } - - assert false : "Unknown kind (" + kind + ") of unary expression: " + tree; - } - - return result; - } - - @Override - public Node visitVariable(VariableTree tree, Void p) { - - // see JLS 14.4 - - boolean isField = - getCurrentPath().getParentPath() != null - && getCurrentPath().getParentPath().getLeaf().getKind() == Kind.CLASS; - Node node = null; - - ClassTree enclosingClass = TreeUtils.enclosingClass(getCurrentPath()); - TypeElement classElem = TreeUtils.elementFromDeclaration(enclosingClass); - Node receiver = new ImplicitThisLiteralNode(classElem.asType()); - - if (isField) { - ExpressionTree initializer = tree.getInitializer(); - assert initializer != null; - node = - translateAssignment( - tree, - new FieldAccessNode( - tree, TreeUtils.elementFromDeclaration(tree), receiver), - initializer); - } else { - // local variable definition - VariableDeclarationNode decl = new VariableDeclarationNode(tree); - extendWithNode(decl); - - // initializer - - ExpressionTree initializer = tree.getInitializer(); - if (initializer != null) { - node = - translateAssignment( - tree, new LocalVariableNode(tree, receiver), initializer); - } - } - - return node; - } - - @Override - public Node visitWhileLoop(WhileLoopTree tree, Void p) { - Name parentLabel = getLabel(getCurrentPath()); - - Label loopEntry = new Label(); - Label loopExit = new Label(); - - // If the loop is a labeled statement, then its continue - // target is identical for continues with no label and - // continues with the loop's label. - Label conditionStart; - if (parentLabel != null) { - conditionStart = continueLabels.get(parentLabel); - } else { - conditionStart = new Label(); - } - - Label oldBreakTargetL = breakTargetL; - breakTargetL = loopExit; - - Label oldContinueTargetL = continueTargetL; - continueTargetL = conditionStart; - - // Condition - addLabelForNextNode(conditionStart); - if (tree.getCondition() != null) { - unbox(scan(tree.getCondition(), p)); - ConditionalJump cjump = new ConditionalJump(loopEntry, loopExit); - extendWithExtendedNode(cjump); - } - - // Loop body - addLabelForNextNode(loopEntry); - if (tree.getStatement() != null) { - scan(tree.getStatement(), p); - } - extendWithExtendedNode(new UnconditionalJump(conditionStart)); - - // Loop exit - addLabelForNextNode(loopExit); - - breakTargetL = oldBreakTargetL; - continueTargetL = oldContinueTargetL; - - return null; - } - - @Override - public Node visitLambdaExpression(LambdaExpressionTree tree, Void p) { - declaredLambdas.add(tree); - Node node = new FunctionalInterfaceNode(tree); - extendWithNode(node); - return node; - } - - @Override - public Node visitMemberReference(MemberReferenceTree tree, Void p) { - Tree enclosingExpr = tree.getQualifierExpression(); - if (enclosingExpr != null) { - scan(enclosingExpr, p); - } - - Node node = new FunctionalInterfaceNode(tree); - extendWithNode(node); - - return node; - } - - @Override - public Node visitWildcard(WildcardTree tree, Void p) { - assert false : "WildcardTree is unexpected in AST to CFG translation"; - return null; - } - - @Override - public Node visitOther(Tree tree, Void p) { - assert false : "Unknown AST element encountered in AST to CFG translation."; - return null; - } - } - - /** A tuple with 4 named elements. */ - private interface TreeInfo { - boolean isBoxed(); - - boolean isNumeric(); - - boolean isBoolean(); - - TypeMirror unboxedType(); - } - - private static A firstNonNull(A first, A second) { - if (first != null) { - return first; - } else if (second != null) { - return second; - } else { - throw new NullPointerException(); - } - } - - /* --------------------------------------------------------- */ - /* Utility routines for debugging CFG building */ - /* --------------------------------------------------------- */ - - /** - * Print a set of {@link Block}s and the edges between them. This is useful for examining the - * results of phase two. - */ - protected static void printBlocks(Set blocks) { - for (Block b : blocks) { - System.out.print(b.hashCode() + ": " + b); - switch (b.getType()) { - case REGULAR_BLOCK: - case SPECIAL_BLOCK: - { - Block succ = ((SingleSuccessorBlockImpl) b).getSuccessor(); - System.out.println(" -> " + (succ != null ? succ.hashCode() : "||")); - break; - } - case EXCEPTION_BLOCK: - { - Block succ = ((SingleSuccessorBlockImpl) b).getSuccessor(); - System.out.print(" -> " + (succ != null ? succ.hashCode() : "||") + " {"); - for (Map.Entry> entry : - ((ExceptionBlockImpl) b).getExceptionalSuccessors().entrySet()) { - System.out.print(entry.getKey() + " : " + entry.getValue() + ", "); - } - System.out.println("}"); - break; - } - case CONDITIONAL_BLOCK: - { - Block tSucc = ((ConditionalBlockImpl) b).getThenSuccessor(); - Block eSucc = ((ConditionalBlockImpl) b).getElseSuccessor(); - System.out.println( - " -> T " - + (tSucc != null ? tSucc.hashCode() : "||") - + " F " - + (eSucc != null ? eSucc.hashCode() : "||")); - break; - } - } - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java deleted file mode 100644 index 9378d83726a9af..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.checkerframework.dataflow.cfg; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -import java.util.Map; -import org.checkerframework.dataflow.analysis.AbstractValue; -import org.checkerframework.dataflow.analysis.Analysis; -import org.checkerframework.dataflow.analysis.FlowExpressions; -import org.checkerframework.dataflow.analysis.Store; -import org.checkerframework.dataflow.analysis.TransferFunction; -import org.checkerframework.dataflow.cfg.block.Block; -import org.checkerframework.dataflow.cfg.block.SpecialBlock; -import org.checkerframework.dataflow.cfg.node.Node; - -/** - * Perform some visualization on a control flow graph. The particular operations depend on the - * implementation. - */ -public interface CFGVisualizer< - A extends AbstractValue, S extends Store, T extends TransferFunction> { - /** - * Initialization method guaranteed to be called once before the first invocation of {@link - * visualize}. - * - * @param args implementation-dependent options - */ - void init(Map args); - - /** - * Output a visualization representing the control flow graph starting at {@code entry}. The - * concrete actions are implementation dependent. - * - *

This is always true, except for cases where the Java type information prevents - * aliasing and none of the subexpressions can alias 'other'. - */ - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return this.equals(other) || store.canAlias(this, other); - } - } - - public static class FieldAccess extends Receiver { - protected Receiver receiver; - protected VariableElement field; - - public Receiver getReceiver() { - return receiver; - } - - public VariableElement getField() { - return field; - } - - public FieldAccess(Receiver receiver, FieldAccessNode node) { - super(node.getType()); - this.receiver = receiver; - this.field = node.getElement(); - } - - public FieldAccess(Receiver receiver, TypeMirror type, VariableElement fieldElement) { - super(type); - this.receiver = receiver; - this.field = fieldElement; - } - - public boolean isFinal() { - return ElementUtils.isFinal(field); - } - - public boolean isStatic() { - return ElementUtils.isStatic(field); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof FieldAccess)) { - return false; - } - FieldAccess fa = (FieldAccess) obj; - return fa.getField().equals(getField()) && fa.getReceiver().equals(getReceiver()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getField(), getReceiver()); - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return super.containsModifiableAliasOf(store, other) - || receiver.containsModifiableAliasOf(store, other); - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) || receiver.containsSyntacticEqualReceiver(other); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof FieldAccess)) { - return false; - } - FieldAccess fa = (FieldAccess) other; - return super.syntacticEquals(other) - || (fa.getField().equals(getField()) - && fa.getReceiver().syntacticEquals(getReceiver())); - } - - @Override - public String toString() { - if (receiver instanceof ClassName) { - return receiver.getType() + "." + field; - } else { - return receiver + "." + field; - } - } - - @Override - public boolean containsOfClass(Class clazz) { - return getClass().equals(clazz) || receiver.containsOfClass(clazz); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return isFinal() && getReceiver().isUnmodifiableByOtherCode(); - } - } - - public static class ThisReference extends Receiver { - public ThisReference(TypeMirror type) { - super(type); - } - - @Override - public boolean equals(Object obj) { - return obj != null && obj instanceof ThisReference; - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(0); - } - - @Override - public String toString() { - return "this"; - } - - @Override - public boolean containsOfClass(Class clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return other instanceof ThisReference; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return false; // 'this' is not modifiable - } - } - - /** - * A ClassName represents the occurrence of a class as part of a static field access or method - * invocation. - */ - public static class ClassName extends Receiver { - public ClassName(TypeMirror type) { - super(type); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ClassName)) { - return false; - } - ClassName other = (ClassName) obj; - return getType().toString().equals(other.getType().toString()); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(getType().toString()); - } - - @Override - public String toString() { - return getType().toString() + ".class"; - } - - @Override - public boolean containsOfClass(Class clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return this.equals(other); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return false; // not modifiable - } - } - - public static class Unknown extends Receiver { - public Unknown(TypeMirror type) { - super(type); - } - - @Override - public boolean equals(Object obj) { - return obj == this; - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - @Override - public String toString() { - return "?"; - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return true; - } - - @Override - public boolean containsOfClass(Class clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - } - - public static class LocalVariable extends Receiver { - protected Element element; - - public LocalVariable(LocalVariableNode localVar) { - super(localVar.getType()); - this.element = localVar.getElement(); - } - - public LocalVariable(Element elem) { - super(ElementUtils.getType(elem)); - this.element = elem; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof LocalVariable)) { - return false; - } - LocalVariable other = (LocalVariable) obj; - VarSymbol vs = (VarSymbol) element; - VarSymbol vsother = (VarSymbol) other.element; - // Use TypeAnnotationUtils.unannotatedType(type).toString().equals(...) instead of Types.isSameType(...) - // because Types requires a processing environment, and FlowExpressions is - // designed to be independent of processing environment. See also - // calls to getType().toString() in FlowExpressions. - return vsother.name.contentEquals(vs.name) - && TypeAnnotationUtils.unannotatedType(vsother.type) - .toString() - .equals(TypeAnnotationUtils.unannotatedType(vs.type).toString()) - && vsother.owner.toString().equals(vs.owner.toString()); - } - - public Element getElement() { - return element; - } - - @Override - public int hashCode() { - VarSymbol vs = (VarSymbol) element; - return HashCodeUtils.hash( - vs.name.toString(), - TypeAnnotationUtils.unannotatedType(vs.type).toString(), - vs.owner.toString()); - } - - @Override - public String toString() { - return element.toString(); - } - - @Override - public boolean containsOfClass(Class clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof LocalVariable)) { - return false; - } - LocalVariable l = (LocalVariable) other; - return l.equals(this); - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - } - - public static class ValueLiteral extends Receiver { - - protected final Object value; - - public ValueLiteral(TypeMirror type, ValueLiteralNode node) { - super(type); - value = node.getValue(); - } - - public ValueLiteral(TypeMirror type, Object value) { - super(type); - this.value = value; - } - - @Override - public boolean containsOfClass(Class clazz) { - return getClass().equals(clazz); - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return true; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ValueLiteral)) { - return false; - } - ValueLiteral other = (ValueLiteral) obj; - if (value == null) { - return type.toString().equals(other.type.toString()) && other.value == null; - } - return type.toString().equals(other.type.toString()) && value.equals(other.value); - } - - @Override - public String toString() { - if (TypesUtils.isString(type)) { - return "\"" + value + "\""; - } else if (type.getKind() == TypeKind.LONG) { - return value.toString() + "L"; - } - return value == null ? "null" : value.toString(); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(value, type.toString()); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return this.equals(other); - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return false; // not modifiable - } - - public Object getValue() { - return value; - } - } - - /** A method call. */ - public static class MethodCall extends Receiver { - - protected final Receiver receiver; - protected final List parameters; - protected final ExecutableElement method; - - public MethodCall( - TypeMirror type, - ExecutableElement method, - Receiver receiver, - List parameters) { - super(type); - this.receiver = receiver; - this.parameters = parameters; - this.method = method; - } - - @Override - public boolean containsOfClass(Class clazz) { - if (getClass().equals(clazz)) { - return true; - } - if (receiver.containsOfClass(clazz)) { - return true; - } - for (Receiver p : parameters) { - if (p.containsOfClass(clazz)) { - return true; - } - } - return false; - } - - /** @return the method call receiver (for inspection only - do not modify) */ - public Receiver getReceiver() { - return receiver; - } - - /** - * @return the method call parameters (for inspection only - do not modify any of the - * parameters) - */ - public List getParameters() { - return Collections.unmodifiableList(parameters); - } - - /** @return the ExecutableElement for the method call */ - public ExecutableElement getElement() { - return method; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) || receiver.syntacticEquals(other); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof MethodCall)) { - return false; - } - MethodCall otherMethod = (MethodCall) other; - if (!receiver.syntacticEquals(otherMethod.receiver)) { - return false; - } - if (parameters.size() != otherMethod.parameters.size()) { - return false; - } - int i = 0; - for (Receiver p : parameters) { - if (!p.syntacticEquals(otherMethod.parameters.get(i))) { - return false; - } - i++; - } - return method.equals(otherMethod.method); - } - - public boolean containsSyntacticEqualParameter(LocalVariable var) { - for (Receiver p : parameters) { - if (p.containsSyntacticEqualReceiver(var)) { - return true; - } - } - return false; - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - if (receiver.containsModifiableAliasOf(store, other)) { - return true; - } - for (Receiver p : parameters) { - if (p.containsModifiableAliasOf(store, other)) { - return true; - } - } - return false; // the method call itself is not modifiable - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof MethodCall)) { - return false; - } - MethodCall other = (MethodCall) obj; - int i = 0; - for (Receiver p : parameters) { - if (!p.equals(other.parameters.get(i))) { - return false; - } - i++; - } - return receiver.equals(other.receiver) && method.equals(other.method); - } - - @Override - public int hashCode() { - int hash = HashCodeUtils.hash(method, receiver); - for (Receiver p : parameters) { - hash = HashCodeUtils.hash(hash, p); - } - return hash; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - if (receiver instanceof ClassName) { - result.append(receiver.getType()); - } else { - result.append(receiver); - } - result.append("."); - String methodName = method.getSimpleName().toString(); - result.append(methodName); - result.append("("); - boolean first = true; - for (Receiver p : parameters) { - if (!first) { - result.append(", "); - } - result.append(p.toString()); - first = false; - } - result.append(")"); - return result.toString(); - } - } - - /** A deterministic method call. */ - public static class ArrayAccess extends Receiver { - - protected final Receiver receiver; - protected final Receiver index; - - public ArrayAccess(TypeMirror type, Receiver receiver, Receiver index) { - super(type); - this.receiver = receiver; - this.index = index; - } - - @Override - public boolean containsOfClass(Class clazz) { - if (getClass().equals(clazz)) { - return true; - } - if (receiver.containsOfClass(clazz)) { - return true; - } - return index.containsOfClass(clazz); - } - - public Receiver getReceiver() { - return receiver; - } - - public Receiver getIndex() { - return index; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) - || receiver.syntacticEquals(other) - || index.syntacticEquals(other); - } - - @Override - public boolean syntacticEquals(Receiver other) { - if (!(other instanceof ArrayAccess)) { - return false; - } - ArrayAccess otherArrayAccess = (ArrayAccess) other; - if (!receiver.syntacticEquals(otherArrayAccess.receiver)) { - return false; - } - return index.syntacticEquals(otherArrayAccess.index); - } - - @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { - if (receiver.containsModifiableAliasOf(store, other)) { - return true; - } - return index.containsModifiableAliasOf(store, other); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayAccess)) { - return false; - } - ArrayAccess other = (ArrayAccess) obj; - return receiver.equals(other.receiver) && index.equals(other.index); - } - - @Override - public int hashCode() { - return HashCodeUtils.hash(receiver, index); - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append(receiver.toString()); - result.append("["); - result.append(index.toString()); - result.append("]"); - return result.toString(); - } - } - - public static class ArrayCreation extends Receiver { - - protected List dimensions; - protected List initializers; - - public ArrayCreation(TypeMirror type, List dimensions, List initializers) { - super(type); - this.dimensions = dimensions; - this.initializers = initializers; - } - - public List getDimensions() { - return dimensions; - } - - public List getInitializers() { - return initializers; - } - - @Override - public boolean containsOfClass(Class clazz) { - for (Node n : dimensions) { - if (n.getClass().equals(clazz)) return true; - } - for (Node n : initializers) { - if (n.getClass().equals(clazz)) return true; - } - return false; - } - - @Override - public boolean isUnmodifiableByOtherCode() { - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode()); - result = prime * result + ((initializers == null) ? 0 : initializers.hashCode()); - result = prime * result + HashCodeUtils.hash(getType().toString()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ArrayCreation)) { - return false; - } - ArrayCreation other = (ArrayCreation) obj; - return this.dimensions.equals(other.getDimensions()) - && this.initializers.equals(other.getInitializers()) - && getType().toString().equals(other.getType().toString()); - } - - @Override - public boolean syntacticEquals(Receiver other) { - return this.equals(other); - } - - @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append("new " + type); - if (!dimensions.isEmpty()) { - boolean needComma = false; - sb.append(" ("); - for (Node dim : dimensions) { - if (needComma) { - sb.append(", "); - } - sb.append(dim); - needComma = true; - } - sb.append(")"); - } - if (!initializers.isEmpty()) { - boolean needComma = false; - sb.append(" = {"); - for (Node init : initializers) { - if (needComma) { - sb.append(", "); - } - sb.append(init); - needComma = true; - } - sb.append("}"); - } - return sb.toString(); - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java deleted file mode 100644 index b4044fae836f2a..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -import java.util.Map; -import javax.lang.model.type.TypeMirror; - -/** - * Implementation of a {@link TransferResult} with just one non-exceptional store. The result of - * {@code getThenStore} and {@code getElseStore} is equal to the only underlying store. - * - * @author Stefan Heule - * @param the {@link Store} used to keep track of intermediate results - */ -public class RegularTransferResult, S extends Store> - extends TransferResult { - - /** The regular result store. */ - protected S store; - - private final boolean storeChanged; - - /** - * Create a {@code TransferResult} with {@code resultStore} as the resulting store. If the - * corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then - * {@code resultStore} is used for both the 'then' and 'else' edge. - * - *

If the given {@link Node} cannot be reached (in the control flow graph), then {@code null} - * is returned. - */ - protected S runAnalysisFor(Node node, boolean before) { - Block block = node.getBlock(); - TransferInput transferInput = stores.get(block); - if (transferInput == null) { - return null; - } - return runAnalysisFor(node, before, transferInput); - } - - /** - * Runs the analysis again within the block of {@code node} and returns the store at the - * location of {@code node}. If {@code before} is true, then the store immediately before the - * {@link Node} {@code node} is returned. Otherwise, the store after {@code node} is returned. - */ - public static , S extends Store> S runAnalysisFor( - Node node, boolean before, TransferInput transferInput) { - assert node != null; - Block block = node.getBlock(); - assert transferInput != null; - Analysis analysis = transferInput.analysis; - Node oldCurrentNode = analysis.currentNode; - - if (analysis.isRunning) { - return analysis.currentInput.getRegularStore(); - } - analysis.isRunning = true; - try { - switch (block.getType()) { - case REGULAR_BLOCK: - { - RegularBlock rb = (RegularBlock) block; - - // Apply transfer function to contents until we found the node - // we - // are looking for. - TransferInput store = transferInput; - TransferResult transferResult = null; - for (Node n : rb.getContents()) { - analysis.currentNode = n; - if (n == node && before) { - return store.getRegularStore(); - } - transferResult = analysis.callTransferFunction(n, store); - if (n == node) { - return transferResult.getRegularStore(); - } - store = new TransferInput<>(n, analysis, transferResult); - } - // This point should never be reached. If the block of 'node' is - // 'block', then 'node' must be part of the contents of 'block'. - assert false; - return null; - } - - case EXCEPTION_BLOCK: - { - ExceptionBlock eb = (ExceptionBlock) block; - - // apply transfer function to content - assert eb.getNode() == node; - if (before) { - return transferInput.getRegularStore(); - } - analysis.currentNode = node; - TransferResult transferResult = - analysis.callTransferFunction(node, transferInput); - return transferResult.getRegularStore(); - } - - default: - // Only regular blocks and exceptional blocks can hold nodes. - assert false; - break; - } - - return null; - } finally { - analysis.currentNode = oldCurrentNode; - analysis.isRunning = false; - } - } -} diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java deleted file mode 100644 index 99a8a525ec0ab3..00000000000000 --- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.checkerframework.dataflow.analysis; - -import java.util.Map; -import javax.lang.model.type.TypeMirror; - -/** - * Implementation of a {@link TransferResult} with two non-exceptional store; one for the 'then' - * edge and one for 'else'. The result of {@code getRegularStore} will be the least upper bound of - * the two underlying stores. - * - * @author Stefan Heule - * @param the {@link Store} used to keep track of intermediate results - */ -public class ConditionalTransferResult, S extends Store> - extends TransferResult { - - private final boolean storeChanged; - - /** The 'then' result store. */ - protected S thenStore; - - /** The 'else' result store. */ - protected S elseStore; - - /** - * Create a {@code ConditionalTransferResult} with {@code thenStore} as the resulting store if - * the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} evaluates to {@code - * true} and {@code elseStore} otherwise. - * - *

See the Checker Framework Manual:
%s
", text); - } - - @Override - public String toString(Tag tag) { - String[] split = tag.text().split(" ", 2); - return formatHeader(formatLink(split)); - } - - @Override - public String toString(Tag[] tags) { - if (tags.length == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(); - for (Tag t : tags) { - String[] split = t.text().split(" ", 2); - if (t != tags[0]) { - sb.append(", "); - } - sb.append(formatLink(split)); - } - return formatHeader(sb.toString()); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public static void register(Map tagletMap) { - ManualTaglet tag = new ManualTaglet(); - Taglet t = (Taglet) tagletMap.get(tag.getName()); - if (t != null) { - tagletMap.remove(tag.getName()); - } - tagletMap.put(tag.getName(), tag); - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java deleted file mode 100644 index 43d79cc7103157..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.checkerframework.javacutil.trees; - -import com.sun.source.tree.VariableTree; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.util.Name; - -/*>>> -import org.checkerframework.checker.nullness.qual.Nullable; -*/ - -/** - * A DetachedVarSymbol represents a variable that is not part of any AST Tree. DetachedVarSymbols - * are created when desugaring source code constructs and they carry important type information, but - * some methods such as TreeInfo.declarationFor do not work on them. - */ -public class DetachedVarSymbol extends Symbol.VarSymbol { - - protected /*@Nullable*/ VariableTree decl; - - /** Construct a detached variable symbol, given its flags, name, type and owner. */ - public DetachedVarSymbol(long flags, Name name, Type type, Symbol owner) { - super(flags, name, type, owner); - this.decl = null; - } - - /** Set the declaration tree for the variable. */ - public void setDeclaration(VariableTree decl) { - this.decl = decl; - } - - /** Get the declaration tree for the variable. */ - public /*@Nullable*/ VariableTree getDeclaration() { - return decl; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java deleted file mode 100644 index eab005dea809ce..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java +++ /dev/null @@ -1,655 +0,0 @@ -package org.checkerframework.javacutil.trees; - -import com.sun.source.tree.ArrayAccessTree; -import com.sun.source.tree.AssignmentTree; -import com.sun.source.tree.BinaryTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.IdentifierTree; -import com.sun.source.tree.LiteralTree; -import com.sun.source.tree.MemberSelectTree; -import com.sun.source.tree.MethodInvocationTree; -import com.sun.source.tree.StatementTree; -import com.sun.source.tree.Tree; -import com.sun.source.tree.TypeCastTree; -import com.sun.source.tree.VariableTree; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symtab; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Names; -import java.util.List; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; -import org.checkerframework.javacutil.InternalUtils; -import org.checkerframework.javacutil.TypesUtils; - -/** - * The TreeBuilder permits the creation of new AST Trees using the non-public Java compiler API - * TreeMaker. - */ -public class TreeBuilder { - protected final Elements elements; - protected final Types modelTypes; - protected final com.sun.tools.javac.code.Types javacTypes; - protected final TreeMaker maker; - protected final Names names; - protected final Symtab symtab; - protected final ProcessingEnvironment env; - - public TreeBuilder(ProcessingEnvironment env) { - this.env = env; - Context context = ((JavacProcessingEnvironment) env).getContext(); - elements = env.getElementUtils(); - modelTypes = env.getTypeUtils(); - javacTypes = com.sun.tools.javac.code.Types.instance(context); - maker = TreeMaker.instance(context); - names = Names.instance(context); - symtab = Symtab.instance(context); - } - - /** - * Builds an AST Tree to access the iterator() method of some iterable expression. - * - * @param iterableExpr an expression whose type is a subtype of Iterable - * @return a MemberSelectTree that accesses the iterator() method of the expression - */ - public MemberSelectTree buildIteratorMethodAccess(ExpressionTree iterableExpr) { - DeclaredType exprType = - (DeclaredType) TypesUtils.upperBound(InternalUtils.typeOf(iterableExpr)); - assert exprType != null : "expression must be of declared type Iterable<>"; - - TypeElement exprElement = (TypeElement) exprType.asElement(); - - // Find the iterator() method of the iterable type - Symbol.MethodSymbol iteratorMethod = null; - - for (ExecutableElement method : - ElementFilter.methodsIn(elements.getAllMembers(exprElement))) { - Name methodName = method.getSimpleName(); - - if (method.getParameters().size() == 0) { - if (methodName.contentEquals("iterator")) { - iteratorMethod = (Symbol.MethodSymbol) method; - } - } - } - - assert iteratorMethod != null : "no iterator method declared for expression type"; - - Type.MethodType methodType = (Type.MethodType) iteratorMethod.asType(); - Symbol.TypeSymbol methodClass = methodType.asElement(); - DeclaredType iteratorType = (DeclaredType) methodType.getReturnType(); - TypeMirror elementType; - - if (iteratorType.getTypeArguments().size() > 0) { - elementType = iteratorType.getTypeArguments().get(0); - // Remove captured type from a wildcard. - if (elementType instanceof Type.CapturedType) { - elementType = ((Type.CapturedType) elementType).wildcard; - } - - iteratorType = - modelTypes.getDeclaredType( - (TypeElement) modelTypes.asElement(iteratorType), elementType); - } - - // Replace the iterator method's generic return type with - // the actual element type of the expression. - Type.MethodType updatedMethodType = - new Type.MethodType( - com.sun.tools.javac.util.List.nil(), - (Type) iteratorType, - com.sun.tools.javac.util.List.nil(), - methodClass); - - JCTree.JCFieldAccess iteratorAccess = - (JCTree.JCFieldAccess) - maker.Select((JCTree.JCExpression) iterableExpr, iteratorMethod); - iteratorAccess.setType(updatedMethodType); - - return iteratorAccess; - } - - /** - * Builds an AST Tree to access the hasNext() method of an iterator. - * - * @param iteratorExpr an expression whose type is a subtype of Iterator - * @return a MemberSelectTree that accesses the hasNext() method of the expression - */ - public MemberSelectTree buildHasNextMethodAccess(ExpressionTree iteratorExpr) { - DeclaredType exprType = (DeclaredType) InternalUtils.typeOf(iteratorExpr); - assert exprType != null : "expression must be of declared type Iterator<>"; - - TypeElement exprElement = (TypeElement) exprType.asElement(); - - // Find the hasNext() method of the iterator type - Symbol.MethodSymbol hasNextMethod = null; - - for (ExecutableElement method : - ElementFilter.methodsIn(elements.getAllMembers(exprElement))) { - Name methodName = method.getSimpleName(); - - if (method.getParameters().size() == 0) { - if (methodName.contentEquals("hasNext")) { - hasNextMethod = (Symbol.MethodSymbol) method; - } - } - } - - assert hasNextMethod != null : "no hasNext method declared for expression type"; - - JCTree.JCFieldAccess hasNextAccess = - (JCTree.JCFieldAccess) - maker.Select((JCTree.JCExpression) iteratorExpr, hasNextMethod); - hasNextAccess.setType(hasNextMethod.asType()); - - return hasNextAccess; - } - - /** - * Builds an AST Tree to access the next() method of an iterator. - * - * @param iteratorExpr an expression whose type is a subtype of Iterator - * @return a MemberSelectTree that accesses the next() method of the expression - */ - public MemberSelectTree buildNextMethodAccess(ExpressionTree iteratorExpr) { - DeclaredType exprType = (DeclaredType) InternalUtils.typeOf(iteratorExpr); - assert exprType != null : "expression must be of declared type Iterator<>"; - - TypeElement exprElement = (TypeElement) exprType.asElement(); - - // Find the next() method of the iterator type - Symbol.MethodSymbol nextMethod = null; - - for (ExecutableElement method : - ElementFilter.methodsIn(elements.getAllMembers(exprElement))) { - Name methodName = method.getSimpleName(); - - if (method.getParameters().size() == 0) { - if (methodName.contentEquals("next")) { - nextMethod = (Symbol.MethodSymbol) method; - } - } - } - - assert nextMethod != null : "no next method declared for expression type"; - - Type.MethodType methodType = (Type.MethodType) nextMethod.asType(); - Symbol.TypeSymbol methodClass = methodType.asElement(); - Type elementType; - - if (exprType.getTypeArguments().size() > 0) { - elementType = (Type) exprType.getTypeArguments().get(0); - } else { - elementType = symtab.objectType; - } - - // Replace the next method's generic return type with - // the actual element type of the expression. - Type.MethodType updatedMethodType = - new Type.MethodType( - com.sun.tools.javac.util.List.nil(), - elementType, - com.sun.tools.javac.util.List.nil(), - methodClass); - - JCTree.JCFieldAccess nextAccess = - (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) iteratorExpr, nextMethod); - nextAccess.setType(updatedMethodType); - - return nextAccess; - } - - /** - * Builds an AST Tree to dereference the length field of an array - * - * @param expression the array expression whose length is being accessed - * @return a MemberSelectTree to dereference the length of the array - */ - public MemberSelectTree buildArrayLengthAccess(ExpressionTree expression) { - - return (JCTree.JCFieldAccess) - maker.Select((JCTree.JCExpression) expression, symtab.lengthVar); - } - - /** - * Builds an AST Tree to call a method designated by the argument expression. - * - * @param methodExpr an expression denoting a method with no arguments - * @return a MethodInvocationTree to call the argument method - */ - public MethodInvocationTree buildMethodInvocation(ExpressionTree methodExpr) { - return maker.App((JCTree.JCExpression) methodExpr); - } - - /** - * Builds an AST Tree to call a method designated by methodExpr, with one argument designated by - * argExpr. - * - * @param methodExpr an expression denoting a method with one argument - * @param argExpr an expression denoting an argument to the method - * @return a MethodInvocationTree to call the argument method - */ - public MethodInvocationTree buildMethodInvocation( - ExpressionTree methodExpr, ExpressionTree argExpr) { - return maker.App( - (JCTree.JCExpression) methodExpr, - com.sun.tools.javac.util.List.of((JCTree.JCExpression) argExpr)); - } - - /** - * Builds an AST Tree to declare and initialize a variable, with no modifiers. - * - * @param type the type of the variable - * @param name the name of the variable - * @param owner the element containing the new symbol - * @param initializer the initializer expression - * @return a VariableDeclTree declaring the new variable - */ - public VariableTree buildVariableDecl( - TypeMirror type, String name, Element owner, ExpressionTree initializer) { - DetachedVarSymbol sym = - new DetachedVarSymbol(0, names.fromString(name), (Type) type, (Symbol) owner); - VariableTree tree = maker.VarDef(sym, (JCTree.JCExpression) initializer); - sym.setDeclaration(tree); - return tree; - } - - /** - * Builds an AST Tree to declare and initialize a variable. The type of the variable is - * specified by a Tree. - * - * @param type the type of the variable, as a Tree - * @param name the name of the variable - * @param owner the element containing the new symbol - * @param initializer the initializer expression - * @return a VariableDeclTree declaring the new variable - */ - public VariableTree buildVariableDecl( - Tree type, String name, Element owner, ExpressionTree initializer) { - Type typeMirror = (Type) InternalUtils.typeOf(type); - DetachedVarSymbol sym = - new DetachedVarSymbol(0, names.fromString(name), typeMirror, (Symbol) owner); - JCTree.JCModifiers mods = maker.Modifiers(0); - JCTree.JCVariableDecl decl = - maker.VarDef( - mods, - sym.name, - (JCTree.JCExpression) type, - (JCTree.JCExpression) initializer); - decl.setType(typeMirror); - decl.sym = sym; - sym.setDeclaration(decl); - return decl; - } - - /** - * Builds an AST Tree to refer to a variable. - * - * @param decl the declaration of the variable - * @return an IdentifierTree to refer to the variable - */ - public IdentifierTree buildVariableUse(VariableTree decl) { - return (IdentifierTree) maker.Ident((JCTree.JCVariableDecl) decl); - } - - /** - * Builds an AST Tree to cast the type of an expression. - * - * @param type the type to cast to - * @param expr the expression to be cast - * @return a cast of the expression to the type - */ - public TypeCastTree buildTypeCast(TypeMirror type, ExpressionTree expr) { - return maker.TypeCast((Type) type, (JCTree.JCExpression) expr); - } - - /** - * Builds an AST Tree to assign an expression to a variable. - * - * @param variable the declaration of the variable to assign to - * @param expr the expression to be assigned - * @return a statement assigning the expression to the variable - */ - public StatementTree buildAssignment(VariableTree variable, ExpressionTree expr) { - return maker.Assignment(TreeInfo.symbolFor((JCTree) variable), (JCTree.JCExpression) expr); - } - - /** - * Builds an AST Tree to assign an RHS expression to an LHS expression. - * - * @param lhs the expression to be assigned to - * @param rhs the expression to be assigned - * @return a statement assigning the expression to the variable - */ - public AssignmentTree buildAssignment(ExpressionTree lhs, ExpressionTree rhs) { - JCTree.JCAssign assign = maker.Assign((JCTree.JCExpression) lhs, (JCTree.JCExpression) rhs); - assign.setType((Type) InternalUtils.typeOf(lhs)); - return assign; - } - - /** Builds an AST Tree representing a literal value of primitive or String type. */ - public LiteralTree buildLiteral(Object value) { - return maker.Literal(value); - } - - /** - * Builds an AST Tree to compare two operands with less than. - * - * @param left the left operand tree - * @param right the right operand tree - * @return a Tree representing "left < right" - */ - public BinaryTree buildLessThan(ExpressionTree left, ExpressionTree right) { - JCTree.JCBinary binary = - maker.Binary( - JCTree.Tag.LT, (JCTree.JCExpression) left, (JCTree.JCExpression) right); - binary.setType((Type) modelTypes.getPrimitiveType(TypeKind.BOOLEAN)); - return binary; - } - - /** - * Builds an AST Tree to dereference an array. - * - * @param array the array to dereference - * @param index the index at which to dereference - * @return a Tree representing the dereference - */ - public ArrayAccessTree buildArrayAccess(ExpressionTree array, ExpressionTree index) { - ArrayType arrayType = (ArrayType) InternalUtils.typeOf(array); - JCTree.JCArrayAccess access = - maker.Indexed((JCTree.JCExpression) array, (JCTree.JCExpression) index); - access.setType((Type) arrayType.getComponentType()); - return access; - } - - /** - * Builds an AST Tree to refer to a class name. - * - * @param elt an element representing the class - * @return an IdentifierTree referring to the class - */ - public IdentifierTree buildClassUse(Element elt) { - return maker.Ident((Symbol) elt); - } - - /** - * Builds an AST Tree to access the valueOf() method of boxed type such as Short or Float. - * - * @param expr an expression whose type is a boxed type - * @return a MemberSelectTree that accesses the valueOf() method of the expression - */ - public MemberSelectTree buildValueOfMethodAccess(Tree expr) { - TypeMirror boxedType = InternalUtils.typeOf(expr); - - assert TypesUtils.isBoxedPrimitive(boxedType); - - // Find the valueOf(unboxedType) method of the boxed type - Symbol.MethodSymbol valueOfMethod = getValueOfMethod(env, boxedType); - - Type.MethodType methodType = (Type.MethodType) valueOfMethod.asType(); - - JCTree.JCFieldAccess valueOfAccess = - (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) expr, valueOfMethod); - valueOfAccess.setType(methodType); - - return valueOfAccess; - } - - /** Returns the valueOf method of a boxed type such as Short or Float. */ - public static Symbol.MethodSymbol getValueOfMethod( - ProcessingEnvironment env, TypeMirror boxedType) { - Symbol.MethodSymbol valueOfMethod = null; - - TypeMirror unboxedType = env.getTypeUtils().unboxedType(boxedType); - TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement(); - for (ExecutableElement method : - ElementFilter.methodsIn(env.getElementUtils().getAllMembers(boxedElement))) { - Name methodName = method.getSimpleName(); - - if (methodName.contentEquals("valueOf")) { - List params = method.getParameters(); - if (params.size() == 1 - && env.getTypeUtils().isSameType(params.get(0).asType(), unboxedType)) { - valueOfMethod = (Symbol.MethodSymbol) method; - } - } - } - - assert valueOfMethod != null : "no valueOf method declared for boxed type"; - return valueOfMethod; - } - - /** - * Builds an AST Tree to access the *Value() method of a boxed type such as Short or Float, - * where * is the corresponding primitive type (i.e. shortValue or floatValue). - * - * @param expr an expression whose type is a boxed type - * @return a MemberSelectTree that accesses the *Value() method of the expression - */ - public MemberSelectTree buildPrimValueMethodAccess(Tree expr) { - TypeMirror boxedType = InternalUtils.typeOf(expr); - TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement(); - - assert TypesUtils.isBoxedPrimitive(boxedType); - TypeMirror unboxedType = modelTypes.unboxedType(boxedType); - - // Find the *Value() method of the boxed type - String primValueName = unboxedType.toString() + "Value"; - Symbol.MethodSymbol primValueMethod = null; - - for (ExecutableElement method : - ElementFilter.methodsIn(elements.getAllMembers(boxedElement))) { - Name methodName = method.getSimpleName(); - - if (methodName.contentEquals(primValueName) && method.getParameters().size() == 0) { - primValueMethod = (Symbol.MethodSymbol) method; - } - } - - assert primValueMethod != null : "no *Value method declared for boxed type"; - - Type.MethodType methodType = (Type.MethodType) primValueMethod.asType(); - - JCTree.JCFieldAccess primValueAccess = - (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) expr, primValueMethod); - primValueAccess.setType(methodType); - - return primValueAccess; - } - - /** Map public AST Tree.Kinds to internal javac JCTree.Tags. */ - public JCTree.Tag kindToTag(Tree.Kind kind) { - switch (kind) { - case AND: - return JCTree.Tag.BITAND; - case AND_ASSIGNMENT: - return JCTree.Tag.BITAND_ASG; - case ANNOTATION: - return JCTree.Tag.ANNOTATION; - case ANNOTATION_TYPE: - return JCTree.Tag.TYPE_ANNOTATION; - case ARRAY_ACCESS: - return JCTree.Tag.INDEXED; - case ARRAY_TYPE: - return JCTree.Tag.TYPEARRAY; - case ASSERT: - return JCTree.Tag.ASSERT; - case ASSIGNMENT: - return JCTree.Tag.ASSIGN; - case BITWISE_COMPLEMENT: - return JCTree.Tag.COMPL; - case BLOCK: - return JCTree.Tag.BLOCK; - case BREAK: - return JCTree.Tag.BREAK; - case CASE: - return JCTree.Tag.CASE; - case CATCH: - return JCTree.Tag.CATCH; - case CLASS: - return JCTree.Tag.CLASSDEF; - case CONDITIONAL_AND: - return JCTree.Tag.AND; - case CONDITIONAL_EXPRESSION: - return JCTree.Tag.CONDEXPR; - case CONDITIONAL_OR: - return JCTree.Tag.OR; - case CONTINUE: - return JCTree.Tag.CONTINUE; - case DIVIDE: - return JCTree.Tag.DIV; - case DIVIDE_ASSIGNMENT: - return JCTree.Tag.DIV_ASG; - case DO_WHILE_LOOP: - return JCTree.Tag.DOLOOP; - case ENHANCED_FOR_LOOP: - return JCTree.Tag.FOREACHLOOP; - case EQUAL_TO: - return JCTree.Tag.EQ; - case EXPRESSION_STATEMENT: - return JCTree.Tag.EXEC; - case FOR_LOOP: - return JCTree.Tag.FORLOOP; - case GREATER_THAN: - return JCTree.Tag.GT; - case GREATER_THAN_EQUAL: - return JCTree.Tag.GE; - case IDENTIFIER: - return JCTree.Tag.IDENT; - case IF: - return JCTree.Tag.IF; - case IMPORT: - return JCTree.Tag.IMPORT; - case INSTANCE_OF: - return JCTree.Tag.TYPETEST; - case LABELED_STATEMENT: - return JCTree.Tag.LABELLED; - case LEFT_SHIFT: - return JCTree.Tag.SL; - case LEFT_SHIFT_ASSIGNMENT: - return JCTree.Tag.SL_ASG; - case LESS_THAN: - return JCTree.Tag.LT; - case LESS_THAN_EQUAL: - return JCTree.Tag.LE; - case LOGICAL_COMPLEMENT: - return JCTree.Tag.NOT; - case MEMBER_SELECT: - return JCTree.Tag.SELECT; - case METHOD: - return JCTree.Tag.METHODDEF; - case METHOD_INVOCATION: - return JCTree.Tag.APPLY; - case MINUS: - return JCTree.Tag.MINUS; - case MINUS_ASSIGNMENT: - return JCTree.Tag.MINUS_ASG; - case MODIFIERS: - return JCTree.Tag.MODIFIERS; - case MULTIPLY: - return JCTree.Tag.MUL; - case MULTIPLY_ASSIGNMENT: - return JCTree.Tag.MUL_ASG; - case NEW_ARRAY: - return JCTree.Tag.NEWARRAY; - case NEW_CLASS: - return JCTree.Tag.NEWCLASS; - case NOT_EQUAL_TO: - return JCTree.Tag.NE; - case OR: - return JCTree.Tag.BITOR; - case OR_ASSIGNMENT: - return JCTree.Tag.BITOR_ASG; - case PARENTHESIZED: - return JCTree.Tag.PARENS; - case PLUS: - return JCTree.Tag.PLUS; - case PLUS_ASSIGNMENT: - return JCTree.Tag.PLUS_ASG; - case POSTFIX_DECREMENT: - return JCTree.Tag.POSTDEC; - case POSTFIX_INCREMENT: - return JCTree.Tag.POSTINC; - case PREFIX_DECREMENT: - return JCTree.Tag.PREDEC; - case PREFIX_INCREMENT: - return JCTree.Tag.PREINC; - case REMAINDER: - return JCTree.Tag.MOD; - case REMAINDER_ASSIGNMENT: - return JCTree.Tag.MOD_ASG; - case RETURN: - return JCTree.Tag.RETURN; - case RIGHT_SHIFT: - return JCTree.Tag.SR; - case RIGHT_SHIFT_ASSIGNMENT: - return JCTree.Tag.SR_ASG; - case SWITCH: - return JCTree.Tag.SWITCH; - case SYNCHRONIZED: - return JCTree.Tag.SYNCHRONIZED; - case THROW: - return JCTree.Tag.THROW; - case TRY: - return JCTree.Tag.TRY; - case TYPE_CAST: - return JCTree.Tag.TYPECAST; - case TYPE_PARAMETER: - return JCTree.Tag.TYPEPARAMETER; - case UNARY_MINUS: - return JCTree.Tag.NEG; - case UNARY_PLUS: - return JCTree.Tag.POS; - case UNION_TYPE: - return JCTree.Tag.TYPEUNION; - case UNSIGNED_RIGHT_SHIFT: - return JCTree.Tag.USR; - case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: - return JCTree.Tag.USR_ASG; - case VARIABLE: - return JCTree.Tag.VARDEF; - case WHILE_LOOP: - return JCTree.Tag.WHILELOOP; - case XOR: - return JCTree.Tag.BITXOR; - case XOR_ASSIGNMENT: - return JCTree.Tag.BITXOR_ASG; - default: - return JCTree.Tag.NO_TAG; - } - } - - /** - * Builds an AST Tree to perform a binary operation. - * - * @param type result type of the operation - * @param op AST Tree operator - * @param left the left operand tree - * @param right the right operand tree - * @return a Tree representing "left < right" - */ - public BinaryTree buildBinary( - TypeMirror type, Tree.Kind op, ExpressionTree left, ExpressionTree right) { - JCTree.Tag jcOp = kindToTag(op); - JCTree.JCBinary binary = - maker.Binary(jcOp, (JCTree.JCExpression) left, (JCTree.JCExpression) right); - binary.setType((Type) type); - return binary; - } -} diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java deleted file mode 100644 index 9ea545e55cc0bb..00000000000000 --- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.checkerframework.javacutil.trees; - -import com.sun.source.tree.ExpressionTree; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Names; -import java.util.StringTokenizer; -import javax.annotation.processing.ProcessingEnvironment; - -/** - * A Utility class for parsing Java expression snippets, and converting them to proper Javac AST - * nodes. - * - *

This is useful for parsing {@code EnsuresNonNull*}, and {@code KeyFor} values. - * - *

Currently, it handles four tree types only: - * - *

    - *
  • Identifier tree (e.g. {@code id}) - *
  • Literal tree (e.g. 2, 3) - *
  • Method invocation tree (e.g. {@code method(2, 3)}) - *
  • Member select tree (e.g. {@code Class.field}, {@code instance.method()}) - *
  • Array access tree (e.g. {@code array[id]}) - *
- * - * Notable limitation: Doesn't handle spaces, or non-method-argument parenthesis. - * - *

It's implemented via a Recursive-Descend parser. - */ -public class TreeParser { - private static final String DELIMS = ".[](),"; - private static final String SENTINAL = ""; - - private final TreeMaker maker; - private final Names names; - - public TreeParser(ProcessingEnvironment env) { - Context context = ((JavacProcessingEnvironment) env).getContext(); - maker = TreeMaker.instance(context); - names = Names.instance(context); - } - - /** - * Parses the snippet in the string as an internal Javac AST expression node - * - * @param s the java snippet - * @return the AST corresponding to the snippet - */ - public ExpressionTree parseTree(String s) { - tokenizer = new StringTokenizer(s, DELIMS, true); - token = tokenizer.nextToken(); - - try { - return parseExpression(); - } catch (Exception e) { - throw new ParseError(e); - } finally { - tokenizer = null; - token = null; - } - } - - StringTokenizer tokenizer = null; - String token = null; - - private String nextToken() { - token = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : SENTINAL; - return token; - } - - JCExpression fromToken(String token) { - // Optimization - if ("true".equals(token)) { - return maker.Literal(true); - } else if ("false".equals(token)) { - return maker.Literal(false); - } - - if (Character.isLetter(token.charAt(0))) { - return maker.Ident(names.fromString(token)); - } - - Object value = null; - try { - value = Integer.valueOf(token); - } catch (Exception e2) { - try { - value = Double.valueOf(token); - } catch (Exception ef) { - } - } - assert value != null; - return maker.Literal(value); - } - - JCExpression parseExpression() { - JCExpression tree = fromToken(token); - - while (tokenizer.hasMoreTokens()) { - String delim = nextToken(); - if (".".equals(delim)) { - nextToken(); - tree = maker.Select(tree, names.fromString(token)); - } else if ("(".equals(delim)) { - nextToken(); - ListBuffer args = new ListBuffer<>(); - while (!")".equals(token)) { - JCExpression arg = parseExpression(); - args.append(arg); - if (",".equals(token)) { - nextToken(); - } - } - // For now, handle empty args only - assert ")".equals(token); - tree = maker.Apply(List.nil(), tree, args.toList()); - } else if ("[".equals(token)) { - nextToken(); - JCExpression index = parseExpression(); - assert "]".equals(token); - tree = maker.Indexed(tree, index); - } else { - return tree; - } - } - - return tree; - } - - private static class ParseError extends RuntimeException { - private static final long serialVersionUID = 1887754619522101929L; - - ParseError(Throwable cause) { - super(cause); - } - } -} diff --git a/third_party/checker_framework_javacutil/javacutil-2.2.2-sources.jar b/third_party/checker_framework_javacutil/javacutil-2.2.2-sources.jar new file mode 100644 index 0000000000000000000000000000000000000000..fdd23d872945f9d4c4288da44a8f7fe31eee970f GIT binary patch literal 55437 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 Zx3_HsoDsa%0DvI)=>u>1ac?&M{SO#k@H7Ab literal 0 HcmV?d00001 diff --git a/third_party/checker_framework_javacutil/javacutil-2.2.2.jar b/third_party/checker_framework_javacutil/javacutil-2.2.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..7e12f3135906809a0ad0707f772b22c9d450ee21 GIT binary patch literal 91671 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

hUG>hcaVwJpK# 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 qZ*ctJhaqZ