Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jdt.annotation/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jdt.annotation/pom.xml2
-rw-r--r--org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/declaration/EclipseDeclarationImpl.java4
-rw-r--r--org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/util/ManyToMany.java5
-rw-r--r--org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java47
-rw-r--r--org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jdt.apt.pluggable.tests/plugin.xml4
-rw-r--r--org.eclipse.jdt.apt.pluggable.tests/pom.xml2
-rw-r--r--org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java28
-rw-r--r--org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Bug341298Processor.java84
-rw-r--r--org.eclipse.jdt.apt.tests/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jdt.apt.tests/pom.xml2
-rw-r--r--org.eclipse.jdt.apt.tests/src-annotations/org/eclipse/jdt/apt/tests/annotations/apitest/APIAnnotationProcessorFactory.java4
-rw-r--r--org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/FactoryPathTests.java2
-rw-r--r--org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AdvancedFactoryPathOptionsDialog.java7
-rw-r--r--org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AptConfigurationBlock.java9
-rw-r--r--org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/Messages.java5
-rw-r--r--org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/messages.properties1
-rw-r--r--org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jdt.compiler.apt.tests/pom.xml2
-rw-r--r--org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java12
-rw-r--r--org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java29
-rw-r--r--org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java5
-rw-r--r--org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java29
-rw-r--r--org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jdt.core.tests.builder/pom.xml2
-rw-r--r--org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParticipantBuildTests.java18
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java2
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java8
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java72
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java214
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java53
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java40
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java2
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java47
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java267
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java76
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/CodeSnippetTest.java14
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationSetup.java219
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/EvaluationSetup.java72
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/SimpleTest.java100
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/target/IDEInterface.java6
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/TargetInterface.java9
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java107
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java7
-rw-r--r--org.eclipse.jdt.core.tests.model/pom.xml7
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/APIDocumentationTests.java16
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java22
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java16
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/RunAllTestsTracing.java22
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java99
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java30
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java7
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java8
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/comment/SingleLineTestCase.java3
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java20
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTestsTracing.java22
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java297
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java8
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java16
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionWithMissingTypesTests_1_5.java2
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java2
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java6
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java4
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/DatabaseTest.java4
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java320
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldOneToOneTest.java8
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/LargeBlockTest.java71
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java1
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/indexer/IndexerTest.java3
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java17
-rw-r--r--org.eclipse.jdt.core.tests.model/test.xml6
-rw-r--r--org.eclipse.jdt.core.tests.performance/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jdt.core.tests.performance/pom.xml2
-rw-r--r--org.eclipse.jdt.core/.options11
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java2
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java7
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java32
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java24
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java9
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java39
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java18
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java24
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java22
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java32
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java12
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java48
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java45
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java17
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java2
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java4
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java3
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java4
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java48
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java4
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java8
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java26
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java7
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java13
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java19
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java4
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java58
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java10
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java8
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java8
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java5
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java3
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java26
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java38
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java35
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java90
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java17
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java63
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java8
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java49
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java56
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/BTree.java2
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkCache.java30
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java456
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java49
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java443
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/RelatedAddress.java59
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/BaseField.java25
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java38
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldByte.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldChar.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldDouble.java25
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldFloat.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldInt.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java327
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldLong.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java152
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java30
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java58
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldPointer.java24
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java27
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchKey.java43
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldShort.java24
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldString.java56
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java40
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java104
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/BindingToIndexConverter.java123
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java158
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java78
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java49
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java26
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java37
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java24
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java20
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java5
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java6
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java18
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java116
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java32
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java19
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java107
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java29
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java32
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java99
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java114
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java22
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java17
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java4
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java28
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java40
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java18
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java10
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java27
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java38
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java5
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java4
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java4
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java10
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java8
202 files changed, 5360 insertions, 2117 deletions
diff --git a/org.eclipse.jdt.annotation/META-INF/MANIFEST.MF b/org.eclipse.jdt.annotation/META-INF/MANIFEST.MF
index ffad534427..1053b02539 100644
--- a/org.eclipse.jdt.annotation/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.annotation/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %bundleName
Bundle-Localization: bundle
Bundle-SymbolicName: org.eclipse.jdt.annotation
-Bundle-Version: 2.1.0.qualifier
+Bundle-Version: 2.1.100.qualifier
Export-Package: org.eclipse.jdt.annotation
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Vendor: %providerName
diff --git a/org.eclipse.jdt.annotation/pom.xml b/org.eclipse.jdt.annotation/pom.xml
index af9a1d5610..fc0dedfab4 100644
--- a/org.eclipse.jdt.annotation/pom.xml
+++ b/org.eclipse.jdt.annotation/pom.xml
@@ -18,7 +18,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.annotation</artifactId>
- <version>2.1.0-SNAPSHOT</version>
+ <version>2.1.100-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
<build>
diff --git a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/declaration/EclipseDeclarationImpl.java b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/declaration/EclipseDeclarationImpl.java
index a293f2e21b..b80570bfa4 100644
--- a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/declaration/EclipseDeclarationImpl.java
+++ b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/declaration/EclipseDeclarationImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2015 BEA Systems, Inc.
+ * Copyright (c) 2005, 2017 BEA Systems, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -173,7 +173,7 @@ public abstract class EclipseDeclarationImpl implements Declaration, EclipseMirr
if( declName == null ) return node;
for(Object obj : ((FieldDeclaration)node).fragments() ){
VariableDeclarationFragment frag = (VariableDeclarationFragment)obj;
- if( declName.equals(frag.getName()) ){
+ if( declName.equals(frag.getName().toString()) ){
name = frag.getName();
break;
}
diff --git a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/util/ManyToMany.java b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/util/ManyToMany.java
index 0a6ac688c2..77c5b57def 100644
--- a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/util/ManyToMany.java
+++ b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/util/ManyToMany.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2015 BEA Systems, Inc.
+ * Copyright (c) 2006, 2017 BEA Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* wharley@bea.com - initial API and implementation
+ * IBM Corporation - Bug 513790
*******************************************************************************/
package org.eclipse.jdt.apt.core.internal.util;
@@ -312,7 +313,7 @@ public class ManyToMany<T1, T2> {
* @see #keyHasOtherValues(Object, Object)
*/
public synchronized boolean valueHasOtherKeys(T2 value, T1 key) {
- Set<T1> keys = _reverse.get(key);
+ Set<T1> keys = _reverse.get(value);
if (keys == null)
return false;
int size = keys.size();
diff --git a/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java b/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java
index c1e9fa69e3..632963cf15 100644
--- a/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java
+++ b/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 BEA Systems, Inc.
+ * Copyright (c) 2007 - 2017 BEA Systems, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,15 +7,22 @@
*
* Contributors:
* wharley@bea.com - initial API and implementation
- *
+ * Fabian Steeg <steeg@hbz-nrw.de> - Pass automatically provided options to Java 6 processors - https://bugs.eclipse.org/341298
*******************************************************************************/
package org.eclipse.jdt.internal.apt.pluggable.core.dispatch;
+import static java.util.stream.Collectors.partitioningBy;
+import static java.util.stream.Collectors.toMap;
+
import java.util.Collections;
-import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.lang.model.element.Element;
@@ -72,17 +79,35 @@ public abstract class IdeProcessingEnvImpl extends BaseProcessingEnvImpl {
// -classpath, etc., but Java 6 options only include the options specified
// with -A, which will have been parsed into key/value pairs with no dash.
Map<String, String> allOptions = AptConfig.getProcessorOptions(_javaProject);
- Map<String, String> procOptions = new HashMap<String, String>();
- for (Map.Entry<String, String> entry : allOptions.entrySet()) {
- if (!entry.getKey().startsWith("-")) { //$NON-NLS-1$
- procOptions.put(entry.getKey(), entry.getValue());
- }
- }
- procOptions.put("phase", getPhase().toString()); //$NON-NLS-1$
- _processorOptions = Collections.unmodifiableMap(procOptions);
+
+ // But we make them available as variables in processor options configured by users
+ // (e.g. %classpath% in an option value is replaced with the value of -classpath):
+ Map<Boolean, List<Entry<String, String>>> isCommandLineOption = allOptions.entrySet().stream()
+ .collect(partitioningBy(option -> option.getKey().startsWith("-")));
+
+ Map<String, String> commandLineOptions = isCommandLineOption.get(true).stream()
+ .collect(toMap(e -> e.getKey().substring(1), Entry::getValue));
+
+ Map<String, String> processorOptions = isCommandLineOption.get(false).stream()
+ .collect(toMap(Entry::getKey, replacePlaceholdersUsing(commandLineOptions)));
+
+ processorOptions.put("phase", getPhase().toString()); //$NON-NLS-1$
+ _processorOptions = Collections.unmodifiableMap(processorOptions);
}
return _processorOptions;
}
+
+ private Function<Entry<String, String>, String> replacePlaceholdersUsing(Map<String, String> commandLineOptions) {
+ return option -> {
+ String variable, replacement, optionValue = option.getValue();
+ Matcher placeholder = Pattern.compile("%([^%]+)%").matcher(optionValue);
+ if (placeholder.find() && (variable = placeholder.group(1)) != null
+ && (replacement = commandLineOptions.get(variable)) != null) {
+ optionValue = optionValue.replace("%" + variable + "%", replacement);
+ }
+ return optionValue;
+ };
+ }
public AptProject getAptProject() {
return _aptProject;
diff --git a/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF
index c3874e9342..3622d1d6a3 100644
--- a/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.apt.pluggable.tests;singleton:=true
-Bundle-Version: 3.4.100.qualifier
+Bundle-Version: 3.4.200.qualifier
Bundle-Activator: org.eclipse.jdt.apt.pluggable.tests.Apt6TestsPlugin
Bundle-Localization: plugin
Require-Bundle: org.junit,
diff --git a/org.eclipse.jdt.apt.pluggable.tests/plugin.xml b/org.eclipse.jdt.apt.pluggable.tests/plugin.xml
index 3fb6eb8c8a..22466f4c7e 100644
--- a/org.eclipse.jdt.apt.pluggable.tests/plugin.xml
+++ b/org.eclipse.jdt.apt.pluggable.tests/plugin.xml
@@ -9,6 +9,7 @@
Contributors:
IBM Corporation - initial API and implementation
+ Fabian Steeg <steeg@hbz-nrw.de> - Pass automatically provided options to Java 6 processors - https://bugs.eclipse.org/341298
-->
<plugin>
@@ -52,6 +53,9 @@
<java6processor
class="org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug510118Processor">
</java6processor>
+ <java6processor
+ class="org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug341298Processor">
+ </java6processor>
</java6processors>
</extension>
</plugin>
diff --git a/org.eclipse.jdt.apt.pluggable.tests/pom.xml b/org.eclipse.jdt.apt.pluggable.tests/pom.xml
index 63fafd14bd..0d83678f46 100644
--- a/org.eclipse.jdt.apt.pluggable.tests/pom.xml
+++ b/org.eclipse.jdt.apt.pluggable.tests/pom.xml
@@ -20,7 +20,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.apt.pluggable.tests</artifactId>
- <version>3.4.100-SNAPSHOT</version>
+ <version>3.4.200-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
<testSuite>${project.artifactId}</testSuite>
diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java
index 848e55f29a..eff108024d 100644
--- a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java
+++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java
@@ -7,8 +7,8 @@
*
* Contributors:
* eclipse@cafewalter.com - initial API and implementation
- * Harry Terkelsen <het@google.com> - Contribution for
- * Bug 437414 - Annotation processing is broken when build is batched
+ * Harry Terkelsen <het@google.com> - Contribution for Bug 437414 - Annotation processing is broken when build is batched
+ * Fabian Steeg <steeg@hbz-nrw.de> - Pass automatically provided options to Java 6 processors - https://bugs.eclipse.org/341298
*******************************************************************************/
package org.eclipse.jdt.apt.pluggable.tests;
@@ -18,6 +18,7 @@ import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.apt.core.util.AptConfig;
+import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug341298Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug468893Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug510118Processor;
import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.BugsProc;
@@ -351,7 +352,8 @@ public class BuilderTests extends TestBase
}
}
- public void testBugbug510118() throws Throwable {
+
+ public void testBug510118() throws Throwable {
ProcessorTestStatus.reset();
IJavaProject jproj = createJavaProject(_projectName);
disableJava5Factories(jproj);
@@ -363,4 +365,24 @@ public class BuilderTests extends TestBase
expectingNoProblems();
assertTrue("Incorrect status received from annotation processor", Bug510118Processor.status());
}
+
+ public void testBug341298() throws Throwable {
+ ProcessorTestStatus.reset();
+ IJavaProject project = createJavaProject(_projectName);
+ IPath root = project.getProject().getFullPath().append("src");
+ env.addClass(root, "test341298", "Annotated",
+ "package test341298;\n" +
+ "@Annotation public class Annotated {}"
+ );
+ env.addClass(root, "test341298", "Annotation",
+ "package test341298;\n" +
+ "public @interface Annotation {}"
+ );
+ AptConfig.addProcessorOption(project, "classpath", "%classpath%");
+ AptConfig.addProcessorOption(project, "sourcepath", "%sourcepath%");
+ AptConfig.addProcessorOption(project, "phase", "%test341298%");
+ AptConfig.setEnabled(project, true);
+ fullBuild();
+ assertTrue("Processor should be able to compile with passed options", Bug341298Processor.success());
+ }
}
diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Bug341298Processor.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Bug341298Processor.java
new file mode 100644
index 0000000000..8ec5f84c35
--- /dev/null
+++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Bug341298Processor.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabian Steeg and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabian Steeg <steeg@hbz-nrw.de> - Pass automatically provided options to Java 6 processors - https://bugs.eclipse.org/341298
+ *******************************************************************************/
+
+package org.eclipse.jdt.apt.pluggable.tests.processors.buildertester;
+
+import static java.util.stream.Collectors.toList;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+@SupportedAnnotationTypes("test341298.Annotation")
+public class Bug341298Processor extends AbstractProcessor {
+
+ private static boolean success = false;
+
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment rndEnv) {
+ TypeElement typeElement = processingEnv.getElementUtils().getTypeElement("test341298.Annotation");
+ if (!rndEnv.getElementsAnnotatedWith(typeElement).isEmpty()) {
+ try {
+ success = compile(writeSourceFile(), processingEnv.getOptions());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return true;
+ }
+
+ private JavaFileObject writeSourceFile() throws IOException {
+ JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile("test341298.Test");
+ PrintWriter pw = new PrintWriter(sourceFile.openOutputStream());
+ pw.println("package test341298;");
+ pw.println("import org.eclipse.jdt.apt.pluggable.tests.annotations.*;"); // classpath dependency
+ pw.write("class Test { Annotated annotated() { return null; } }"); // sourcepath dependency
+ pw.close();
+ return sourceFile;
+ }
+
+ private Boolean compile(JavaFileObject sourceFile, Map<String, String> opts) throws IOException {
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+
+ List<String> options = opts.entrySet().stream().filter((e) -> !e.getKey().equals("phase"))
+ .flatMap((e) -> Arrays.asList("-" + e.getKey(), e.getValue()).stream()).collect(toList());
+
+ Iterable<? extends JavaFileObject> objects = fileManager
+ .getJavaFileObjectsFromFiles(Arrays.asList(new File(sourceFile.toUri())));
+
+ Boolean success = compiler.getTask(null, fileManager, null, options, null, objects).call();
+ fileManager.close();
+ return success;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latest();
+ }
+
+ public static boolean success() {
+ return success;
+ }
+}
diff --git a/org.eclipse.jdt.apt.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.apt.tests/META-INF/MANIFEST.MF
index b73d6eb98c..ca8c494f5f 100644
--- a/org.eclipse.jdt.apt.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.apt.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.apt.tests; singleton:=true
-Bundle-Version: 3.4.0.qualifier
+Bundle-Version: 3.4.100.qualifier
Bundle-ClassPath: apt.jar,
aptext.jar,
.
diff --git a/org.eclipse.jdt.apt.tests/pom.xml b/org.eclipse.jdt.apt.tests/pom.xml
index f996a84eb5..7f31d1eb73 100644
--- a/org.eclipse.jdt.apt.tests/pom.xml
+++ b/org.eclipse.jdt.apt.tests/pom.xml
@@ -20,7 +20,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.apt.tests</artifactId>
- <version>3.4.0-SNAPSHOT</version>
+ <version>3.4.100-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
<testSuite>${project.artifactId}</testSuite>
diff --git a/org.eclipse.jdt.apt.tests/src-annotations/org/eclipse/jdt/apt/tests/annotations/apitest/APIAnnotationProcessorFactory.java b/org.eclipse.jdt.apt.tests/src-annotations/org/eclipse/jdt/apt/tests/annotations/apitest/APIAnnotationProcessorFactory.java
index 0ff313140a..53f08a4be1 100644
--- a/org.eclipse.jdt.apt.tests/src-annotations/org/eclipse/jdt/apt/tests/annotations/apitest/APIAnnotationProcessorFactory.java
+++ b/org.eclipse.jdt.apt.tests/src-annotations/org/eclipse/jdt/apt/tests/annotations/apitest/APIAnnotationProcessorFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 BEA Systems, Inc.
+ * Copyright (c) 2005, 2017 BEA Systems, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -173,7 +173,7 @@ public class APIAnnotationProcessorFactory extends BaseFactory {
*/
private AnnotationMirror findMirror(Declaration decl, AnnotationTypeDeclaration at) {
for (AnnotationMirror mirror : decl.getAnnotationMirrors()) {
- if (mirror.getAnnotationType().equals(at)) {
+ if (mirror.getAnnotationType().getDeclaration().equals(at)) {
return mirror;
}
}
diff --git a/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/FactoryPathTests.java b/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/FactoryPathTests.java
index b92a4feca1..5ce02a803c 100644
--- a/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/FactoryPathTests.java
+++ b/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/FactoryPathTests.java
@@ -108,7 +108,7 @@ public class FactoryPathTests extends TestCase {
// Will throw an exception if the newly added jar isn't first
WkspJarFactoryContainer fc = (WkspJarFactoryContainer) path.getAllContainers().keySet().iterator().next();
- assertTrue(fc.getJarFile().toString().endsWith(toAdd.toString()));
+ assertTrue(fc.getJarFile().toString().endsWith(toAdd.toOSString()));
path.removeWkspJar(toAdd);
diff --git a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AdvancedFactoryPathOptionsDialog.java b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AdvancedFactoryPathOptionsDialog.java
index f99b848286..757e25f7c2 100644
--- a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AdvancedFactoryPathOptionsDialog.java
+++ b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AdvancedFactoryPathOptionsDialog.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 BEA Systems, Inc.
+ * Copyright (c) 2005, 2007 BEA Systems, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* wharley@bea.com - initial API and implementation
+ * Fabian Steeg <steeg@hbz-nrw.de> - Update APT options documentation - https://bugs.eclipse.org/515329
*******************************************************************************/
package org.eclipse.jdt.apt.ui.internal.preferences;
@@ -21,7 +22,7 @@ import org.eclipse.jdt.apt.ui.internal.util.IAptHelpContextIds;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
-import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
@@ -38,7 +39,7 @@ import org.eclipse.ui.PlatformUI;
* be configured, and which may require deeper-than-usual
* understanding of the annotation processing architecture.
*/
-public class AdvancedFactoryPathOptionsDialog extends Dialog {
+public class AdvancedFactoryPathOptionsDialog extends StatusDialog {
private final static int LIST_WIDTH= 70; // width (in chars) of factory list
private final static int LIST_HEIGHT= 10; // number of lines in factory list
diff --git a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AptConfigurationBlock.java b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AptConfigurationBlock.java
index cf210f3dce..4824e3dbb4 100644
--- a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AptConfigurationBlock.java
+++ b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/AptConfigurationBlock.java
@@ -8,6 +8,7 @@
* Contributors:
* BEA Systems Inc. - initial API and implementation
* IBM Corporation - fix deprecation warnings
+ * Fabian Steeg <steeg@hbz-nrw.de> - Update APT options documentation - https://bugs.eclipse.org/515329
*******************************************************************************/
package org.eclipse.jdt.apt.ui.internal.preferences;
@@ -30,7 +31,6 @@ import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
@@ -325,13 +325,6 @@ public class AptConfigurationBlock extends BaseConfigurationBlock {
reconcileGD.horizontalIndent = indent;
fReconcileEnabledField.getSelectionButton(parent).setLayoutData(reconcileGD);
- Label description= new Label(fBlockControl, SWT.WRAP);
- description.setText(Messages.AptConfigurationBlock_classpathAddedAutomaticallyNote);
- GridData gdLabel= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
- gdLabel.horizontalSpan= 2;
- gdLabel.widthHint= fPixelConverter.convertWidthInCharsToPixels(60);
- description.setLayoutData(gdLabel);
-
Dialog.applyDialogFont(fBlockControl);
validateSettings(null, null, null);
diff --git a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/Messages.java b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/Messages.java
index 73208ff0bf..c4bf99358e 100644
--- a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/Messages.java
+++ b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/Messages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 BEA Systems, Inc.
+ * Copyright (c) 2005, 2007 BEA Systems, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* jgarms@bea.com - initial API and implementation
+ * Fabian Steeg <steeg@hbz-nrw.de> - Update APT options documentation - https://bugs.eclipse.org/515329
*
*******************************************************************************/
package org.eclipse.jdt.apt.ui.internal.preferences;
@@ -64,8 +65,6 @@ public class Messages extends NLS {
public static String BaseConfigurationBlock_rebuildRequired;
- public static String AptConfigurationBlock_classpathAddedAutomaticallyNote;
-
public static String AptConfigurationBlock_warningIgnoredOptions;
public static String FactoryPathConfigurationBlock_unableToSaveFactorypath_title;
diff --git a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/messages.properties b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/messages.properties
index 3379f7d517..d07f4d9523 100644
--- a/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/messages.properties
+++ b/org.eclipse.jdt.apt.ui/src/org/eclipse/jdt/apt/ui/internal/preferences/messages.properties
@@ -15,7 +15,6 @@ AptConfigurationBlock_generatedSrcDir=&Generated source directory:
AptConfigurationBlock_warningIgnoredOptions=An automatically set option will override this option
AptConfigurationBlock_warningContentsMayBeDeleted=Contents of generated source directory may be deleted
AptConfigurationBlock_enableReconcileProcessing=Enable processing in edito&r
-AptConfigurationBlock_classpathAddedAutomaticallyNote=Note: options such as \"-classpath\" and \"-sourcepath\" are automatically passed to all processors, with values corresponding to the project's Java settings.
AptConfigurationBlock_genSrcDirMustBeValidRelativePath=Generated source directory must be a valid relative path
AptConfigurationBlock_options=Processor options (-Akey=value):
AptPreferencePage_preferences=Specify the default annotation processor settings for new projects:
diff --git a/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF
index e078971bf2..31d60e1a90 100644
--- a/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.compiler.apt.tests;singleton:=true
-Bundle-Version: 1.1.100.qualifier
+Bundle-Version: 1.1.200.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/org.eclipse.jdt.compiler.apt.tests/pom.xml b/org.eclipse.jdt.compiler.apt.tests/pom.xml
index a7132631bd..8207b4da7b 100644
--- a/org.eclipse.jdt.compiler.apt.tests/pom.xml
+++ b/org.eclipse.jdt.compiler.apt.tests/pom.xml
@@ -20,7 +20,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.compiler.apt.tests</artifactId>
- <version>1.1.100-SNAPSHOT</version>
+ <version>1.1.200-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
diff --git a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java
index 3d5859fb0f..a0fd12eb81 100644
--- a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java
+++ b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java
@@ -20,6 +20,7 @@ import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashSet;
@@ -211,4 +212,15 @@ public class FileManagerTests extends TestCase {
fileManager.close();
}
+ public void testBug514121_getClassloader_close() throws Exception {
+ EclipseFileManager fileManager = new EclipseFileManager(Locale.getDefault(), Charset.defaultCharset());
+ List<File> classpath = new ArrayList<>();
+ classpath.add(new File(BatchTestUtils.getPluginDirectoryPath(), "resources/targets/filemanager/dependency.zip"));
+ fileManager.setLocation(javax.tools.StandardLocation.ANNOTATION_PROCESSOR_PATH, classpath);
+ URLClassLoader loader = (URLClassLoader) fileManager
+ .getClassLoader(javax.tools.StandardLocation.ANNOTATION_PROCESSOR_PATH);
+ assertNotNull(loader.findResource("jarresource.txt")); // sanity check
+ fileManager.close();
+ assertNull(loader.findResource("jarresource.txt")); // assert the classloader is closed
+ }
}
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
index d689a24c02..4f287645bf 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
@@ -66,6 +66,7 @@ public class EclipseFileManager implements StandardJavaFileManager {
Charset charset;
Locale locale;
Map<String, Iterable<? extends File>> locations;
+ final Map<Location, URLClassLoader> classloaders;
int flags;
public ResourceBundle bundle;
@@ -73,6 +74,7 @@ public class EclipseFileManager implements StandardJavaFileManager {
this.locale = locale == null ? Locale.getDefault() : locale;
this.charset = charset == null ? Charset.defaultCharset() : charset;
this.locations = new HashMap<>();
+ this.classloaders = new HashMap<>();
this.archivesCache = new HashMap<>();
try {
this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath());
@@ -99,6 +101,10 @@ public class EclipseFileManager implements StandardJavaFileManager {
archive.close();
}
this.archivesCache.clear();
+ for (URLClassLoader cl : this.classloaders.values()) {
+ cl.close();
+ }
+ this.classloaders.clear();
}
private void collectAllMatchingFiles(File file, String normalizedPackageName, Set<Kind> kinds, boolean recurse, ArrayList<JavaFileObject> collector) {
@@ -222,17 +228,22 @@ public class EclipseFileManager implements StandardJavaFileManager {
// location is unknown
return null;
}
- ArrayList<URL> allURLs = new ArrayList<>();
- for (File f : files) {
- try {
- allURLs.add(f.toURI().toURL());
- } catch (MalformedURLException e) {
- // the url is malformed - this should not happen
- throw new RuntimeException(e);
+ URLClassLoader cl = this.classloaders.get(location);
+ if (cl == null) {
+ ArrayList<URL> allURLs = new ArrayList<>();
+ for (File f : files) {
+ try {
+ allURLs.add(f.toURI().toURL());
+ } catch (MalformedURLException e) {
+ // the url is malformed - this should not happen
+ throw new RuntimeException(e);
+ }
}
+ URL[] result = new URL[allURLs.size()];
+ cl = new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader());
+ this.classloaders.put(location, cl);
}
- URL[] result = new URL[allURLs.size()];
- return new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader());
+ return cl;
}
private Iterable<? extends File> getPathsFrom(String path) {
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
index 6517830cc9..98d5afefa2 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2015 BEA Systems, Inc.
+ * Copyright (c) 2006, 2017 BEA Systems, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,6 +8,7 @@
* Contributors:
* wharley@bea.com - initial API and implementation
* (originally in org.eclipse.jdt.apt.core)
+ * IBM Corporation - Bug 513790
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.apt.util;
@@ -311,7 +312,7 @@ public class ManyToMany<T1, T2> {
* @see #keyHasOtherValues(Object, Object)
*/
public synchronized boolean valueHasOtherKeys(T2 value, T1 key) {
- Set<T1> keys = _reverse.get(key);
+ Set<T1> keys = _reverse.get(value);
if (keys == null)
return false;
int size = keys.size();
diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java
index 3fb1122b8b..eca44dd094 100644
--- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java
+++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java
@@ -66,6 +66,7 @@ public class EclipseFileManager implements StandardJavaFileManager {
Charset charset;
Locale locale;
Map<String, Iterable<? extends File>> locations;
+ final Map<Location, URLClassLoader> classloaders;
int flags;
public ResourceBundle bundle;
@@ -73,6 +74,7 @@ public class EclipseFileManager implements StandardJavaFileManager {
this.locale = locale == null ? Locale.getDefault() : locale;
this.charset = charset == null ? Charset.defaultCharset() : charset;
this.locations = new HashMap<>();
+ this.classloaders = new HashMap<>();
this.archivesCache = new HashMap<>();
try {
this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath());
@@ -99,6 +101,10 @@ public class EclipseFileManager implements StandardJavaFileManager {
archive.close();
}
this.archivesCache.clear();
+ for (URLClassLoader cl : this.classloaders.values()) {
+ cl.close();
+ }
+ this.classloaders.clear();
}
private void collectAllMatchingFiles(File file, String normalizedPackageName, Set<Kind> kinds, boolean recurse, ArrayList<JavaFileObject> collector) {
@@ -224,17 +230,22 @@ public class EclipseFileManager implements StandardJavaFileManager {
// location is unknown
return null;
}
- ArrayList<URL> allURLs = new ArrayList<>();
- for (File f : files) {
- try {
- allURLs.add(f.toURI().toURL());
- } catch (MalformedURLException e) {
- // the url is malformed - this should not happen
- throw new RuntimeException(e);
+ URLClassLoader cl = this.classloaders.get(location);
+ if (cl == null) {
+ ArrayList<URL> allURLs = new ArrayList<>();
+ for (File f : files) {
+ try {
+ allURLs.add(f.toURI().toURL());
+ } catch (MalformedURLException e) {
+ // the url is malformed - this should not happen
+ throw new RuntimeException(e);
+ }
}
+ URL[] result = new URL[allURLs.size()];
+ cl = new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader());
+ this.classloaders.put(location, cl);
}
- URL[] result = new URL[allURLs.size()];
- return new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader());
+ return cl;
}
private Iterable<? extends File> getPathsFrom(String path) {
diff --git a/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF
index 3412b6cbd0..ee2afc6c69 100644
--- a/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.core.tests.builder; singleton:=true
-Bundle-Version: 3.10.4.qualifier
+Bundle-Version: 3.10.5.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.jdt.core.tests.builder
diff --git a/org.eclipse.jdt.core.tests.builder/pom.xml b/org.eclipse.jdt.core.tests.builder/pom.xml
index 5e33c6b8d5..500a9baef1 100644
--- a/org.eclipse.jdt.core.tests.builder/pom.xml
+++ b/org.eclipse.jdt.core.tests.builder/pom.xml
@@ -19,7 +19,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core.tests.builder</artifactId>
- <version>3.10.4-SNAPSHOT</version>
+ <version>3.10.5-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParticipantBuildTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParticipantBuildTests.java
index 3da81634a0..5a448b699b 100644
--- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParticipantBuildTests.java
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/ParticipantBuildTests.java
@@ -432,9 +432,21 @@ public class ParticipantBuildTests extends BuilderTests {
AbstractTypeDeclaration typeDecl = (AbstractTypeDeclaration) types.get(t);
ITypeBinding typeBinding = typeDecl.resolveBinding();
if (typeBinding == null) continue;
- typeBinding = typeBinding.getAnnotations()[0].getAnnotationType();
- IAnnotationBinding targetValue = typeBinding.getAnnotations()[0];
- IMethodBinding method = targetValue.getDeclaredMemberValuePairs()[0].getMethodBinding();
+ IAnnotationBinding[] annotations = typeBinding.getAnnotations();
+ if (annotations == null || annotations.length == 0) {
+ throw new IllegalStateException(
+ "Expected at least one annotation in binding " + typeBinding);
+ }
+ IAnnotationBinding targetValue = annotations[0];
+ typeBinding = targetValue.getAnnotationType();
+
+ IMemberValuePairBinding[] pairs = targetValue.getAllMemberValuePairs();
+ if (pairs == null || pairs.length == 0) {
+ throw new IllegalStateException(
+ "Expected at least one member value pair in " + targetValue
+ + ", binding was: " + typeBinding);
+ }
+ IMethodBinding method = pairs[0].getMethodBinding();
if (!"value".equals(method.getName()))
problems.add(new ParticipantProblem("method " + method.getName() + " not found", file.getName()));
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index a2dba715b6..5da04c55b7 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -1132,7 +1132,7 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("lambdaSignatureMismatched", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("IllegalArrayOfUnionType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("IllegalArrayTypeInIntersectionCast", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
- expectedProblemAttributes.put("ProblemNotAnalysed", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
+ expectedProblemAttributes.put("ProblemNotAnalysed", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE));
StringBuffer failures = new StringBuffer();
StringBuffer correctResult = new StringBuffer(70000);
Field[] fields = (iProblemClass = IProblem.class).getFields();
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index 633a8af025..68d3f69b33 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -19771,11 +19771,7 @@ public void test0617() {
"1. ERROR in X.java (at line 9)\n" +
" String s = foo(l1, l2);\n" +
" ^^^^^^^^^^^\n" +
- (this.complianceLevel < ClassFileConstants.JDK1_8 ?
- "Type mismatch: cannot convert from List<capture#2-of ? extends Object&Serializable&Comparable<?>> to String\n"
- :
- "Type mismatch: cannot convert from List<capture#3-of ? extends Object&Serializable&Comparable<?>> to String\n"
- ) +
+ "Type mismatch: cannot convert from List<capture#2-of ? extends Object&Serializable&Comparable<?>> to String\n" +
"----------\n");
}
// check capture for conditional operator
@@ -19807,7 +19803,7 @@ public void test0617() {
"1. ERROR in X.java (at line 10)\n" +
" String s = l1 != null ? foo(l1, l2) : l3;\n" +
" ^^^^^^^^^^^\n" +
- "Type mismatch: cannot convert from List<capture#3-of ? extends Number&Comparable<?>> to String\n" +
+ "Type mismatch: cannot convert from List<capture#2-of ? extends Number&Comparable<?>> to String\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=92556
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
index 3a7c006723..1a014e7b42 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
@@ -6053,5 +6053,77 @@ public void testBug469297() {
"----------\n");
}
}
+public void testBug508799() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_RAW_TYPE_REFERENCE, JavaCore.IGNORE);
+ runConformTest(
+ new String[] {
+ "test/A.java",
+ "package test;\n" +
+ "\n" +
+ "public interface A<T extends Iterable> {\n" +
+ " void a();\n" +
+ "}\n" +
+ "",
+ "test/B1.java",
+ "package test;\n" +
+ "\n" +
+ "public interface B1 extends A<Iterable> {\n" +
+ " void b1();\n" +
+ "}\n" +
+ "",
+ "test/B2.java",
+ "package test;\n" +
+ "\n" +
+ "public interface B2 extends A<Iterable> {\n" +
+ " void b2();\n" +
+ "}\n" +
+ "",
+ },
+ customOptions
+ );
+ runConformTest(false,
+ new String[] {
+ "test/C.java",
+ "package test;\n" +
+ "\n" +
+ "public class C implements B1, B2 {\n" +
+ " public void a() {\n" +
+ " }\n" +
+ "\n" +
+ " public void b1() {\n" +
+ " }\n" +
+ "\n" +
+ " public void b2() {\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ }, null, customOptions, "", "", "", null
+ );
+}
+public void testBug515614() {
+ runConformTest(
+ new String[] {
+ "test/Test.java",
+ "package test;\n" +
+ "\n" +
+ "abstract class Generic<E> {\n" +
+ " interface NestedInterface {\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "abstract class X<V> {\n" +
+ " public static <W> X<W> create(Class<W> vclass) {\n" +
+ " return vclass == null ? null : null;\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " X<Generic.NestedInterface[]> x = X.create(Generic.NestedInterface[].class);\n" +
+ "}\n" +
+ "",
+ }
+ );
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
index 3687bf91d0..c7f034725c 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
@@ -8020,4 +8020,218 @@ public void testBug508834_comment0() {
"}\n"
});
}
+ public void testBug506021() {
+ runConformTest(
+ new String[] {
+ "test/__.java",
+ "package test;\n" +
+ "\n" +
+ "interface Result {}\n" +
+ "\n" +
+ "interface Property<V> {}\n" +
+ "\n" +
+ "interface GraphTraversal<E> {}\n" +
+ "\n" +
+ "public class __ {\n" +
+ " public static <E> GraphTraversal<? extends Property<E>> properties2() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static GraphTraversal<? extends Property<Result>> properties() {\n" +
+ " return properties2();\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ });
+ }
+
+ public void testBug506022() {
+ // extracted from problem compiling org.apache.tinkerpop.gremlin.giraph.structure.io.GiraphVertexOutputFormat
+ // changing the return type of getClass to Class<U> fixes the problem
+ runConformTest(
+ new String[] {
+ "test2/Test2.java",
+ "package test2;\n" +
+ "\n" +
+ "abstract class OutputFormat {\n" +
+ " public abstract int getOutputCommitter();\n" +
+ "}\n" +
+ "\n" +
+ "public abstract class Test2 {\n" +
+ " public static <T> T newInstance(Class<T> theClass) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "\n" +
+ " abstract <U> Class<? extends U> getClass(Class<U> xface);\n" +
+ "\n" +
+ " int f() {\n" +
+ " return newInstance(getClass(OutputFormat.class)).getOutputCommitter();\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ }
+ );
+ }
+
+ public void testBug506022b() {
+ // extracted from a problem in org.apache.tinkerpop.gremlin.process.computer.util.ComputerGraph
+ // replacing this.properties() by this.<I>properties() fixes the problem
+ runNegativeTest(
+ new String[] {
+ "test/Test.java",
+ "package test;\n" +
+ "\n" +
+ "interface Iterator<A> {\n" +
+ "}\n" +
+ "\n" +
+ "interface Function<B, C> {\n" +
+ " C applyTo(B b);\n" +
+ "}\n" +
+ "\n" +
+ "interface Property<D> {\n" +
+ "}\n" +
+ "\n" +
+ "class ComputerProperty<E> implements Property<E> {\n" +
+ " public ComputerProperty(final Property<E> property) {\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "public abstract class Test {\n" +
+ " public abstract <F, G> Iterator<G> map(final Iterator<F> iterator, final Function<F, G> function);\n" +
+ "\n" +
+ " public abstract <H> Iterator<? extends Property<H>> properties();\n" +
+ "\n" +
+ " public <I> Iterator<Property<I>> test() {\n" +
+ " return map(this.properties(), property -> new ComputerProperty(property));\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ "----------\n" +
+ "1. WARNING in test\\Test.java (at line 24)\n" +
+ " return map(this.properties(), property -> new ComputerProperty(property));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: The constructor ComputerProperty(Property) belongs to the raw type ComputerProperty. References to generic type ComputerProperty<E> should be parameterized\n" +
+ "----------\n" +
+ "2. WARNING in test\\Test.java (at line 24)\n" +
+ " return map(this.properties(), property -> new ComputerProperty(property));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: The expression of type ComputerProperty needs unchecked conversion to conform to Property<I>\n" +
+ "----------\n" +
+ "3. WARNING in test\\Test.java (at line 24)\n" +
+ " return map(this.properties(), property -> new ComputerProperty(property));\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "ComputerProperty is a raw type. References to generic type ComputerProperty<E> should be parameterized\n" +
+ "----------\n"
+ );
+ }
+ public void testBug514884() {
+ runConformTest(
+ new String[] {
+ "Minimal.java",
+ "import java.io.*;\n" +
+ "public class Minimal {\n" +
+ " public void iCrash() throws IOException {\n" +
+ " try (Closeable o = consumes(sneaky()::withVarargs)) {\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " private Minimal sneaky() { return this; }\n" +
+ "\n" +
+ " private void withVarargs(String... test) {}\n" +
+ "\n" +
+ " private Closeable consumes(Runnable r) { return null; }\n" +
+ "}\n"
+ });
+ }
+
+ public void testBug494733_comment0() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " List<Integer> integerList = new ArrayList<>();\n" +
+ " Set<List<Number>> numbetListSet = Collections.singleton(toWildcardGeneric(integerList));\n" +
+ " numbetListSet.iterator().next().add(new Float(1.0));\n" +
+ " Integer i = integerList.get(0); // Throws ClassCastException\n" +
+ " }\n" +
+ " \n" +
+ " static <T> List<? extends T> toWildcardGeneric(List<T> l) {\n" +
+ " return l;\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " Set<List<Number>> numbetListSet = Collections.singleton(toWildcardGeneric(integerList));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type mismatch: cannot convert from Set<List<Integer>> to Set<List<Number>>\n" +
+ "----------\n");
+ }
+
+ public void testBug494733_comment1() {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "public class X {\n" +
+ "public static void main(String[] args) {\n" +
+ " List<Integer> integerList = new ArrayList<>();\n" +
+ " List<Object> objectList = id(toWildcardGeneric(integerList));\n" +
+ " objectList.add(\"Woo?\");\n" +
+ " Integer i = integerList.get(0);\n" +
+ "}\n" +
+ "\n" +
+ "static <T> T id(T o) {\n" +
+ " return o;\n" +
+ "}\n" +
+ "\n" +
+ "static <T> List<? extends T> toWildcardGeneric(List<T> l) {\n" +
+ " return l;\n" +
+ "}\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " List<Object> objectList = id(toWildcardGeneric(integerList));\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Type mismatch: cannot convert from List<Integer> to List<Object>\n" +
+ "----------\n");
+ }
+
+ public void test483952_bare () {
+ runNegativeTest(
+ new String[] {
+ "test/Test.java",
+ "package test;\n" +
+ "import java.util.function.Function;\n" +
+ "public class Test {\n" +
+ " void test1() {\n" +
+ " Function function = x -> x;\n" +
+ " String [] z = test2(function, \"\");\n" +
+ " }\n" +
+ " <T> T [] test2(Function<T, T> function, T t) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}"
+
+ },
+ "----------\n" +
+ "1. WARNING in test\\Test.java (at line 5)\n" +
+ " Function function = x -> x;\n" +
+ " ^^^^^^^^\n" +
+ "Function is a raw type. References to generic type Function<T,R> should be parameterized\n" +
+ "----------\n" +
+ "2. WARNING in test\\Test.java (at line 6)\n" +
+ " String [] z = test2(function, \"\");\n" +
+ " ^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: Unchecked invocation test2(Function, String) of the generic method test2(Function<T,T>, T) of type Test\n" +
+ "----------\n" +
+ "3. WARNING in test\\Test.java (at line 6)\n" +
+ " String [] z = test2(function, \"\");\n" +
+ " ^^^^^^^^\n" +
+ "Type safety: The expression of type Function needs unchecked conversion to conform to Function<String,String>\n" +
+ "----------\n");
+ }
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
index 96ecf3ef76..9025cea450 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
@@ -6400,6 +6400,59 @@ public void test509804() {
},
"private static java.lang.Object Test.lambda$1()");
}
+public void testBug514105() {
+ runConformTest(
+ new String[] {
+ "FunctionalInterfaceBug.java",
+ "import java.util.function.Function;\n" +
+ "import java.util.function.UnaryOperator;\n" +
+ "\n" +
+ "@FunctionalInterface\n" +
+ "interface BaseFunction<S, T> extends Function<S, T> {\n" +
+ "\n" +
+ " T foo(final S s);\n" +
+ "\n" +
+ " default T apply(final S s) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "@FunctionalInterface\n" +
+ "interface SubFunction<T> extends UnaryOperator<T>, BaseFunction<T, T> {\n" +
+ "}\n" +
+ "public class FunctionalInterfaceBug {}\n"
+ });
+}
+public void testBug515473() {
+ runConformTest(
+ new String[] {
+ "test/LambdaResourceLeak.java",
+ "package test;\n" +
+ "\n" +
+ "class X implements AutoCloseable {\n" +
+ " @Override\n" +
+ " public void close() {\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "interface SAM {\n" +
+ " Object m();\n" +
+ "}\n" +
+ "\n" +
+ "public class LambdaResourceLeak {\n" +
+ " void f() {\n" +
+ " X x1 = new X();\n" +
+ " SAM sam = () -> {\n" +
+ " return \"\";\n" +
+ " };\n" +
+ " sam.m();\n" +
+ " x1.close();\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ }
+ );
+}
public static Class testClass() {
return LambdaExpressionsTest.class;
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
index 997a1304e8..b6a3f616f0 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
@@ -14335,4 +14335,44 @@ public void testBug500673() {
"The type mfa must implement the inherited abstract method mfi.a(Throwable)\n" +
"----------\n");
}
+public void testBug506653() {
+ runConformTest(
+ false, // flushOutputDirectory
+ new String[] {
+ "A.java",
+ " public class A {\n" +
+ " public class B {\n" +
+ " <E extends Object, F extends E> E bar(F x) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " }\n" +
+ " public class C extends B {\n" +
+ " @Override\n" +
+ " public String bar(Object x) {\n" +
+ " return \"Oops\";\n" +
+ " }\n" +
+ " }\n" +
+ " public static void main(String... args) {\n" +
+ " new A().test();\n" +
+ " }\n" +
+ " void test() {\n" +
+ " B b = new C();\n" +
+ " try {\n" +
+ " Integer i = b.bar(1);\n" +
+ " } catch (ClassCastException cce) {\n" +
+ " System.out.print(\"cce\");\n" +
+ " }\n" +
+ " }\n" +
+ " }\n"
+ },
+ "----------\n" +
+ "1. WARNING in A.java (at line 9)\n" +
+ " public String bar(Object x) {\n" +
+ " ^^^^^^\n" +
+ "Type safety: The return type String for bar(Object) from the type A.C needs unchecked conversion to conform to E from the type A.B\n" +
+ "----------\n",
+ "cce",
+ "",
+ JavacTestOptions.DEFAULT);
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
index 6bb9f9dbd5..aa2de45f73 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
@@ -8581,7 +8581,7 @@ public void test428177() {
"5. ERROR in X.java (at line 38)\n" +
" return stream.collect(Collectors.toList()); // NO ERROR\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
- "Type mismatch: cannot convert from List<capture#19-of ? extends String> to Stream<String>\n" +
+ "Type mismatch: cannot convert from List<capture#17-of ? extends String> to Stream<String>\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=428795, - [1.8]Internal compiler error: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.ast.MessageSend.analyseCode
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
index cd55662392..35c595e246 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
@@ -5376,6 +5376,53 @@ public void test_nullable_field_15() {
potNPE_nullable("The field nullable") +
"----------\n");
}
+// access to a nullable field - dereference after check in while loop
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=414761
+public void test_nullable_field_16() {
+ // currently no flow analysis for fields is implemented,
+ // but the direct sequence of null-check + dereference is optionally supported as a special case
+ Map options = getCompilerOptions();
+ options.put(JavaCore.COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS, JavaCore.ENABLED);
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "public class X {\n" +
+ " @Nullable Object prop;\n" +
+ " void testWhileAlone(){\n" +
+ " while(this.prop != null) {\n" +
+ " test(this.prop);\n" +
+ " }\n" +
+ " }\n" +
+ " @Nullable Object other;\n" +
+ " void testTwoFields() {\n" +
+ " boolean b = this.other != null;\n" + // we had funny interaction between analyses of other & prop
+ " while(this.prop != null) {\n" +
+ " test(this.prop);\n" +
+ " }\n" +
+ " }\n" +
+ " void testWhileInIf() {\n" +
+ " if (this.prop != null) {\n" +
+ " while(this.other != null) {\n" +
+ " test(this.prop);\n" + // no longer protected by outer if
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " void test(@NonNull Object param){\n" +
+ " assert param != null;\n" +
+ " }" +
+ "}\n"
+ },
+ options /*customOptions*/,
+ "----------\n" +
+ "1. ERROR in X.java (at line 19)\n" +
+ " test(this.prop);\n" +
+ " ^^^^^^^^^\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8
+ ? "Null type mismatch: required '@NonNull Object' but the provided value is specified as @Nullable\n"
+ : "Null type mismatch (type annotations): required \'@NonNull Object\' but this expression has type \'@Nullable Object\'\n") +
+ "----------\n");
+}
// an enum is declared within the scope of a null-default
// https://bugs.eclipse.org/331649#c61
public void test_enum_field_01() {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
index 2ef44cbb35..8a2379feba 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
@@ -9334,6 +9334,16 @@ public void test483952 () {
" Function function = x -> x;\n" +
" ^^^^^^^^\n" +
"Function is a raw type. References to generic type Function<T,R> should be parameterized\n" +
+ "----------\n" +
+ "2. WARNING in test\\Test.java (at line 7)\n" +
+ " String @Nullable [] z = test2(function, \"\");\n" +
+ " ^^^^^^^^^^^^^^^^^^^\n" +
+ "Type safety: Unchecked invocation test2(Function, String) of the generic method test2(Function<T,T>, T) of type Test\n" +
+ "----------\n" +
+ "3. WARNING in test\\Test.java (at line 7)\n" +
+ " String @Nullable [] z = test2(function, \"\");\n" +
+ " ^^^^^^^^\n" +
+ "Type safety: The expression of type Function needs unchecked conversion to conform to Function<String,String>\n" +
"----------\n");
}
public void test484055() {
@@ -15120,4 +15130,261 @@ public void testBug498084b() {
"----------\n"
);
}
+public void testBug513495() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "test/Test3.java",
+ "package test;\n" +
+ "\n" +
+ "import java.util.function.Function;\n" +
+ "\n" +
+ "import org.eclipse.jdt.annotation.Nullable;\n" +
+ "\n" +
+ "public class Test3 {\n" +
+ " public static void main(String[] args) {\n" +
+ " Function<@Nullable Integer, Object> sam = Integer::intValue;\n" +
+ " sam.apply(null); // <- NullPointerExpection\n" +
+ " Function<Integer, Object> sam2 = Integer::intValue;\n" +
+ " sam2.apply(null); // variation: unchecked, so intentionally no warning reported, but would give NPE too \n" +
+ " }\n" +
+ " void wildcards(Class<?>[] params) { // unchecked case with wildcards\n" +
+ " java.util.Arrays.stream(params).map(Class::getName).toArray(String[]::new);\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. ERROR in test\\Test3.java (at line 9)\n" +
+ " Function<@Nullable Integer, Object> sam = Integer::intValue;\n" +
+ " ^^^^^^^^^^^^^^^^^\n" +
+ "Null type mismatch at parameter 'this': required \'@NonNull Integer\' but provided \'@Nullable Integer\' via method descriptor Function<Integer,Object>.apply(Integer)\n" +
+ "----------\n"
+ );
+}
+public void testBug513855() {
+ runConformTestWithLibs(
+ new String[] {
+ "test1/X.java",
+ "package test1;\n" +
+ "\n" +
+ "import java.math.BigDecimal;\n" +
+ "\n" +
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "\n" +
+ "@NonNullByDefault\n" +
+ "public class X {\n" +
+ " interface Sink<T extends Number> {\n" +
+ " void receive(T t);\n" +
+ " }\n" +
+ "\n" +
+ " interface Source<U extends BigDecimal> {\n" +
+ " U get();\n" +
+ " }\n" +
+ "\n" +
+ " void nn(Object x) {\n" +
+ " }\n" +
+ "\n" +
+ " void f(Source<?> source) {\n" +
+ " nn(source.get());\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ getCompilerOptions(),
+ ""
+ );
+}
+public void testBug513855lambda() {
+ runConformTestWithLibs(
+ new String[] {
+ "test1/Lambda3.java",
+ "package test1;\n" +
+ "\n" +
+ "import java.math.BigDecimal;\n" +
+ "\n" +
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "\n" +
+ "@NonNullByDefault\n" +
+ "public class Lambda3 {\n" +
+ " interface Sink<T extends Number> {\n" +
+ " void receive(T t);\n" +
+ " }\n" +
+ "\n" +
+ " interface Source<U extends BigDecimal> {\n" +
+ " void sendTo(Sink<? super U> c);\n" +
+ " }\n" +
+ "\n" +
+ " void f(Source<?> source) {\n" +
+ " source.sendTo(a -> a.scale());\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ getCompilerOptions(),
+ ""
+ );
+}
+public void testBug514091() {
+ runConformTestWithLibs(
+ new String[] {
+ "test1/SAM.java",
+ "package test1;\n" +
+ "\n" +
+ "@org.eclipse.jdt.annotation.NonNullByDefault\n" +
+ "interface SAM<A> {\n" +
+ " void f(A[] a);\n" +
+ "}\n" +
+ ""
+ },
+ getCompilerOptions(),
+ ""
+ );
+ runConformTestWithLibs(
+ new String[] {
+ "test1/LambdaNN.java",
+ "package test1;\n" +
+ "\n" +
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "\n" +
+ "public class LambdaNN {\n" +
+ " void g1() {\n" +
+ " SAM<? super Number> sam = (Number @NonNull [] a) -> {};\n" +
+ " sam.f(new Number[0]);\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ getCompilerOptions(),
+ ""
+ );
+}
+public void testBug514570() {
+ final Map compilerOptions = getCompilerOptions();
+ compilerOptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
+ runConformTestWithLibs(
+ new String[] {
+ "test/Test.java",
+ "package test;\n" +
+ "\n" +
+ "import java.util.List;\n" +
+ "\n" +
+ "import org.eclipse.jdt.annotation.NonNull;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " /**\n" +
+ " * {@link #bug()}\n" +
+ " */\n" +
+ " <E, T extends List<@NonNull E>> void bug() {\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ compilerOptions,
+ ""
+ );
+}
+public void testBug514977() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "test/Test.java",
+ "package test;\n" +
+ "\n" +
+ "import org.eclipse.jdt.annotation.DefaultLocation;\n" +
+ "import org.eclipse.jdt.annotation.NonNull;\n" +
+ "import org.eclipse.jdt.annotation.NonNullByDefault;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " static void nn(@NonNull Object i) {\n" +
+ " i.hashCode();\n" +
+ " }\n" +
+ "\n" +
+ " static void f(@NonNull Integer @NonNull... args) {\n" +
+ " nn(args);\n" +
+ " for (Integer s : args) {\n" +
+ " nn(s);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " @NonNullByDefault({ DefaultLocation.ARRAY_CONTENTS, DefaultLocation.PARAMETER })\n" +
+ " static void g(Integer... args) {\n" +
+ " nn(args);\n" +
+ " for (Integer s : args) {\n" +
+ " nn(s);\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " public static void main(String[] args) {\n" +
+ " Integer i = args.length == 0 ? null : 1;\n" +
+ " Integer[] array = i == null ? null : new Integer[] {i};\n" +
+ " f(array);\n" +
+ " f(i);\n" +
+ " f(1, i);\n" +
+ " g(array);\n" +
+ " g(i);\n" +
+ " g(1, i);\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. ERROR in test\\Test.java (at line 30)\n" +
+ " f(array);\n" +
+ " ^^^^^\n" +
+ "Null type mismatch: required \'@NonNull Integer @NonNull[]\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "2. ERROR in test\\Test.java (at line 31)\n" +
+ " f(i);\n" +
+ " ^\n" +
+ "Null type mismatch: required \'@NonNull Integer\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "3. ERROR in test\\Test.java (at line 32)\n" +
+ " f(1, i);\n" +
+ " ^\n" +
+ "Null type mismatch: required \'@NonNull Integer\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "4. ERROR in test\\Test.java (at line 33)\n" +
+ " g(array);\n" +
+ " ^^^^^\n" +
+ "Null type mismatch: required \'@NonNull Integer @NonNull[]\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "5. ERROR in test\\Test.java (at line 34)\n" +
+ " g(i);\n" +
+ " ^\n" +
+ "Null type mismatch: required \'@NonNull Integer\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "6. ERROR in test\\Test.java (at line 35)\n" +
+ " g(1, i);\n" +
+ " ^\n" +
+ "Null type mismatch: required \'@NonNull Integer\' but the provided value is inferred as @Nullable\n" +
+ "----------\n"
+ );
+}
+public void testBug515292() {
+ runConformTestWithLibs(
+ new String[] {
+ "test/BoundedByFinal.java",
+ "package test;\n" +
+ "import org.eclipse.jdt.annotation.NonNull;\n" +
+ "import org.eclipse.jdt.annotation.Nullable;\n" +
+ "\n" +
+ "public abstract class BoundedByFinal {\n" +
+ " abstract <T extends @Nullable String> void setSelection(T[] selectedObjects);\n" +
+ "\n" +
+ " abstract @NonNull String @NonNull [] toArray1();\n" +
+ "\n" +
+ " abstract @Nullable String @NonNull [] toArray2();\n" +
+ "\n" +
+ " void test() {\n" +
+ " setSelection(toArray1());\n" +
+ " setSelection(toArray2());\n" +
+ " }\n" +
+ "}\n" +
+ "",
+ },
+ getCompilerOptions(),
+ ""
+ );
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java
index 47ee79b629..29ed4e81c4 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java
@@ -3221,6 +3221,82 @@ public void testBug410218f() {
true/*shouldFlushOutputDirectory*/,
customOptions);
}
+public void testBug514956a() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE, JavaCore.WARNING);
+ customOptions.put(JavaCore.COMPILER_PB_UNNECESSARY_TYPE_CHECK, JavaCore.ERROR);
+ runConformTest(
+ new String[] {
+ "Unlikely.java",
+ "import java.util.Map;\n" +
+ "\n" +
+ "interface MApplicationElement {}\n" +
+ "interface EObject {}\n" +
+ "public class Unlikely {\n" +
+ " void m(Map<MApplicationElement, MApplicationElement> map, EObject key) {\n" +
+ " map.get((MApplicationElement)key);\n" +
+ " }\n" +
+ "}\n"
+ },
+ customOptions);
+}
+public void testBug514956b() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_EQUALS_ARGUMENT_TYPE, JavaCore.WARNING);
+ customOptions.put(JavaCore.COMPILER_PB_UNNECESSARY_TYPE_CHECK, JavaCore.ERROR);
+ runConformTest(
+ new String[] {
+ "Unlikely.java",
+ "interface EObject {}\n" +
+ "public class Unlikely {\n" +
+ " boolean m(EObject key) {\n" +
+ " return this.equals((Unlikely)key);\n" +
+ " }\n" +
+ "}\n"
+ },
+ customOptions);
+}
+public void testBug514956c() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_EQUALS_ARGUMENT_TYPE, JavaCore.WARNING);
+ customOptions.put(JavaCore.COMPILER_PB_UNNECESSARY_TYPE_CHECK, JavaCore.ERROR);
+ runNegativeTest(
+ new String[] {
+ "Unlikely.java",
+ "interface I1 {}\n" +
+ "interface I2 {}\n" +
+ "interface I3 {}\n" +
+ "public class Unlikely implements I1 {\n" +
+ " boolean m1(I1 i1) {\n" +
+ " return i1.equals((I1)this);\n" + // not a downcast
+ " }\n" +
+ " boolean m2(I1 i1, I2 i2) {\n" +
+ " return i1.equals((I3)i2);\n" + // cast doesn't fix a problem
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Unlikely.java (at line 6)\n" +
+ " return i1.equals((I1)this);\n" +
+ " ^^^^^^^^\n" +
+ "Unnecessary cast from Unlikely to I1\n" +
+ "----------\n" +
+ "2. ERROR in Unlikely.java (at line 9)\n" +
+ " return i1.equals((I3)i2);\n" +
+ " ^^^^^^\n" +
+ "Unnecessary cast from I2 to I3\n" +
+ "----------\n" +
+ "3. WARNING in Unlikely.java (at line 9)\n" +
+ " return i1.equals((I3)i2);\n" +
+ " ^^^^^^\n" +
+ "Unlikely argument type for equals(): I3 seems to be unrelated to I1\n" +
+ "----------\n",
+ null, // classlibs
+ false, // flush output dir
+ customOptions);
+}
// mixture of raw type an parametrized type
public void testBug513310() {
if (this.complianceLevel < ClassFileConstants.JDK1_5)
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/CodeSnippetTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/CodeSnippetTest.java
index 65c1daf790..07a0527c0a 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/CodeSnippetTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/CodeSnippetTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -950,4 +950,16 @@ public void testDiamond() {
"new X<>(\"SUCCESS\").foo();\n"}),
"SUCCESS".toCharArray());
}
+/**
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=464656
+ */
+public void testBug464656() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_8) {
+ return;
+ }
+ evaluateWithExpectedDisplayString(buildCharArray(new String[] {
+ "java.util.stream.Stream<String> s = java.util.stream.Stream.of(\"a\",\"b\");\n" +
+ "return s.findFirst();"}),
+ "Optional[a]".toCharArray());
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationSetup.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationSetup.java
index ce13db08eb..c0bfbfb973 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationSetup.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/DebugEvaluationSetup.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@ package org.eclipse.jdt.core.tests.eval;
import java.io.IOException;
import java.io.InputStream;
+import java.net.ServerSocket;
import java.util.List;
import java.util.Map;
@@ -40,124 +41,128 @@ public class DebugEvaluationSetup extends EvaluationSetup {
protected void setUp() {
if (this.context == null) {
// Launch VM in evaluation mode
- int debugPort = Util.getFreePort();
- int evalPort = Util.getFreePort();
- LocalVMLauncher launcher;
- try {
- launcher = LocalVMLauncher.getLauncher();
- launcher.setVMArguments(new String[]{"-verify"});
- launcher.setVMPath(JRE_PATH);
- launcher.setEvalPort(evalPort);
- launcher.setEvalTargetPath(EVAL_DIRECTORY);
- launcher.setDebugPort(debugPort);
- this.launchedVM = launcher.launch();
- } catch (TargetException e) {
- throw new Error(e.getMessage());
- }
-
- // Thread that read the stout of the VM so that the VM doesn't block
- try {
- startReader("VM's stdout reader", this.launchedVM.getInputStream(), System.out);
- } catch (TargetException e) {
- }
-
- // Thread that read the sterr of the VM so that the VM doesn't block
- try {
- startReader("VM's sterr reader", this.launchedVM.getErrorStream(), System.err);
- } catch (TargetException e) {
- }
-
- // Start JDI connection (try 10 times)
- for (int i = 0; i < 10; i++) {
+ try (ServerSocket evalServer = new ServerSocket(0)) {
+ int debugPort = Util.getFreePort();
+ int evalPort = evalServer.getLocalPort();
+ LocalVMLauncher launcher;
try {
- VirtualMachineManager manager = org.eclipse.jdi.Bootstrap.virtualMachineManager();
- List connectors = manager.attachingConnectors();
- if (connectors.size() == 0)
- break;
- AttachingConnector connector = (AttachingConnector)connectors.get(0);
- Map args = connector.defaultArguments();
- Connector.Argument argument = (Connector.Argument)args.get("port");
- if (argument != null) {
- argument.setValue(String.valueOf(debugPort));
- }
- argument = (Connector.Argument)args.get("hostname");
- if (argument != null) {
- argument.setValue(launcher.getTargetAddress());
- }
- argument = (Connector.Argument)args.get("timeout");
- if (argument != null) {
- argument.setValue("10000");
- }
- this.vm = connector.attach(args);
-
- // workaround pb with some VMs
- this.vm.resume();
-
- break;
- } catch (IllegalConnectorArgumentsException e) {
- e.printStackTrace();
- try {
- System.out.println("Could not contact the VM at " + launcher.getTargetAddress() + ":" + debugPort + ". Retrying...");
- Thread.sleep(100);
- } catch (InterruptedException e2) {
- }
- } catch (IOException e) {
- e.printStackTrace();
- try {
- System.out.println("Could not contact the VM at " + launcher.getTargetAddress() + ":" + debugPort + ". Retrying...");
- Thread.sleep(100);
- } catch (InterruptedException e2) {
- }
+ launcher = LocalVMLauncher.getLauncher();
+ launcher.setVMArguments(new String[]{"-verify"});
+ launcher.setVMPath(JRE_PATH);
+ launcher.setEvalPort(evalPort);
+ launcher.setEvalTargetPath(EVAL_DIRECTORY);
+ launcher.setDebugPort(debugPort);
+ this.launchedVM = launcher.launch();
+ } catch (TargetException e) {
+ throw new Error(e.getMessage());
}
- }
- if (this.vm == null) {
- if (this.launchedVM != null) {
- // If the VM is not running, output error stream
+
+ // Thread that read the stout of the VM so that the VM doesn't block
+ try {
+ startReader("VM's stdout reader", this.launchedVM.getInputStream(), System.out);
+ } catch (TargetException e) {
+ }
+
+ // Thread that read the sterr of the VM so that the VM doesn't block
+ try {
+ startReader("VM's sterr reader", this.launchedVM.getErrorStream(), System.err);
+ } catch (TargetException e) {
+ }
+
+ // Start JDI connection (try 10 times)
+ for (int i = 0; i < 10; i++) {
try {
- if (!this.launchedVM.isRunning()) {
- InputStream in = this.launchedVM.getErrorStream();
- int read;
- do {
- read = in.read();
- if (read != -1)
- System.out.print((char)read);
- } while (read != -1);
+ VirtualMachineManager manager = org.eclipse.jdi.Bootstrap.virtualMachineManager();
+ List connectors = manager.attachingConnectors();
+ if (connectors.size() == 0)
+ break;
+ AttachingConnector connector = (AttachingConnector)connectors.get(0);
+ Map args = connector.defaultArguments();
+ Connector.Argument argument = (Connector.Argument)args.get("port");
+ if (argument != null) {
+ argument.setValue(String.valueOf(debugPort));
+ }
+ argument = (Connector.Argument)args.get("hostname");
+ if (argument != null) {
+ argument.setValue(launcher.getTargetAddress());
+ }
+ argument = (Connector.Argument)args.get("timeout");
+ if (argument != null) {
+ argument.setValue("10000");
+ }
+ this.vm = connector.attach(args);
+
+ // workaround pb with some VMs
+ this.vm.resume();
+
+ break;
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace();
+ try {
+ System.out.println("Could not contact the VM at " + launcher.getTargetAddress() + ":" + debugPort + ". Retrying...");
+ Thread.sleep(100);
+ } catch (InterruptedException e2) {
}
- } catch (TargetException e) {
} catch (IOException e) {
- }
-
- // Shut it down
- try {
- if (this.target != null) {
- this.target.disconnect(); // Close the socket first so that the OS resource has a chance to be freed.
+ e.printStackTrace();
+ try {
+ System.out.println("Could not contact the VM at " + launcher.getTargetAddress() + ":" + debugPort + ". Retrying...");
+ Thread.sleep(100);
+ } catch (InterruptedException e2) {
}
- int retry = 0;
- while (this.launchedVM.isRunning() && (++retry < 20)) {
- try {
- Thread.sleep(retry * 100);
- } catch (InterruptedException e) {
+ }
+ }
+ if (this.vm == null) {
+ if (this.launchedVM != null) {
+ // If the VM is not running, output error stream
+ try {
+ if (!this.launchedVM.isRunning()) {
+ InputStream in = this.launchedVM.getErrorStream();
+ int read;
+ do {
+ read = in.read();
+ if (read != -1)
+ System.out.print((char)read);
+ } while (read != -1);
}
+ } catch (TargetException e) {
+ } catch (IOException e) {
}
- if (this.launchedVM.isRunning()) {
- this.launchedVM.shutDown();
+
+ // Shut it down
+ try {
+ if (this.target != null) {
+ this.target.disconnect(); // Close the socket first so that the OS resource has a chance to be freed.
+ }
+ int retry = 0;
+ while (this.launchedVM.isRunning() && (++retry < 20)) {
+ try {
+ Thread.sleep(retry * 100);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (this.launchedVM.isRunning()) {
+ this.launchedVM.shutDown();
+ }
+ } catch (TargetException e) {
}
- } catch (TargetException e) {
}
+ System.err.println("Could not contact the VM");
+ return;
}
- System.err.println("Could not contact the VM");
- return;
+
+ // Create context
+ this.context = new EvaluationContext();
+
+ // Create target
+ this.target = new TargetInterface();
+ this.target.connect(evalServer, 30000); // allow 30s max to connect (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=188127)
+
+ // Create name environment
+ this.env = new FileSystem(Util.getJavaClassLibs(), new String[0], null);
+ } catch (IOException e1) {
+ throw new Error("Failed to open socket", e1);
}
-
- // Create context
- this.context = new EvaluationContext();
-
- // Create target
- this.target = new TargetInterface();
- this.target.connect("localhost", evalPort, 30000); // allow 30s max to connect (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=188127)
-
- // Create name environment
- this.env = new FileSystem(Util.getJavaClassLibs(), new String[0], null);
}
super.setUp();
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/EvaluationSetup.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/EvaluationSetup.java
index 69665ba33c..12882d6572 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/EvaluationSetup.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/EvaluationSetup.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,8 +11,10 @@
package org.eclipse.jdt.core.tests.eval;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
+import java.net.ServerSocket;
import org.eclipse.jdt.core.tests.runtime.LocalVirtualMachine;
@@ -41,39 +43,43 @@ public class EvaluationSetup extends CompilerTestSetup {
protected void setUp() {
if (this.context == null) { // non null if called from subclass
- // Launch VM in evaluation mode
- int evalPort = Util.getFreePort();
- try {
- LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
- launcher.setVMPath(JRE_PATH);
- launcher.setEvalPort(evalPort);
- launcher.setEvalTargetPath(EVAL_DIRECTORY);
- this.launchedVM = launcher.launch();
- } catch (TargetException e) {
- throw new Error(e.getMessage());
- }
-
- // Thread that read the stout of the VM so that the VM doesn't block
- try {
- startReader("VM's stdout reader", this.launchedVM.getInputStream(), System.out);
- } catch (TargetException e) {
- }
-
- // Thread that read the sterr of the VM so that the VM doesn't block
- try {
- startReader("VM's sterr reader", this.launchedVM.getErrorStream(), System.err);
- } catch (TargetException e) {
+ try (ServerSocket server = new ServerSocket(0)) {
+ // Launch VM in evaluation mode
+ int evalPort = server.getLocalPort();
+ try {
+ LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
+ launcher.setVMPath(JRE_PATH);
+ launcher.setEvalPort(evalPort);
+ launcher.setEvalTargetPath(EVAL_DIRECTORY);
+ this.launchedVM = launcher.launch();
+ } catch (TargetException e) {
+ throw new Error(e.getMessage());
+ }
+
+ // Thread that read the stout of the VM so that the VM doesn't block
+ try {
+ startReader("VM's stdout reader", this.launchedVM.getInputStream(), System.out);
+ } catch (TargetException e) {
+ }
+
+ // Thread that read the sterr of the VM so that the VM doesn't block
+ try {
+ startReader("VM's sterr reader", this.launchedVM.getErrorStream(), System.err);
+ } catch (TargetException e) {
+ }
+
+ // Create context
+ this.context = new EvaluationContext();
+
+ // Create target
+ this.target = new TargetInterface();
+ this.target.connect(server, 30000); // allow 30s max to connect (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=188127)
+
+ // Create name environment
+ this.env = new FileSystem(Util.getJavaClassLibs(), new String[0], null);
+ } catch (IOException e1) {
+ throw new Error("Failed to open socket", e1);
}
-
- // Create context
- this.context = new EvaluationContext();
-
- // Create target
- this.target = new TargetInterface();
- this.target.connect("localhost", evalPort, 30000); // allow 30s max to connect (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=188127)
-
- // Create name environment
- this.env = new FileSystem(Util.getJavaClassLibs(), new String[0], null);
}
super.setUp();
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/SimpleTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/SimpleTest.java
index 8019e42e66..8763eb180f 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/SimpleTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/SimpleTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,8 @@
package org.eclipse.jdt.core.tests.eval;
import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.tests.runtime.LocalVMLauncher;
@@ -239,58 +241,62 @@ protected IProblemFactory getProblemFactory() {
return new DefaultProblemFactory(java.util.Locale.getDefault());
}
protected void startEvaluationContext() throws TargetException {
- LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
- launcher.setVMPath(JRE_PATH);
- launcher.setClassPath(RUNTIME_CLASSPATH);
- int evalPort = Util.getFreePort();
- launcher.setEvalPort(evalPort);
- launcher.setEvalTargetPath(TARGET_PATH);
- this.launchedVM = launcher.launch();
-
- (new Thread() {
- public void run() {
- try {
- java.io.InputStream in = SimpleTest.this.launchedVM.getInputStream();
- int read = 0;
- while (read != -1) {
- try {
- read = in.read();
- } catch (java.io.IOException e) {
- read = -1;
- }
- if (read != -1) {
- System.out.print((char)read);
+ try (ServerSocket server = new ServerSocket(0)) {
+ LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
+ launcher.setVMPath(JRE_PATH);
+ launcher.setClassPath(RUNTIME_CLASSPATH);
+ int evalPort = server.getLocalPort();
+ launcher.setEvalPort(evalPort);
+ launcher.setEvalTargetPath(TARGET_PATH);
+ this.launchedVM = launcher.launch();
+
+ (new Thread() {
+ public void run() {
+ try {
+ java.io.InputStream in = SimpleTest.this.launchedVM.getInputStream();
+ int read = 0;
+ while (read != -1) {
+ try {
+ read = in.read();
+ } catch (java.io.IOException e) {
+ read = -1;
+ }
+ if (read != -1) {
+ System.out.print((char)read);
+ }
}
+ } catch (TargetException e) {
}
- } catch (TargetException e) {
}
- }
- }).start();
-
- (new Thread() {
- public void run() {
- try {
- java.io.InputStream in = SimpleTest.this.launchedVM.getErrorStream();
- int read = 0;
- while (read != -1) {
- try {
- read = in.read();
- } catch (java.io.IOException e) {
- read = -1;
- }
- if (read != -1) {
- System.out.print((char)read);
+ }).start();
+
+ (new Thread() {
+ public void run() {
+ try {
+ java.io.InputStream in = SimpleTest.this.launchedVM.getErrorStream();
+ int read = 0;
+ while (read != -1) {
+ try {
+ read = in.read();
+ } catch (java.io.IOException e) {
+ read = -1;
+ }
+ if (read != -1) {
+ System.out.print((char)read);
+ }
}
+ } catch (TargetException e) {
}
- } catch (TargetException e) {
}
- }
- }).start();
-
- this.requestor = new Requestor();
- this.target = new TargetInterface();
- this.target.connect("localhost", evalPort, 30000); // allow 30s max to connect (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=188127)
- this.context = new EvaluationContext();
+ }).start();
+
+ this.requestor = new Requestor();
+ this.target = new TargetInterface();
+ this.target.connect(server, 30000); // allow 30s max to connect (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=188127)
+ this.context = new EvaluationContext();
+ } catch (IOException e) {
+ throw new Error("Failed to open socket", e);
+ }
}
protected void stopEvaluationContext() {
try {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/target/IDEInterface.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/target/IDEInterface.java
index d91a9a9d78..dac44cfdb9 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/target/IDEInterface.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/eval/target/IDEInterface.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -58,10 +58,8 @@ IDEInterface(int portNumber) {
* @throws IOException if the connection could not be established.
*/
void connect() throws IOException {
- ServerSocket server = new ServerSocket(this.portNumber);
- this.socket = server.accept();
+ this.socket = new Socket("localhost", this.portNumber);
this.socket.setTcpNoDelay(true);
- server.close();
}
/**
* Disconnects this interface from the IDE.
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/TargetInterface.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/TargetInterface.java
index ec3a790dcc..3f8a69cd20 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/TargetInterface.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/TargetInterface.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -54,18 +54,17 @@ public class TargetInterface {
* Try as long as the given time (in ms) has not expired.
* Use isConnected() to find out if the connection was successful.
*/
-public void connect(String targetAddress, int portNumber, int timeout) {
+public void connect(ServerSocket server, int timeout) {
if (isConnected()) {
return;
}
- if (portNumber > 0) {
+ if (server != null) {
long startTime = System.currentTimeMillis();
do {
try {
- this.socket = new Socket(targetAddress, portNumber);
+ this.socket = server.accept();
this.socket.setTcpNoDelay(true);
break;
- } catch (UnknownHostException e) {
} catch (IOException e) {
}
if (this.socket == null) {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
index de9ba93db8..8ea0fd5db3 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
@@ -146,7 +146,7 @@ public String getExecutionError(){
private String getVerifyTestsCode() {
return
"/*******************************************************************************\n" +
- " * Copyright (c) 2000, 2011 IBM Corporation and others.\n" +
+ " * Copyright (c) 2000, 2017 IBM Corporation and others.\n" +
" * All rights reserved. This program and the accompanying materials\n" +
" * are made available under the terms of the Eclipse Public License v1.0\n" +
" * which accompanies this distribution, and is available at\n" +
@@ -166,7 +166,6 @@ private String getVerifyTestsCode() {
"import java.io.InputStream;\n" +
"import java.lang.reflect.InvocationTargetException;\n" +
"import java.lang.reflect.Method;\n" +
- "import java.net.ServerSocket;\n" +
"import java.net.Socket;\n" +
"import java.util.StringTokenizer;\n" +
"\n" +
@@ -345,10 +344,8 @@ private String getVerifyTestsCode() {
" verify.run();\n" +
"}\n" +
"public void run() throws IOException {\n" +
- " ServerSocket server = new ServerSocket(this.portNumber);\n" +
- " this.socket = server.accept();\n" +
+ " this.socket = new Socket(\"localhost\", this.portNumber);\n" +
" this.socket.setTcpNoDelay(true);\n" +
- " server.close();\n" +
"\n" +
" DataInputStream in = new DataInputStream(this.socket.getInputStream());\n" +
" final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());\n" +
@@ -496,62 +493,66 @@ private void launchVerifyTestsIfNeeded(String[] classpaths, String[] vmArguments
launcher.setVMArguments(new String[] {"-verify"});
}
launcher.setProgramClass(VerifyTests.class.getName());
- int portNumber = Util.getFreePort();
- launcher.setProgramArguments(new String[] {Integer.toString(portNumber)});
- try {
- this.vm = launcher.launch();
- final InputStream input = this.vm.getInputStream();
- Thread outputThread = new Thread(new Runnable() {
- public void run() {
- try {
- int c = input.read();
- while (c != -1) {
- TestVerifier.this.outputBuffer.append((char) c);
- c = input.read();
+ try (ServerSocket server = new ServerSocket(0)) {
+ int portNumber = server.getLocalPort();
+
+ launcher.setProgramArguments(new String[] {Integer.toString(portNumber)});
+ try {
+ this.vm = launcher.launch();
+ final InputStream input = this.vm.getInputStream();
+ Thread outputThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ int c = input.read();
+ while (c != -1) {
+ TestVerifier.this.outputBuffer.append((char) c);
+ c = input.read();
+ }
+ } catch(IOException ioEx) {
+ }
+ }
+ });
+ final InputStream errorStream = this.vm.getErrorStream();
+ Thread errorThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ int c = errorStream.read();
+ while (c != -1) {
+ TestVerifier.this.errorBuffer.append((char) c);
+ c = errorStream.read();
+ }
+ } catch(IOException ioEx) {
}
- } catch(IOException ioEx) {
}
+ });
+ outputThread.start();
+ errorThread.start();
+ } catch(TargetException e) {
+ throw new Error(e.getMessage());
+ }
+
+ // connect to the vm
+ this.socket = null;
+ boolean isVMRunning = false;
+ do {
+ try {
+ this.socket = server.accept();
+ this.socket.setTcpNoDelay(true);
+ break;
+ } catch (UnknownHostException e) {
+ } catch (IOException e) {
}
- });
- final InputStream errorStream = this.vm.getErrorStream();
- Thread errorThread = new Thread(new Runnable() {
- public void run() {
+ if (this.socket == null) {
try {
- int c = errorStream.read();
- while (c != -1) {
- TestVerifier.this.errorBuffer.append((char) c);
- c = errorStream.read();
- }
- } catch(IOException ioEx) {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
}
+ isVMRunning = this.vm.isRunning();
}
- });
- outputThread.start();
- errorThread.start();
- } catch(TargetException e) {
+ } while (this.socket == null && isVMRunning);
+ } catch (IOException e) {
throw new Error(e.getMessage());
}
-
- // connect to the vm
- this.socket = null;
- boolean isVMRunning = false;
- do {
- try {
- this.socket = new Socket("localhost", portNumber);
- this.socket.setTcpNoDelay(true);
- break;
- } catch (UnknownHostException e) {
- } catch (IOException e) {
- }
- if (this.socket == null) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- }
- isVMRunning = this.vm.isRunning();
- }
- } while (this.socket == null && isVMRunning);
-
}
/**
* Loads and runs the given class.
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java
index 0fc1cf78c8..4adc9ae724 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/VerifyTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -19,7 +19,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;
@@ -199,10 +198,8 @@ public static void main(String[] args) throws IOException {
verify.run();
}
public void run() throws IOException {
- ServerSocket server = new ServerSocket(this.portNumber);
- this.socket = server.accept();
+ this.socket = new Socket("localhost", this.portNumber);
this.socket.setTcpNoDelay(true);
- server.close();
DataInputStream in = new DataInputStream(this.socket.getInputStream());
final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
diff --git a/org.eclipse.jdt.core.tests.model/pom.xml b/org.eclipse.jdt.core.tests.model/pom.xml
index 942986ba52..6f5139f8c2 100644
--- a/org.eclipse.jdt.core.tests.model/pom.xml
+++ b/org.eclipse.jdt.core.tests.model/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2012, 2016 Eclipse Foundation and others.
+ Copyright (c) 2012, 2017 Eclipse Foundation and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Distribution License v1.0
which accompanies this distribution, and is available at
@@ -35,9 +35,10 @@
<artifactId>tycho-surefire-plugin</artifactId>
<version>${tycho.version}</version>
<configuration>
+ <argLine>-Djdt.default.test.compliance=1.8</argLine>
<includes>
- <include>org/eclipse/jdt/core/tests/model/AllJavaModelTests.class</include>
- <include>org/eclipse/jdt/core/tests/dom/RunAllTests.class</include>
+ <include>org/eclipse/jdt/core/tests/model/AllJavaModelTestsTracing.class</include>
+ <include>org/eclipse/jdt/core/tests/dom/RunAllTestsTracing.class</include>
<include>org/eclipse/jdt/core/tests/RunFormatterTests.class</include>
</includes>
</configuration>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/APIDocumentationTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/APIDocumentationTests.java
index 25368a3657..e042f3c397 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/APIDocumentationTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/APIDocumentationTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2015 IBM Corporation and others.
+ * Copyright (c) 2008, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -202,6 +202,10 @@ public void testJavaCoreAPI() throws CoreException, IllegalArgumentException, Il
Map.Entry optionID = (Map.Entry) optionIDs.next();
realOptionNames.put(optionID.getValue(), optionID.getKey());
}
+ // tests have specific defaults for these:
+ realOptionNames.remove(JavaCore.COMPILER_SOURCE);
+ realOptionNames.remove(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM);
+ realOptionNames.remove(JavaCore.COMPILER_COMPLIANCE);
// fetch default option values
Hashtable realDefaultValues = JavaCore.getDefaultOptions();
@@ -284,7 +288,7 @@ public void testJavaCoreAPI() throws CoreException, IllegalArgumentException, Il
Map.Entry entry = (Map.Entry) check.next();
key = (String) entry.getKey();
value = (String) entry.getValue();
- if (!value.equals(realDefaultValues.get(key)) &&
+ if (realOptionNames.containsKey(key) && !value.equals(realDefaultValues.get(key)) &&
!"org.eclipse.jdt.core.compiler.problem.booleanMethodThrowingException".equals(key)) { // will remove once bug 216571 is fixed
expected = value;
actual = (String) realDefaultValues.get(key);
@@ -297,4 +301,12 @@ public void testJavaCoreAPI() throws CoreException, IllegalArgumentException, Il
System.err.println("JavaCore.java not found, skipping APIDocumentationTests#test001");
}
}
+// see https://bugs.eclipse.org/482991
+// check that tests are run with -Djdt.default.test.compliance=1.8 in effect
+public void testTestDefaultCompliance() {
+ Hashtable<String,String> defaultValues = JavaCore.getDefaultOptions();
+ assertEquals("Tests should run at default compliance 1.8", "1.8", defaultValues.get(JavaCore.COMPILER_COMPLIANCE));
+ assertEquals("Tests should run at default source level 1.8", "1.8", defaultValues.get(JavaCore.COMPILER_SOURCE));
+ assertEquals("Tests should run at default target level 1.8", "1.8", defaultValues.get(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM));
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java
index e0eb04e64a..9cf6c08efb 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -19,7 +19,10 @@ import junit.framework.Test;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.dom.*;
@@ -1293,4 +1296,21 @@ public void testBug277204e() throws JavaModelException {
"Syntax error, insert \";\" to complete ClassBodyDeclarations\n",
result);
}
+
+// Verify that the binding for a constructor is a method binding
+public void testBug381503() throws CoreException, IOException {
+ try {
+ IJavaProject javaProject = createJavaProject("P", new String[] { "src" }, new String[] { "CONVERTER_JCL_LIB" }, "bin");
+ IType type = javaProject.findType("java.lang.IllegalMonitorStateException");
+ IMethod javaElement = type.getMethod("IllegalMonitorStateException", new String[]{});
+ ASTParser parser = ASTParser.newParser(AST.JLS8);
+ parser.setResolveBindings(true);
+ parser.setProject(javaProject);
+ IBinding[] bindings = parser.createBindings(new IJavaElement[] { javaElement }, null);
+ assertEquals("Wrong number of bindings", 1, bindings.length);
+ assertTrue("Wrong binding kind: "+bindings[0].getClass().getName(), bindings[0] instanceof IMethodBinding);
+ } finally {
+ deleteProject("P");
+ }
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java
index 11437ce060..b939c9a39d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterTest.java
@@ -8586,8 +8586,8 @@ public class ASTConverterTest extends ConverterTestSetup {
ICompilationUnit sourceUnit = getCompilationUnit("Converter" , "src", "test0344", "Test.java"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
preferences = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID);
pb_assert = preferences.get(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, "");
- compiler_source = preferences.get(JavaCore.COMPILER_SOURCE, "");
- compiler_compliance = preferences.get(JavaCore.COMPILER_COMPLIANCE, "");
+ compiler_source = preferences.get(JavaCore.COMPILER_SOURCE, null);
+ compiler_compliance = preferences.get(JavaCore.COMPILER_COMPLIANCE, null);
preferences.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
preferences.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_4);
@@ -8601,8 +8601,16 @@ public class ASTConverterTest extends ConverterTestSetup {
} finally {
if (preferences != null) {
preferences.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, pb_assert);
- preferences.put(JavaCore.COMPILER_SOURCE, compiler_source);
- preferences.put(JavaCore.COMPILER_COMPLIANCE, compiler_compliance);
+ if (compiler_source != null) {
+ preferences.put(JavaCore.COMPILER_SOURCE, compiler_source);
+ } else {
+ preferences.remove(JavaCore.COMPILER_SOURCE);
+ }
+ if (compiler_compliance != null) {
+ preferences.put(JavaCore.COMPILER_COMPLIANCE, compiler_compliance);
+ } else {
+ preferences.remove(JavaCore.COMPILER_COMPLIANCE);
+ }
}
}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/RunAllTestsTracing.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/RunAllTestsTracing.java
new file mode 100644
index 0000000000..2aa6412fe7
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/RunAllTestsTracing.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.dom;
+
+import org.eclipse.test.TracingSuite;
+import org.eclipse.test.TracingSuite.TracingOptions;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(TracingSuite.class)
+@SuiteClasses(RunAllTests.class)
+@TracingOptions(stackDumpTimeoutSeconds = 60)
+public class RunAllTestsTracing {
+}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
index 6b591cb2ac..7e86442592 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -3281,6 +3281,7 @@ public void testBug290905b() throws JavaModelException {
);
}
public void testBug290905c() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.MIXED;
this.formatterPrefs.tab_size = 0;
this.formatterPrefs.indentation_size = 0;
@@ -3304,6 +3305,7 @@ public void testBug290905c() throws JavaModelException {
);
}
public void testBug290905d() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.MIXED;
this.formatterPrefs.tab_size = 0;
this.formatterPrefs.indentation_size = 0;
@@ -3327,6 +3329,7 @@ public void testBug290905d() throws JavaModelException {
);
}
public void testBug290905e() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
this.formatterPrefs.tab_size = 0;
this.formatterPrefs.indentation_size = 0;
@@ -3350,6 +3353,7 @@ public void testBug290905e() throws JavaModelException {
);
}
public void testBug290905f() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
this.formatterPrefs.tab_size = 0;
this.formatterPrefs.indentation_size = 0;
@@ -3418,6 +3422,7 @@ public void testBug293240() {
* @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=293300"
*/
public void testBug293300_wksp1_01() {
+ useOldCommentWidthCounting();
String source =
"package wksp1;\n" +
"\n" +
@@ -3455,6 +3460,7 @@ public void testBug293300_wksp1_01() {
);
}
public void testBug293300_wkps1_02() {
+ useOldCommentWidthCounting();
String source =
"package wksp1;\n" +
"\n" +
@@ -3522,6 +3528,7 @@ public void testBug293300_wkps1_03() {
);
}
public void testBug293300_wkps1_04() {
+ useOldCommentWidthCounting();
String source =
"package wksp1;\n" +
"\n" +
@@ -3723,6 +3730,7 @@ public void testBug293300_wksp2_03() {
);
}
public void testBug293300_wksp2_04() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -4201,6 +4209,7 @@ public void testBug293300_wksp2_05e_spaces() {
formatSource(source, EXPECTED_OUTPUT_WKSP2E3_SPACES);
}
public void testBug293300_wksp_06() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -4408,6 +4417,7 @@ public void testBug293300_wksp2_09() {
);
}
public void testBug293300_wksp2_10() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -4493,6 +4503,7 @@ public void testBug293300_wksp2_11() {
);
}
public void testBug293300_wksp2_12a() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -4531,6 +4542,7 @@ public void testBug293300_wksp2_12a() {
);
}
public void testBug293300_wksp2_12b() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -4569,6 +4581,7 @@ public void testBug293300_wksp2_12b() {
);
}
public void testBug293300_wksp2_13() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -4653,6 +4666,7 @@ public void _testBug293300_wksp2_15a() {
);
}
public void testBug293300_wksp2_15b() {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5072,6 +5086,7 @@ public void testBug295175d() {
);
}
public void testBug295175e() {
+ useOldCommentWidthCounting();
String source =
"package wksp3;\n" +
"\n" +
@@ -5100,6 +5115,7 @@ public void testBug295175e() {
);
}
public void testBug295175f() {
+ useOldCommentWidthCounting();
String source =
"package wksp1;\n" +
"\n" +
@@ -5137,6 +5153,7 @@ public void testBug295175f() {
* @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=295238"
*/
public void testBug295238() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_lines_in_comments = false;
String source =
"package wksp1;\n" +
@@ -5173,6 +5190,7 @@ public void testBug295238() {
}
// the following test already passed with v_A21, but failed with first version of the patch
public void testBug295238b1() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_lines_in_comments = false;
String source =
"package wksp1;\n" +
@@ -5206,6 +5224,7 @@ public void testBug295238b1() {
}
// the following test failed with v_A21 and with the version v00 of the patch
public void testBug295238b2() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_lines_in_comments = false;
String source =
"package wksp1;\n" +
@@ -5234,6 +5253,7 @@ public void testBug295238b2() {
}
// the following test failed with v_A21 and with the version v00 of the patch
public void testBug295238b3() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_lines_in_comments = false;
String source =
"package wksp1;\n" +
@@ -7462,6 +7482,7 @@ public void testBug320754_03() throws JavaModelException {
* @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=328240"
*/
public void testBug328240() {
+ useOldCommentWidthCounting();
String source =
"package com.example;\n" +
"\n" +
@@ -8404,6 +8425,7 @@ public void testBug330313_wksp1_14() {
);
}
public void testBug330313_wksp1_14_njl() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_wrapped_lines = false;
String source =
"package wksp1;\n" +
@@ -9627,6 +9649,7 @@ public void testBug330313_wksp1_46_njl() {
);
}
public void testBug330313_wksp1_47_njl() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_wrapped_lines = false;
String source =
"package wksp1;\n" +
@@ -9674,6 +9697,7 @@ public void testBug330313_wksp1_47_njl() {
);
}
public void testBug330313_wksp1_48_njl() {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_wrapped_lines = false;
String source =
"package wksp1;\n" +
@@ -11235,6 +11259,7 @@ public void testBug474916() {
* https://bugs.eclipse.org/474918 - [formatter] doesn't align fields in declarations of annotations, enums and anonymous classes
*/
public void testBug474918() {
+ useOldCommentWidthCounting();
this.formatterPrefs.align_type_members_on_columns = true;
String source =
"import java.util.function.Function;\r\n" +
@@ -11299,6 +11324,7 @@ public void testBug474918() {
* https://bugs.eclipse.org/474918 - [formatter] doesn't align fields in declarations of annotations, enums and anonymous classes
*/
public void testBug474918b() {
+ useOldCommentWidthCounting();
this.formatterPrefs.align_type_members_on_columns = true;
this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
String source =
@@ -11364,6 +11390,7 @@ public void testBug474918b() {
* https://bugs.eclipse.org/474918 - [formatter] doesn't align fields in declarations of annotations, enums and anonymous classes
*/
public void testBug474918c() {
+ useOldCommentWidthCounting();
this.formatterPrefs.align_type_members_on_columns = true;
this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
String source =
@@ -12618,4 +12645,74 @@ public void testBug500853() {
"}";
formatSource(source);
}
+/**
+ * https://bugs.eclipse.org/500853 - [formatter] Errors around formatter:off regions with "use space to indent wrapped lines"
+ * @test no {@code IndexOutOfBoundsException} is thrown
+ */
+public void testBug512791a() {
+ this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+ String source =
+ "public class Test {\n" +
+ "\n" +
+ " void f() {\n" +
+ " int a = 1 + 2 + 3 + 4;\n" +
+ " f ( ;\n" +
+ " }\n" +
+ "\n" +
+ " Object o = new Object() {\n" +
+ " };\n" +
+ "}";
+ formatSource(source);
+}
+/**
+ * https://bugs.eclipse.org/500853 - [formatter] Errors around formatter:off regions with "use space to indent wrapped lines"
+ * @test formatter doesn't get stuck in an infinite loop
+ */
+public void testBug512791b() {
+ this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+ String source =
+ "public class Test {\n" +
+ "\n" +
+ " void f() {\n" +
+ " f ( ;\n" +
+ " }\n" +
+ "\n" +
+ " Object o = new Object() {\n" +
+ " int a;\n" +
+ " };\n" +
+ "}";
+ formatSource(source);
+}
+/**
+ * https://bugs.eclipse.org/514591 - [formatter] NegativeArraySizeException with "Never indent line comments on first column"
+ * + "Use spaces to indent wrapped lines"
+ */
+public void testBug514591a() {
+ this.formatterPrefs.never_indent_line_comments_on_first_column = true;
+ this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+ String source =
+ "public class Test {\n" +
+ "\n" +
+ " String s = new StringBuilder()\n" +
+ "// .append(\"aa\")\n" +
+ " .toString();\n" +
+ "}";
+ formatSource(source);
+}
+/**
+ * https://bugs.eclipse.org/514591 - [formatter] NegativeArraySizeException with "Never indent line comments on first column"
+ * + "Use spaces to indent wrapped lines"
+ */
+public void testBug514591b() {
+ this.formatterPrefs.never_indent_block_comments_on_first_column = true;
+ this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+ String source =
+ "public class Test {\n" +
+ "\n" +
+ " String s = new StringBuilder()\n" +
+ "/* .append(\"aa\") */\n" +
+ " .toString();\n" +
+ "}";
+ formatSource(source);
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java
index 4c6f07e036..a08fb5048d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -1628,6 +1628,7 @@ public void testBug233259a() throws JavaModelException {
);
}
public void testBug233259b() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.comment_line_length = 40;
// difference with 3.3 formatter:
// split html reference as this allow not to go over the max line width
@@ -2484,6 +2485,7 @@ public void testBug237051c() throws JavaModelException {
);
}
public void testBug237051d() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"public class X {\n" +
"\n" +
@@ -2898,6 +2900,7 @@ public void testBug238210_X01() throws JavaModelException {
);
}
public void testBug238210_X02() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package eclipse30;\n" +
"\n" +
@@ -2915,6 +2918,7 @@ public void testBug238210_X02() throws JavaModelException {
);
}
public void testBug238210_X03() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package eclipse30;\n" +
"\n" +
@@ -3161,6 +3165,7 @@ public void testBug239130_clearBlankLines_preserveLineBreaks() throws JavaModelE
}
// duplicate bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=196124
public void testBug239130_196124_default() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"public class X {\n" +
"\n" +
@@ -3247,6 +3252,7 @@ public void testBug239130_96696_block_default() throws JavaModelException {
formatSource(source, source);
}
public void testBug239130_96696_block_clearBlankLines() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.join_wrapped_lines = false;
this.formatterPrefs.comment_clear_blank_lines_in_block_comment = true;
String source =
@@ -3325,6 +3331,7 @@ public void testBug239130_96696_javadoc_default() throws JavaModelException {
formatSource(source, source);
}
public void testBug239130_96696_javadoc_clearBlankLines() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.comment_clear_blank_lines_in_javadoc_comment = true;
String source =
"public class Test {\n" +
@@ -3426,6 +3433,7 @@ public void testBug239719() throws JavaModelException {
);
}
public void testBug239719b() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"public class X01 {\n" +
" \n" +
@@ -4282,6 +4290,7 @@ public void testBug260011_05() throws JavaModelException {
);
}
public void testBug260011_06() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"public interface Test {\n" +
"\n" +
@@ -4525,6 +4534,7 @@ public void testBug260274d() throws JavaModelException {
);
}
public void testBug260274e() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"class X {\n" +
"/*\n" +
@@ -4544,6 +4554,7 @@ public void testBug260274e() throws JavaModelException {
);
}
public void testBug260274f() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"class X {\n" +
"/* *****************************************************************************\n" +
@@ -4564,6 +4575,7 @@ public void testBug260274f() throws JavaModelException {
);
}
public void testBug260274g() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"class X {\n" +
"/*\n" +
@@ -4894,6 +4906,7 @@ public void testBug260381k() throws JavaModelException {
formatSource(source);
}
public void testBug260381_wksp1_01() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp1;\n" +
"\n" +
@@ -5067,6 +5080,7 @@ public void testBug260381_wksp2_01c() throws JavaModelException {
);
}
public void testBug260381_wksp2_02() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5099,6 +5113,7 @@ public void testBug260381_wksp2_02() throws JavaModelException {
);
}
public void testBug260381_wksp2_03() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5177,6 +5192,7 @@ public void testBug260381_wksp2_03b() throws JavaModelException {
);
}
public void testBug260381_wksp2_04() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5238,6 +5254,7 @@ public void testBug260381_wksp2_04() throws JavaModelException {
);
}
public void testBug260381_wksp2_05() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5321,6 +5338,7 @@ public void testBug260381_wksp2_05() throws JavaModelException {
);
}
public void testBug260381_wksp2_06() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5383,6 +5401,7 @@ public void testBug260381_wksp2_06() throws JavaModelException {
);
}
public void testBug260381_wksp2_07() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -5427,6 +5446,7 @@ public void testBug260381_wksp2_07() throws JavaModelException {
);
}
public void testBug260381_wksp2_08() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package wksp2;\n" +
"\n" +
@@ -6420,6 +6440,7 @@ public void testBug305518() {
"}\n");
}
public void testBug305518_wksp2_01() {
+ useOldCommentWidthCounting();
String source =
"public class X01 {\n" +
"/**\n" +
@@ -6750,6 +6771,7 @@ public void testBug309835_wksp1_01() {
);
}
public void testBug309835_wksp1_02() {
+ useOldCommentWidthCounting();
String source =
"public class X02 {\n" +
"\n" +
@@ -6814,6 +6836,7 @@ public void testBug309835_wksp2_01() {
* @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=311864"
*/
public void testBug311864() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.use_tags = true;
String source =
"public class Test {\n" +
@@ -7110,6 +7133,7 @@ public void testBug313651_wksp3_02() {
);
}
public void testBug348338() {
+ useOldCommentWidthCounting();
String source =
"public class X03 {\n" +
" /**\n" +
@@ -7201,6 +7225,7 @@ public void testBug471918() {
* https://bugs.eclipse.org/474011 - [formatter] non-nls strings are duplicated by formatter
*/
public void testBug474011() {
+ useOldCommentWidthCounting();
String source =
"class A {\n" +
" String aaaaaaaaaaaaaaaa = \"11111111111111111111111111111111111111\"; //$NON-NLS-1$ aaa bbb ccc\n" +
@@ -7228,6 +7253,7 @@ public void testBug474011() {
* https://bugs.eclipse.org/475294 - [formatter] "Preserve whitespace..." problems with wrapped line comments
*/
public void testBug475294() {
+ useOldCommentWidthCounting();
this.formatterPrefs.comment_preserve_white_space_between_code_and_line_comments = true;
String source =
"public class A {\n" +
@@ -7277,6 +7303,7 @@ public void testBug475294() {
* https://bugs.eclipse.org/475294 - [formatter] "Preserve whitespace..." problems with wrapped line comments
*/
public void testBug475294b() {
+ useOldCommentWidthCounting();
this.formatterPrefs.comment_preserve_white_space_between_code_and_line_comments = true;
this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
String source =
@@ -7581,6 +7608,7 @@ public void testBug510995b() {
* https://bugs.eclipse.org/512095 - [formatter] Unstable wrap on a line with wrapped code and wrapped block comment
*/
public void testBug512095() {
+ useOldCommentWidthCounting();
String source =
"class Test1 {\n" +
" void f() {\n" +
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java
index 9edcdc6bd2..bb85ca7f23 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -239,6 +239,7 @@ private Map getDefaultCompilerOptions() {
}
void formatUnit(String packageName, String unitName) throws JavaModelException{
+ useOldCommentWidthCounting();
formatUnit(packageName, unitName, CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, 0, false, 0, -1, null);
}
@@ -732,6 +733,7 @@ public void testLineComments01() throws JavaModelException {
formatUnit("comments.line", "X01.java");
}
public void testLineComments02() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"public class X02 {\r\n" +
" int field; // This is a long comment that should be split in multiple line comments in case the line comment formatting is enabled\r\n" +
@@ -745,6 +747,7 @@ public void testLineComments02() throws JavaModelException {
);
}
public void testLineComments02b() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"public interface X02b {\r\n" +
"\r\n" +
@@ -776,6 +779,7 @@ public void testLineComments06() throws JavaModelException {
formatUnit("comments.line", "X06.java");
}
public void testLineComments07() throws JavaModelException {
+ useOldCommentWidthCounting();
String source =
"package test.comments.line;\r\n" +
"\r\n" +
@@ -826,6 +830,7 @@ public void testLineComments10() throws JavaModelException {
formatUnit("comments.line", "X10.java");
}
public void testLineComments11() throws JavaModelException {
+ useOldCommentWidthCounting();
this.formatterPrefs.comment_line_length = 40;
String source =
"package test.comments.line;\r\n" +
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
index 122f47f299..67a7006683 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
@@ -107,6 +107,14 @@ public class FormatterRegressionTests extends AbstractJavaModelTests {
private void setFormatterOptions80() {
this.formatterOptions.put(DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT, Integer.toString(80));
}
+
+ /**
+ * Helper function for tests that are expect comment width counted from the
+ * beginning of the line, not from comment's starting position.
+ */
+ protected void useOldCommentWidthCounting() {
+ this.formatterPrefs.comment_count_line_length_from_starting_position = false;
+ }
/**
* Returns the OS path to the directory that contains this plugin.
*
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/comment/SingleLineTestCase.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/comment/SingleLineTestCase.java
index e3d7195c2a..7ad666b31a 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/comment/SingleLineTestCase.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/comment/SingleLineTestCase.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -145,6 +145,7 @@ public class SingleLineTestCase extends CommentTestCase {
public void testCommentWrapping5() {
setUserOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.TAB);
+ setUserOption(DefaultCodeFormatterConstants.FORMATTER_COMMENT_COUNT_LINE_LENGTH_FROM_STARTING_POSITION, DefaultCodeFormatterConstants.FALSE);
String prefix= "public class Test {" + DELIMITER + " int test; // test test test test test test test test test test test test";
String inputInfix= " ";
String expectedInfix= DELIMITER + "\t\t\t\t" + PREFIX;
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
index 4c5f2498d1..5ef43d2961 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
@@ -1332,7 +1332,7 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
null/*no source outputs*/,
null/*no inclusion pattern*/,
null/*no exclusion pattern*/,
- "1.4"
+ ""
);
}
/*
@@ -1355,7 +1355,7 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
sourceOutputs,
null/*no inclusion pattern*/,
null/*no exclusion pattern*/,
- "1.4"
+ ""
);
}
protected IJavaProject createJavaProject(String projectName, String[] sourceFolders, String[] libraries, String output) throws CoreException {
@@ -1375,7 +1375,7 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
null/*no source outputs*/,
null/*no inclusion pattern*/,
null/*no exclusion pattern*/,
- "1.4",
+ "",
false/*don't import*/
);
}
@@ -1436,7 +1436,7 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
null/*no source outputs*/,
null/*no inclusion pattern*/,
null/*no exclusion pattern*/,
- "1.4"
+ ""
);
}
protected SearchPattern createPattern(IJavaElement element, int limitTo) {
@@ -1465,7 +1465,7 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
null/*no source outputs*/,
null/*no inclusion pattern*/,
null/*no exclusion pattern*/,
- "1.4"
+ ""
);
}
protected IJavaProject createJavaProject(String projectName, String[] sourceFolders, String[] libraries, String[] projects, String projectOutput, String compliance) throws CoreException {
@@ -1792,7 +1792,13 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
javaProject.setRawClasspath(entries, projectPath.append(outputPath), monitor);
// set compliance level options
- if ("1.5".equals(compliance)) {
+ if ("1.4".equals(compliance)) {
+ Map options = new HashMap();
+ options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
+ options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4);
+ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
+ javaProject.setOptions(options);
+ } else if ("1.5".equals(compliance)) {
Map options = new HashMap();
options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
@@ -2940,7 +2946,7 @@ public abstract class AbstractJavaModelTests extends SuiteOfTestCases {
IClasspathEntry entry = classpath[i];
final IPath path = entry.getPath();
// Choose the new JCL path only if the current JCL path is different
- if (isJCLPath(path) && !path.equals(newJclLibString)) {
+ if (isJCLPath(path) && !path.toString().equals(newJclLibString)) {
classpath[i] = JavaCore.newVariableEntry(
new Path(newJclLibString),
new Path(newJclSrcString),
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTestsTracing.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTestsTracing.java
new file mode 100644
index 0000000000..8f3bfdac9a
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTestsTracing.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.model;
+
+import org.eclipse.test.TracingSuite;
+import org.eclipse.test.TracingSuite.TracingOptions;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(TracingSuite.class)
+@SuiteClasses(AllJavaModelTests.class)
+@TracingOptions(stackDumpTimeoutSeconds = 60)
+public class AllJavaModelTestsTracing {
+}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
index cbad9742ee..dda4d17fd0 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014, 2016 IBM Corporation and others.
+ * Copyright (c) 2014, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
package org.eclipse.jdt.core.tests.model;
+import java.util.HashMap;
import java.util.Map;
import junit.framework.Test;
@@ -26,7 +27,7 @@ import org.eclipse.jdt.internal.codeassist.RelevanceConstants;
public class CompletionTests18 extends AbstractJavaModelCompletionTests {
static {
-// TESTS_NAMES = new String[] {"test001"};
+// TESTS_NAMES = new String[] {"test492947"};
}
public CompletionTests18(String name) {
@@ -1532,13 +1533,18 @@ public void test430441() throws JavaModelException {
IJavaProject javaProject = getJavaProject("Completion");
Map<String, String> options = javaProject.getOptions(true);
- options.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED);
- options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
- javaProject.setOptions(options);
+ try {
+ Map<String, String> customOptions = new HashMap<String, String>(options);
+ customOptions.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED);
+ customOptions.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
+ javaProject.setOptions(customOptions);
- IEvaluationContext context = javaProject.newEvaluationContext();
- CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
- context.codeComplete(str, cursorLocation, requestor);
+ IEvaluationContext context = javaProject.newEvaluationContext();
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+ context.codeComplete(str, cursorLocation, requestor);
+ } finally {
+ javaProject.setOptions(options);
+ }
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430656, [1.8][content assist] Content assist does not work for method reference argument
public void test430656() throws JavaModelException {
@@ -2757,4 +2763,279 @@ public void test489962() throws JavaModelException {
"dispose[METHOD_REF]{dispose(), LI2;, ()I, null, null, dispose, null, [46, 50], " + (relevance + R_EXACT_EXPECTED_TYPE) + "}"
, requestor.getResults());
}
+public void test492947() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n" +
+ " public interface SomeInterface {\n" +
+ " public void someMethod(String builder);\n" +
+ "}\n" +
+ " public enum SomeEnum {\n" +
+ " SOME_ENUM((String bui) -> {\n" +
+ " bui.toCh\n" +
+ " });\n" +
+ " SomeEnum(SomeInterface callable) {}\n" +
+ " }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "bui.toCh";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ int relevance = R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED;
+ assertResults(
+ "toCharArray[METHOD_REF]{toCharArray(), Ljava.lang.String;, ()[C, null, null, toCharArray, null, [156, 160], " + relevance + "}"
+ , requestor.getResults());
+}
+public void test492947b() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n" +
+ " public interface SomeInterface {\n" +
+ " public void someMethod(StringBuilder builder);\n" +
+ "}\n" +
+ " public enum SomeEnum {\n" +
+ " SOME_ENUM((StringBui bui) -> {\n" +
+ " });\n" +
+ " SomeEnum(SomeInterface callable) {}\n" +
+ " }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "StringBui";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ int relevance = R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_RESTRICTED + R_UNQUALIFIED;
+ assertResults(
+ "StringBuilder[TYPE_REF]{StringBuilder, java.lang, Ljava.lang.StringBuilder;, null, null, null, null, [139, 148], " + relevance + "}",
+ requestor.getResults());
+}
+/**
+ * Bug - No proposal yet for types on lambda arguments
+ * @throws JavaModelException
+ */
+public void _test492947c() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n" +
+ " public interface SomeInterface {\n" +
+ " public void someMethod(StringBuilder builder);\n" +
+ "}\n" +
+ " public enum SomeEnum {\n" +
+ " SOME_ENUM((StringBui) -> {\n" +
+ " });\n" +
+ " SomeEnum(SomeInterface callable) {}\n" +
+ " }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "StringBui";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ int relevance = R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_RESTRICTED + R_UNQUALIFIED;
+ assertResults(
+ "StringBuilder[TYPE_REF]{StringBuilder, java.lang, Ljava.lang.StringBuilder;, null, null, null, null, [139, 148], " + relevance + "}"
+ , requestor.getResults());
+}
+public void _test492947d() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n" +
+ " public Main(SomeInterface arg) {}\n" +
+ " public interface SomeInterface {\n" +
+ " public void someMethod(StringBuilder builder);\n" +
+ "}\n" +
+ " Main m = new Main((StringBui) -> {\n" +
+ " });\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "StringBui";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ int relevance = R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_RESTRICTED + R_UNQUALIFIED;
+ assertResults(
+ "StringBuilder[TYPE_REF]{StringBuilder, java.lang, Ljava.lang.StringBuilder;, null, null, null, null, [139, 148], " + relevance + "}"
+ , requestor.getResults());
+}
+public void testBug493705() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/HelloWorld.java",
+ "package b493705;\n" +
+ "\n" +
+ "import java.util.function.BiFunction;\n" +
+ "\n" +
+ "class Control { }\n" +
+ "class Composite extends Control { }\n" +
+ "class Label extends Control {\n" +
+ " public Label(Composite p, int i) {}\n" +
+ "}\n" +
+ "\n" +
+ "class Viewer { }\n" +
+ "interface ViewerSupplier {\n" +
+ " ViewerUI<? extends Viewer> getViewerUI();\n" +
+ "}\n" +
+ "class ViewerUI<V extends Viewer> extends SwtUI<Control>{\n" +
+ "\n" +
+ "}\n" +
+ "interface ControlSupplier {\n" +
+ " SwtUI<? extends Control> getControlUI();\n" +
+ "}\n" +
+ "class SwtUI<T> {\n" +
+ " public SwtUI<T> child(ControlSupplier supplier) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public SwtUI<T> child(ViewerSupplier supplier) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public static <T extends Control> SwtUI<T> create(BiFunction<Composite, Integer, T> ctor) {\n" +
+ " return null;\n" +
+ " }\n" +
+ " public SwtUI<T> text(String text) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n" +
+ "public class HelloWorld {\n" +
+ " void test(SwtUI<Composite> root) {\n" +
+ " root.child(() -> SwtUI.create(Label::new)\n" +
+ " .text(\"Selection\").\n" +
+ " );\n" +
+ " }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = ".text(\"Selection\").";
+ int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ // TODO: compute relevances
+ int relevance1 = R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_RESTRICTED;
+ int relevance2 = R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_RESTRICTED + R_NON_STATIC;
+ assertResults(
+ "create[METHOD_REF]{create(), LSwtUI<LLabel;>;, <T:LControl;>(Ljava.util.function.BiFunction<LComposite;Ljava.lang.Integer;TT;>;)LSwtUI<TT;>;, null, null, create, (ctor), [853, 853], "+relevance1+"}\n" +
+ "new[KEYWORD]{new, null, null, null, null, new, null, [853, 853], "+relevance1+"}\n" +
+ "child[METHOD_REF]{child(), LSwtUI<LLabel;>;, (LControlSupplier;)LSwtUI<LLabel;>;, null, null, child, (supplier), [853, 853], "+relevance2+"}\n" +
+ "child[METHOD_REF]{child(), LSwtUI<LLabel;>;, (LViewerSupplier;)LSwtUI<LLabel;>;, null, null, child, (supplier), [853, 853], "+relevance2+"}\n" +
+ "clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, null, null, clone, null, [853, 853], "+relevance2+"}\n" +
+ "equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, null, null, equals, (obj), [853, 853], "+relevance2+"}\n" +
+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, null, null, finalize, null, [853, 853], "+relevance2+"}\n" +
+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<*>;, null, null, getClass, null, [853, 853], "+relevance2+"}\n" +
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, null, null, hashCode, null, [853, 853], "+relevance2+"}\n" +
+ "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, null, null, notify, null, [853, 853], "+relevance2+"}\n" +
+ "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, null, null, notifyAll, null, [853, 853], "+relevance2+"}\n" +
+ "text[METHOD_REF]{text(), LSwtUI<LLabel;>;, (Ljava.lang.String;)LSwtUI<LLabel;>;, null, null, text, (text), [853, 853], "+relevance2+"}\n" +
+ "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, null, null, toString, null, [853, 853], "+relevance2+"}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, null, null, wait, null, [853, 853], "+relevance2+"}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, null, null, wait, (millis), [853, 853], "+relevance2+"}\n" +
+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, null, null, wait, (millis, nanos), [853, 853], "+relevance2+"}"
+ , requestor.getResults());
+}
+// https://bugs.eclipse.org/515809 - Syso shortcut lambda expression
+public void test515809() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/X.java",
+ "public class X {\n" +
+ " void test() {\n" +
+ " new Thread(() -> sysout);\n" +
+ " }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "sysout";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults("", requestor.getResults());
+ assertEquals("completion offset=57\n" +
+ "completion range=[51, 56]\n" +
+ "completion token=\"sysout\"\n" +
+ "completion token kind=TOKEN_KIND_NAME\n" +
+ "expectedTypesSignatures=null\n" +
+ "expectedTypesKeys=null\n" +
+ "completion token location={STATEMENT_START}", requestor.getContext());
+}
+//https://bugs.eclipse.org/485492
+public void test485492a() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/Foo.java",
+ "import java.util.function.Function;\n" +
+ "public enum Foo {\n" +
+ " BAR((z) -> {\n" +
+ " z.has\n" +
+ " return z;\n" +
+ " });\n" +
+ " Foo(Function<String, String> func) { }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "z.has";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.String;, ()I, null, null, hashCode, null, [71, 74], 60}",
+ requestor.getResults());
+}
+public void test485492b() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/Foo.java",
+ "import java.util.function.Function;\n" +
+ "public enum Foo {\n" +
+ " BAR((zilch) -> {\n" +
+ " return zil;\n" +
+ " });\n" +
+ " Foo(Function<String, String> func) { }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "return zil";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "zilch[LOCAL_VARIABLE_REF]{zilch, null, Ljava.lang.String;, null, null, zilch, null, [81, 84], 52}",
+ requestor.getResults());
+}
+public void test485492c() throws JavaModelException {
+ this.workingCopies = new ICompilationUnit[1];
+ this.workingCopies[0] = getWorkingCopy(
+ "/Completion/src/Foo.java",
+ "import java.util.function.Function;\n" +
+ "public enum Foo {\n" +
+ " BAR((z) -> {\n" +
+ " return z.has;\n" +
+ " });\n" +
+ " Foo(Function<String, String> func) { }\n" +
+ "}\n");
+
+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
+ requestor.allowAllRequiredProposals();
+ String str = this.workingCopies[0].getSource();
+ String completeBehind = "z.has";
+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+ assertResults(
+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.String;, ()I, null, null, hashCode, null, [79, 82], 60}",
+ requestor.getResults());
+}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java
index ea37cbcd34..a3d5f37442 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests2.java
@@ -5254,7 +5254,7 @@ public void testBug281598c() throws Exception {
IndexManager indexManager = JavaModelManager.getIndexManager();
try {
// Create project
- IJavaProject p = createJavaProject("P", new String[] {"src"}, new String[]{"JCL_LIB"}, "bin");
+ IJavaProject p = createJavaProject("P", new String[] {"src"}, new String[]{"JCL_LIB"}, "bin", "1.4");
waitUntilIndexesReady();
// Disable indexing
@@ -5302,7 +5302,7 @@ public void testBug281598c() throws Exception {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=151500
public void testBug151500a() throws Exception {
try {
- IJavaProject p = createJavaProject("P", new String[] {"src"}, new String[]{"JCL15_LIB", "/P/lib151500.jar"}, "bin", "1.4");
+ IJavaProject p = createJavaProject("P", new String[] {"src"}, new String[]{"JCL_LIB", "/P/lib151500.jar"}, "bin", "1.4");
createJar(
new String[] {
"foo/Foo.java",
@@ -5514,7 +5514,7 @@ public void testBug317264b() throws CoreException {
IJavaProject project = null;
try
{
- project = createJavaProject("P2");
+ project = createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, "", "1.4");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path("/Completion/b317264/org.apache.commons.lang_2.modified.jar"), null, null));
createFile(
@@ -5577,7 +5577,7 @@ public void testBug317264d() throws CoreException {
IJavaProject project = null;
try
{
- project = createJavaProject("P2");
+ project = createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, "", "1.4");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path("/Completion/b317264/org.apache.commons.lang_2.modified.jar"), null, null));
createFile(
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java
index a65c072843..33fec225e7 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests_1_5.java
@@ -5969,8 +5969,8 @@ public void test0187() throws JavaModelException {
result.context);
assertResults(
- "zzz1[FIELD_REF]{zzz1, Ltest0187.ZZClass1<!+TU;>;, [Ltest0187.ZZClass2<!+TU;>;, zzz1, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}\n" +
- "zzz2[METHOD_REF]{zzz2(), Ltest0187.ZZClass1<!+TU;>;, ()[Ltest0187.ZZClass2<!+TU;>;, zzz2, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + + R_NON_STATIC + R_NON_RESTRICTED) + "}",
+ "zzz1[FIELD_REF]{zzz1, Ltest0187.ZZClass1<Ljava.lang.Object;>;, [Ltest0187.ZZClass2<Ljava.lang.Object;>;, zzz1, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}\n" +
+ "zzz2[METHOD_REF]{zzz2(), Ltest0187.ZZClass1<Ljava.lang.Object;>;, ()[Ltest0187.ZZClass2<Ljava.lang.Object;>;, zzz2, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + + R_NON_STATIC + R_NON_RESTRICTED) + "}",
result.proposals);
}
// completion test with capture
@@ -6058,8 +6058,8 @@ public void test0190() throws JavaModelException {
result.context);
assertResults(
- "zzz1[FIELD_REF]{zzz1, Ltest0190.ZZClass1<!+Ljava.lang.Object;>;, [Ltest0190.ZZClass2<!+Ljava.lang.Object;>;, zzz1, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC+ R_NON_RESTRICTED) + "}\n" +
- "zzz2[METHOD_REF]{zzz2(), Ltest0190.ZZClass1<!+Ljava.lang.Object;>;, ()[Ltest0190.ZZClass2<!+Ljava.lang.Object;>;, zzz2, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + + R_NON_STATIC + R_NON_RESTRICTED) + "}",
+ "zzz1[FIELD_REF]{zzz1, Ltest0190.ZZClass1<Ljava.lang.Object;>;, [Ltest0190.ZZClass2<Ljava.lang.Object;>;, zzz1, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC+ R_NON_RESTRICTED) + "}\n" +
+ "zzz2[METHOD_REF]{zzz2(), Ltest0190.ZZClass1<Ljava.lang.Object;>;, ()[Ltest0190.ZZClass2<Ljava.lang.Object;>;, zzz2, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + + R_NON_STATIC + R_NON_RESTRICTED) + "}",
result.proposals);
}
// completion test with capture
@@ -9270,7 +9270,7 @@ public void test0295() throws JavaModelException {
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
- "compareTo[METHOD_REF]{compareTo, Ltest.ComparableTest<!*>;, (!*)I, compareTo, (t), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}",
+ "compareTo[METHOD_REF]{compareTo, Ltest.ComparableTest<Ljava.lang.Object;>;, (Ljava.lang.Object;)I, compareTo, (t), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=99928
@@ -9325,7 +9325,7 @@ public void test0296() throws JavaModelException {
this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
assertResults(
- "compareTo[METHOD_REF]{compareTo(), Ltest.ComparableTest<!*>;, (!*)I, compareTo, (t), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}",
+ "compareTo[METHOD_REF]{compareTo(), Ltest.ComparableTest<Ljava.lang.Object;>;, (Ljava.lang.Object;)I, compareTo, (t), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=154993
@@ -11478,7 +11478,7 @@ public void test0356() throws JavaModelException {
assertResults(
"getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}\n" +
- "get[METHOD_REF]{get(), Ltest.util.List<!*>;, (I)!*, get, (i), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_NON_STATIC + R_NON_RESTRICTED) + "}",
+ "get[METHOD_REF]{get(), Ltest.util.List<Ljava.lang.Object;>;, (I)Ljava.lang.Object;, get, (i), " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_NON_STATIC + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=96604
@@ -11510,7 +11510,7 @@ public void test0357() throws JavaModelException {
assertResults(
"getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_NON_STATIC + R_NON_RESTRICTED) + "}\n" +
- "get[METHOD_REF]{get(), Ltest.X<!*>;, ()!*, get, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_NON_STATIC + R_NON_RESTRICTED) + "}",
+ "get[METHOD_REF]{get(), Ltest.X<Ltest.X<Ljava.lang.Object;>;>;, ()Ltest.X<Ltest.X<Ljava.lang.Object;>;>;, get, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_EXACT_NAME + R_NON_STATIC + R_NON_RESTRICTED) + "}",
requestor.getResults());
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=96604
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionWithMissingTypesTests_1_5.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionWithMissingTypesTests_1_5.java
index 29437ffe71..884fe4b321 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionWithMissingTypesTests_1_5.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionWithMissingTypesTests_1_5.java
@@ -369,7 +369,7 @@ public void test0007() throws JavaModelException {
int start2 = str.lastIndexOf("MissingType");
int end2 = start2 + "MissingType".length();
assertResults(
- "bar[METHOD_REF]{bar(), Ltest.AType<!+Lmissing.MissingType;>;, (!+Lmissing.MissingType;)V, bar, (t), ["+start1+", "+end1+"], " + (relevance1) + "}\n" +
+ "bar[METHOD_REF]{bar(), Ltest.AType<Lmissing.MissingType;>;, (Lmissing.MissingType;)V, bar, (t), ["+start1+", "+end1+"], " + (relevance1) + "}\n" +
" MissingType[TYPE_REF]{missing.MissingType, missing, Lmissing.MissingType;, null, null, ["+start2+", "+end2+"], " + (relevance1) + "}",
requestor.getResults());
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java
index 076c2013a0..c2b6ac0e8b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CopyMoveResourcesTests.java
@@ -205,7 +205,7 @@ public void movePositive(IJavaElement[] elements, IJavaElement[] destinations, I
public void setUp() throws Exception {
super.setUp();
- this.createJavaProject("P", new String[] {"src", "src2"}, "bin");
+ this.createJavaProject("P", new String[] {"src", "src2"}, new String[] { "JCL_LIB" }, "bin", "1.4");
}
static {
// TESTS_NAMES = new String[] { "testCopyWorkingCopyDestination"};
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
index 141f09574b..98a256ddb4 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
@@ -11993,7 +11993,7 @@ public void testBug317264b() throws CoreException {
IJavaProject project = null;
try
{
- project = createJavaProject("P");
+ project = createJavaProject("P", new String[] {""}, new String[] {"JCL_LIB"}, "", "1.4");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path("/JavaSearchBugs/lib/b317264/org.apache.commons.lang_2.modified.jar"), null, null));
int mask = IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SOURCES | IJavaSearchScope.REFERENCED_PROJECTS;
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project }, mask);
@@ -12037,7 +12037,7 @@ public void testBug317264c() throws CoreException {
public void testBug317264d() throws CoreException {
try
{
- IJavaProject project = createJavaProject("P");
+ IJavaProject project = createJavaProject("P", new String[] {""}, new String[] {"JCL_LIB"}, "", "1.4");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path("/JavaSearchBugs/lib/b317264/org.apache.commons.lang_2.modified.jar"), null, null));
int mask = IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SOURCES ;
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project }, mask);
@@ -12069,7 +12069,7 @@ public void testBug317264e() throws CoreException {
public void testBug317264f() throws CoreException {
try
{
- IJavaProject project = createJavaProject("P");
+ IJavaProject project = createJavaProject("P", new String[] {""}, new String[] {"JCL_LIB"}, "", "1.4");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path("/JavaSearchBugs/lib/b317264/org.apache.commons.lang_2.modified.jar"), null, null));
int mask = IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SOURCES ;
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project }, mask);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
index 76cd5c1bb7..994f117c19 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
@@ -1855,7 +1855,7 @@ public void test424198a() throws JavaModelException {
IJavaElement[] elements = this.wc.codeSelect(start, length);
assertElementsEqual(
"Unexpected elements",
- "v2 [in apply(capture-of ? extends java.lang.String) [in <lambda #1> [in processJar(Path) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
+ "v2 [in apply(java.lang.String) [in <lambda #1> [in processJar(Path) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
elements,
true
);
@@ -1920,7 +1920,7 @@ public void test424198b() throws JavaModelException {
IJavaElement[] elements = this.wc.codeSelect(start, length);
assertElementsEqual(
"Unexpected elements",
- "s1 [in accept(capture-of ? extends java.lang.String) [in <lambda #1> [in withWildcard(Stream<? extends String>) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
+ "s1 [in accept(java.lang.String) [in <lambda #1> [in withWildcard(Stream<? extends String>) [in InsistentCapture [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]]]",
elements,
true
);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/DatabaseTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/DatabaseTest.java
index 3d770f95e3..2d93939ea7 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/DatabaseTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/DatabaseTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2016 QNX Software Systems and others.
+ * Copyright (c) 2005, 2017 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -220,7 +220,7 @@ public class DatabaseTest extends BaseTestCase {
assertTrue(record != 0);
assertEquals(i, this.db.getInt(record));
IString rname = this.db.getString(this.db.getRecPtr(record + 4));
- assertTrue(rname.equals(name));
+ assertTrue(rname.toString().equals(name));
}
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java
new file mode 100644
index 0000000000..ad718cea77
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldListTest.java
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.nd;
+
+import java.util.List;
+
+import org.eclipse.jdt.core.tests.nd.util.BaseTestCase;
+import org.eclipse.jdt.internal.core.nd.IDestructable;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdNodeTypeRegistry;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+import junit.framework.Test;
+
+public class FieldListTest extends BaseTestCase {
+ static int nodeDeletions;
+ static int structDeletions;
+
+ public static class ElementNode extends NdNode {
+ public static final FieldString NAME;
+ public static final FieldOneToMany<TestStruct> RELATED_STRUCTS;
+ public static final FieldManyToOne<TestStruct> PARENT_NODE;
+ public static final FieldList<TestStruct> LIST_CONTENTS;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<ElementNode> type;
+
+ static {
+ type = StructDef.create(ElementNode.class, NdNode.type);
+
+ NAME = type.addString();
+ RELATED_STRUCTS = FieldOneToMany.create(type, TestStruct.RELATED_NODE);
+ PARENT_NODE = FieldManyToOne.createOwner(type, TestStruct.CHILD_NODES);
+ LIST_CONTENTS = FieldList.create(type, TestStruct.type, 3);
+ type.done();
+ }
+
+ public ElementNode(Nd nd, long record) {
+ super(nd, record);
+ }
+
+ public ElementNode(Nd nd, String name, TestStruct parent) {
+ super(nd);
+
+ NAME.put(nd, this.address, name);
+ PARENT_NODE.put(nd, this.address, parent);
+ }
+
+ public TestStruct createChild(String name) {
+ TestStruct result = LIST_CONTENTS.append(this.nd, this.address);
+ result.setName(name);
+ return result;
+ }
+
+ public List<TestStruct> getChildren() {
+ return LIST_CONTENTS.asList(getNd(), getAddress());
+ }
+
+ @Override
+ public void destruct() {
+ super.destruct();
+
+ FieldListTest.nodeDeletions++;
+ }
+
+ public IString getName() {
+ return NAME.get(getNd(), getAddress());
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ printStringTo(builder);
+ return builder.toString();
+ }
+
+ public void printStringTo(StringBuilder builder) {
+ builder.append(getName().getString());
+ if (!RELATED_STRUCTS.isEmpty(getNd(), getAddress())) {
+ builder.append("->[");
+ boolean isFirst = true;
+ for (TestStruct struct : getRelatedStructs()) {
+ if (!isFirst) {
+ builder.append(", ");
+ }
+ isFirst = false;
+ builder.append(struct.getName());
+ }
+ builder.append("]");
+ }
+
+ List<TestStruct> children = getChildren();
+ if (!children.isEmpty()) {
+ builder.append("(");
+ boolean isFirst = true;
+ for (TestStruct struct : children) {
+ if (!isFirst) {
+ builder.append(", ");
+ }
+ isFirst = false;
+ struct.printStringTo(builder);
+ }
+ builder.append(")");
+ }
+ }
+
+ public List<TestStruct> getRelatedStructs() {
+ return RELATED_STRUCTS.asList(getNd(), getAddress());
+ }
+ }
+
+ public static class TestStruct extends NdStruct implements IDestructable {
+ public static final FieldString NAME;
+ public static final FieldOneToMany<ElementNode> CHILD_NODES;
+ public static final FieldManyToOne<ElementNode> RELATED_NODE;
+ public static final FieldByte EXTRA_BYTE;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<TestStruct> type;
+
+ static {
+ type = StructDef.create(TestStruct.class, NdStruct.type);
+
+ NAME = type.addString();
+ CHILD_NODES = FieldOneToMany.create(type, ElementNode.PARENT_NODE);
+ RELATED_NODE = FieldManyToOne.create(type, ElementNode.RELATED_STRUCTS);
+ EXTRA_BYTE = type.addByte();
+ type.done();
+ }
+
+ public TestStruct(Nd nd, long record) {
+ super(nd, record);
+ }
+
+ public void printStringTo(StringBuilder builder) {
+ builder.append(getName().getString());
+ ElementNode related = RELATED_NODE.get(getNd(), getAddress());
+ if (related != null) {
+ builder.append("->[");
+ builder.append(related.getName().getString());
+ builder.append("]");
+ }
+
+ List<ElementNode> children = getChildren();
+ if (!children.isEmpty()) {
+ builder.append("(");
+ boolean isFirst = true;
+ for (ElementNode struct : children) {
+ if (!isFirst) {
+ builder.append(", ");
+ }
+ isFirst = false;
+ struct.printStringTo(builder);
+ }
+ builder.append(")");
+ }
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ printStringTo(builder);
+ return builder.toString();
+ }
+
+ public IString getName() {
+ return NAME.get(getNd(), getAddress());
+ }
+
+ public void setRelatedNode(ElementNode elementNode) {
+ RELATED_NODE.put(getNd(), getAddress(), elementNode);
+ }
+
+ public ElementNode getRelatedNode() {
+ return RELATED_NODE.get(getNd(), getAddress());
+ }
+
+ public void setName(String name) {
+ NAME.put(getNd(), getAddress(), name);
+ }
+
+ public List<ElementNode> getChildren() {
+ return CHILD_NODES.asList(getNd(), getAddress());
+ }
+
+ public ElementNode createChild(String name) {
+ return new ElementNode(getNd(), name, this);
+ }
+
+ @Override
+ public void destruct() {
+ FieldListTest.structDeletions++;
+ }
+ }
+
+ TestStruct referencer;
+ TestStruct owner;
+ private Nd nd;
+ private ElementNode root;
+ private boolean nodeDeleted;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ structDeletions = 0;
+ nodeDeletions = 0;
+ NdNodeTypeRegistry<NdNode> registry = new NdNodeTypeRegistry<>();
+ registry.register(0, ElementNode.type.getFactory());
+ this.nd = DatabaseTestUtil.createEmptyNd(getName(), registry);
+ this.nd.getDB().setExclusiveLock();
+ this.root = new ElementNode(this.nd, "root", null);
+ }
+
+ protected void freeAllMemory() throws Exception {
+ if (this.nodeDeleted) {
+ return;
+ }
+ this.nodeDeleted = true;
+ this.root.delete();
+ this.nd.processDeletions();
+ long freed = this.nd.getDB().getBytesFreed();
+ long allocated = this.nd.getDB().getBytesAllocated();
+ assertEquals("We should have freed all the bytes we allocated and no more", allocated, freed);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ freeAllMemory();
+ super.tearDown();
+ }
+
+ public void testEmptyList() throws Exception {
+ assertTrue("isEmpty() should return true if no children inserted",
+ this.root.getChildren().isEmpty());
+ freeAllMemory();
+ assertEquals("No structs should have been disposed during this test", 0, structDeletions);
+ assertEquals("One node should have been disposed during this test", 1, nodeDeletions);
+ }
+
+ public void testOneChild() throws Exception {
+ TestStruct testStruct = this.root.createChild("child");
+ assertEquals("root should be initialized properly", "child", testStruct.getName().getString());
+ assertEquals("root should have correct contents", "root(child)", this.root.toString());
+ freeAllMemory();
+ assertEquals("No structs should have been disposed during this test", 1, structDeletions);
+ assertEquals("One node should have been disposed during this test", 1, nodeDeletions);
+ }
+
+ public void testElementsInBlock() throws Exception {
+ this.root.createChild("child1");
+ this.root.createChild("child2");
+ assertEquals("root should have correct contents", "root(child1, child2)", this.root.toString());
+ this.root.createChild("child3");
+ assertEquals("root should have correct contents", "root(child1, child2, child3)",
+ this.root.toString());
+ this.root.createChild("child4");
+ assertEquals("root should have correct contents", "root(child1, child2, child3, child4)",
+ this.root.toString());
+ this.root.createChild("child5");
+ assertEquals("root should have correct contents", "root(child1, child2, child3, child4, child5)",
+ this.root.toString());
+ freeAllMemory();
+ assertEquals("No structs should have been disposed during this test", 5, structDeletions);
+ assertEquals("One node should have been disposed during this test", 1, nodeDeletions);
+ }
+
+ public void testDestructorInPartiallyFilledBlock() throws Exception {
+ this.root.createChild("child1");
+ this.root.createChild("child2");
+ this.root.createChild("child3");
+ this.root.createChild("child4");
+ freeAllMemory();
+ assertEquals("No structs should have been disposed during this test", 4, structDeletions);
+ assertEquals("One node should have been disposed during this test", 1, nodeDeletions);
+ }
+
+ public void testListOwningNode() throws Exception {
+ TestStruct child1 = this.root.createChild("child1");
+ child1.createChild("grandchild1");
+
+ assertEquals("root should have correct contents", "root(child1(grandchild1))", this.root.toString());
+
+ freeAllMemory();
+ assertEquals("No structs should have been disposed during this test", 1, structDeletions);
+ assertEquals("One node should have been disposed during this test", 2, nodeDeletions);
+ }
+
+ public void testListWithManyToOneNode() throws Exception {
+ TestStruct child1 = this.root.createChild("child1");
+ ElementNode relatedNode = new ElementNode(this.nd, "relatedNode", null);
+ child1.setRelatedNode(relatedNode);
+
+ assertEquals("Related node should have been set", relatedNode, child1.getRelatedNode());
+ assertEquals("root should have correct contents", "root(child1->[relatedNode])", this.root.toString());
+
+ this.root.delete();
+ this.nodeDeleted = true;
+
+ assertEquals("Related node should be cleared", null, child1.getRelatedNode());
+ }
+
+ public static Test suite() {
+ return BaseTestCase.suite(FieldListTest.class);
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldOneToOneTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldOneToOneTest.java
index fff83425b9..6f7631fec7 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldOneToOneTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/FieldOneToOneTest.java
@@ -33,8 +33,8 @@ public class FieldOneToOneTest extends BaseTestCase {
static {
type = StructDef.create(TestStruct.class, NdNode.type);
- ANOTHER_STRUCT = FieldOneToOne.create(type, TestStruct2.class, TestStruct2.ANOTHER_STRUCT);
- OWNED = FieldOneToOne.create(type, TestStruct2.class, TestStruct2.OWNER);
+ ANOTHER_STRUCT = FieldOneToOne.create(type, TestStruct2.type, TestStruct2.ANOTHER_STRUCT);
+ OWNED = FieldOneToOne.create(type, TestStruct2.type, TestStruct2.OWNER);
type.done();
}
@@ -79,8 +79,8 @@ public class FieldOneToOneTest extends BaseTestCase {
static {
type = StructDef.create(TestStruct2.class, NdNode.type);
- OWNER = FieldOneToOne.createOwner(type, TestStruct.class, TestStruct.OWNED);
- ANOTHER_STRUCT = FieldOneToOne.create(type, TestStruct.class, TestStruct.ANOTHER_STRUCT);
+ OWNER = FieldOneToOne.createOwner(type, TestStruct.type, TestStruct.OWNED);
+ ANOTHER_STRUCT = FieldOneToOne.create(type, TestStruct.type, TestStruct.ANOTHER_STRUCT);
type.done();
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/LargeBlockTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/LargeBlockTest.java
index 674c709c5c..c517e523f9 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/LargeBlockTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/LargeBlockTest.java
@@ -269,6 +269,25 @@ public class LargeBlockTest extends BaseTestCase {
assertEquals("A chunk should have been reused", chunkCount, this.db.getChunkCount());
}
+ public void testEndOfFreeBlockIsUsedIfThePreviousBlockIsLargerThanTheNextBlock() throws Exception {
+ long prevChunk = mallocChunks(4);
+ long middleChunk = mallocChunks(4);
+ long nextChunk = mallocChunks(2);
+
+ free(middleChunk);
+ // This should be taken from the end of "middleChunk", since that's closer to the smaller neighbor
+ long smallChunk1 = mallocChunks(1);
+ // This should also be taken from the end of the remaining portion of "middleChunk"
+ long smallChunk2 = mallocChunks(1);
+
+ assertTrue("The small chunks should have been allocated from space after 'prevChunk'",
+ prevChunk < smallChunk2);
+ assertTrue("The small chunks should have been allocated from the end of the free block",
+ smallChunk2 < smallChunk1);
+ assertTrue("The small chunks should have been allocated from space before 'nextChunk'",
+ smallChunk1 < nextChunk);
+ }
+
/**
* Tests various corner cases in the trie map.
*/
@@ -332,4 +351,56 @@ public class LargeBlockTest extends BaseTestCase {
assertEquals("A chunk should have been reused", chunkCount, this.db.getChunkCount());
}
}
+
+ /**
+ * Tests removals from the large chunk sibling list. Ensures that such removals don't interfere with
+ * the trie itself.
+ */
+ public void testUnlinkedBlockNotInTrieGetsRelinked() throws Exception {
+ long rootChunk = mallocChunks(1);
+ mallocChunks(1);
+ long unusedChunk = mallocChunks(1);
+ mallocChunks(1);
+ long chunkToBeMerged = mallocChunks(1);
+ long chunkThatWillCauseMerging = mallocChunks(1);
+ mallocChunks(1);
+ long followingChunkInFreeSpaceList = mallocChunks(1);
+ mallocChunks(1);
+ long chunkOfSize2 = mallocChunks(2);
+ mallocChunks(1);
+
+ int chunkCount = this.db.getChunkCount();
+
+ free(rootChunk);
+ free(unusedChunk);
+ free(chunkToBeMerged);
+ free(followingChunkInFreeSpaceList);
+ free(chunkOfSize2);
+
+ // At this point, the free space trie looks like this:
+ //
+ // size 1: rootChunk -> unusedChunk -> chunkToBeMerged -> followingChunkInFreeSpaceList
+ // -> size 2: chunkOfSize2
+ //
+ // By freeing chunkThatWillCauseMerging, chunkToBeMerged will be removed from the
+ // list of size 1 and inserted into the list of size 2. This test verifies that the
+ // code won't mess with the root pointer by inserting unusedChunk or chunk into the root
+
+ // This call will corrupt the database if we don't do the removal correctly
+ free(chunkThatWillCauseMerging);
+
+ // Now reallocate the original chunks to ensure they can all be found in the list
+ long firstDoubleChunk = mallocChunks(2);
+ long secondDoubleChunk = mallocChunks(2);
+
+ mallocChunks(1);
+ mallocChunks(1);
+ mallocChunks(1);
+
+ assertEquals("A chunk should have been reused", chunkCount, this.db.getChunkCount());
+ assertNotSame("Both new chunks should have been unique", firstDoubleChunk, secondDoubleChunk);
+ assertNotSame("The first chunk should not be null", 0, firstDoubleChunk);
+ assertNotSame("The second chunk should not be null", 0, secondDoubleChunk);
+ this.db.validateFreeSpace();
+ }
}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java
index f358ea0bb9..9bb4a9fb12 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/RunIndexTests.java
@@ -30,6 +30,7 @@ public static Class[] getAllTestClasses() {
ChunkWriterTests.class,
DatabaseTest.class,
FieldBackPointerTest.class,
+ FieldListTest.class,
FieldOneToOneTest.class,
IndexerTest.class,
InheritenceTests.class,
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/indexer/IndexerTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/indexer/IndexerTest.java
index 4940d07cba..a5a181da94 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/indexer/IndexerTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/nd/indexer/IndexerTest.java
@@ -158,6 +158,7 @@ public class IndexerTest extends AbstractJavaModelTests {
"p/Outer.java",
"import java.lang.annotation.*;\n" +
"\n" +
+ "@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) @interface A0 {}\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) @interface A {}\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface M {}\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @interface P {}\n" +
@@ -175,7 +176,7 @@ public class IndexerTest extends AbstractJavaModelTests {
" Middle1.@A Inner e1;\n" +
" Middle2.@A Inner e2;\n" +
" Middle2.Middle3.@A Inner2 e3;\n" +
- " @M void foo(@P Middle2.Middle3.@A Inner2 e3) {};\n" +
+ " @M void foo(@A0 Object p0, @P Middle2.Middle3.@A Inner2 e3) {};\n" +
" class Middle4 extends @A Middle1 {}\n" +
"}\n",
}, "1.8");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java
index 1f6e8665cf..db6adec763 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ImportRewrite18Test.java
@@ -37,6 +37,7 @@ import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.core.tests.model.AbstractJavaModelTests;
import org.eclipse.jface.text.BadLocationException;
@@ -549,7 +550,7 @@ public class ImportRewrite18Test extends AbstractJavaModelTests {
assertTrue(actualType.isParameterizedType());
}
- private Type runTest426094andGetType(int i) throws Exception {
+ private Type runTest426094andGetType(int i, boolean testNullImportRewriteContext) throws Exception {
String contents = "package pack1;\n" +
"public class X{\n" +
this.bug426094TestInput[i][0] + "\n" +
@@ -599,7 +600,12 @@ public class ImportRewrite18Test extends AbstractJavaModelTests {
ITypeBinding typeBinding = variableBinding.getType();
cu = getCompilationUnit("/" + PROJECT + "/src/pack1/A.java");
ImportRewrite rewrite = newImportsRewrite(cu, new String[0], 99, 99, true);
- Type actualType = rewrite.addImport(typeBinding, astRoot.getAST());
+ Type actualType;
+ if(testNullImportRewriteContext) {
+ actualType = rewrite.addImport(typeBinding, astRoot.getAST(), null, TypeLocation.UNKNOWN);
+ } else {
+ actualType = rewrite.addImport(typeBinding, astRoot.getAST());
+ }
return actualType;
}
@@ -618,7 +624,7 @@ public class ImportRewrite18Test extends AbstractJavaModelTests {
};
private Type bug426094_runi_since_8(int i) throws Exception {
- Type actualType = runTest426094andGetType(i);
+ Type actualType = runTest426094andGetType(i, false);
assertEquals(this.bug426094TestInput[i][1], actualType.toString());
return actualType;
}
@@ -831,4 +837,9 @@ public class ImportRewrite18Test extends AbstractJavaModelTests {
edit.apply(document);
compilationUnit.getBuffer().setContents(document.get());
}
+
+ public void testBug513869() throws Exception {
+ Type actualType = runTest426094andGetType(0, true);
+ assertEquals(this.bug426094TestInput[0][1], actualType.toString());
+ }
}
diff --git a/org.eclipse.jdt.core.tests.model/test.xml b/org.eclipse.jdt.core.tests.model/test.xml
index b85584fe5f..816740b5ab 100644
--- a/org.eclipse.jdt.core.tests.model/test.xml
+++ b/org.eclipse.jdt.core.tests.model/test.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2002, 2014 IBM Corporation and others.
+ Copyright (c) 2002, 2017 IBM Corporation and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
@@ -40,7 +40,7 @@
<ant target="core-test" antfile="${library-file}" dir="${eclipse-home}">
<!-- Use a subdir 'data' so that the JCL jars are put in jdt-model-folder and are deleted at the end of the tests. -->
<property name="data-dir" value="${jdt-model-folder}/data"/>
- <property name="vmargs" value="-Xmx800M -XX:+HeapDumpOnOutOfMemoryError -DstoreMemory=jdtcoremodel_mem_trace,dir=${basedir}/../.."/>
+ <property name="vmargs" value="-Xmx800M -XX:+HeapDumpOnOutOfMemoryError -DstoreMemory=jdtcoremodel_mem_trace,dir=${basedir}/../.. -Djdt.default.test.compliance=1.8"/>
<property name="plugin-name" value="${plugin-name}"/>
<property name="classname"
value="org.eclipse.jdt.core.tests.model.AllJavaModelTests"/>
@@ -53,6 +53,7 @@
<ant target="core-test" antfile="${library-file}" dir="${eclipse-home}">
<!-- Use a subdir 'data' so that the JCL jars are put in jdt-model-folder and are deleted at the end of the tests. -->
<property name="data-dir" value="${jdt-dom-folder}/data"/>
+ <property name="vmargs" value="-Djdt.default.test.compliance=1.8"/>
<property name="plugin-name" value="${plugin-name}"/>
<property name="classname"
value="org.eclipse.jdt.core.tests.dom.RunAllTests"/>
@@ -64,6 +65,7 @@
<delete dir="${formatter-folder}" quiet="true"/>
<ant target="core-test" antfile="${library-file}" dir="${eclipse-home}">
<property name="data-dir" value="${formatter-folder}"/>
+ <property name="vmargs" value="-Djdt.default.test.compliance=1.8"/>
<property name="plugin-name" value="${plugin-name}"/>
<property name="classname"
value="org.eclipse.jdt.core.tests.RunFormatterTests"/>
diff --git a/org.eclipse.jdt.core.tests.performance/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.performance/META-INF/MANIFEST.MF
index 6d33669ab6..58a7973a9a 100644
--- a/org.eclipse.jdt.core.tests.performance/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.tests.performance/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.core.tests.performance
-Bundle-Version: 3.10.0.qualifier
+Bundle-Version: 3.10.100.qualifier
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.jdt.core.tests.performance,
diff --git a/org.eclipse.jdt.core.tests.performance/pom.xml b/org.eclipse.jdt.core.tests.performance/pom.xml
index 40fbdbb7e8..0db10c8b01 100644
--- a/org.eclipse.jdt.core.tests.performance/pom.xml
+++ b/org.eclipse.jdt.core.tests.performance/pom.xml
@@ -20,7 +20,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core.tests.performance</artifactId>
- <version>3.10.0-SNAPSHOT</version>
+ <version>3.10.100-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
<testSuite>${project.artifactId}</testSuite>
diff --git a/org.eclipse.jdt.core/.options b/org.eclipse.jdt.core/.options
index e5bdf264a6..a90286e204 100644
--- a/org.eclipse.jdt.core/.options
+++ b/org.eclipse.jdt.core/.options
@@ -62,8 +62,12 @@ org.eclipse.jdt.core/debug/javamodel/insertions=false
# Records information about the invalid archive cache
org.eclipse.jdt.core/debug/javamodel/invalid_archives=false
-# Runs self-diagnostics on the large chunk free space tree
-org.eclipse.jdt.core/debug/index/largechunks=false
+# Runs self-diagnostics on the free space lists. This is expensive and will slow down indexing.
+org.eclipse.jdt.core/debug/index/freespacetest=false
+
+# Controls the amount of memory used by the traceback log, in megabytes (suggested size = 1024).
+# If nonzero, the index will print out detailed traceback information when corruption is detected.
+org.eclipse.jdt.core/debug/index/logsizemegs=0
# Logs every time a page is allocated, flushed, or inserted/removed from the page cache (very verbose)
org.eclipse.jdt.core/debug/index/pagecache=false
@@ -77,6 +81,9 @@ org.eclipse.jdt.core/debug/index/insertions=false
# Prints diagnostic information about index database locks
org.eclipse.jdt.core/debug/index/locks=false
+# Prints a message whenever the indexer is scheduled. Useful for tracking race conditions in the unit tests.
+org.eclipse.jdt.core/debug/index/scheduling=false
+
# Prints statistics about database memory usage
org.eclipse.jdt.core/debug/index/space=false
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index 194015f49d..41081ef990 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -1864,7 +1864,7 @@ public final class CompletionEngine
if (expression.body().sourceStart <= astNode.sourceStart &&
astNode.sourceEnd <= expression.body().sourceEnd) {
// completion is inside a method body
- if (astNodeParent == null &&
+ if ((astNodeParent == null || astNodeParent == expression) &&
astNode instanceof CompletionOnSingleNameReference &&
!((CompletionOnSingleNameReference)astNode).isPrecededByModifiers) {
context.setTokenLocation(CompletionContext.TL_STATEMENT_START);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
index ad48604475..ebf52c6e76 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -2126,6 +2126,7 @@ public void completionIdentifierCheck(){
// if not in a method in non diet mode and if not inside a field initializer, only record references attached to types
if (!(isInsideMethod() && !this.diet)
&& !isIndirectlyInsideFieldInitialization()
+ && !isIndirectlyInsideEnumConstantnitialization()
&& !isInsideAttributeValue()
&& !isInsideModuleInfo()) return;
@@ -3630,7 +3631,7 @@ protected void consumeToken(int token) {
int previous = this.previousToken;
int prevIdentifierPtr = this.previousIdentifierPtr;
- if (isInsideMethod() || isInsideFieldInitialization() || isInsideAnnotation()) {
+ if (isInsideMethod() || isInsideFieldInitialization() || isInsideAnnotation() || isInsideEnumConstantnitialization()) {
switch(token) {
case TokenNameLPAREN:
if(previous == TokenNameIdentifier &&
@@ -3682,7 +3683,7 @@ protected void consumeToken(int token) {
&& this.identifierStack[this.identifierPtr] == assistIdentifier()
&& this.currentElement == null
&& (!isIndirectlyInsideLambdaExpression() || isIndirectlyInsideLambdaBlock())
- && isIndirectlyInsideFieldInitialization()) {
+ && (isIndirectlyInsideFieldInitialization() || isIndirectlyInsideEnumConstantnitialization())) {
this.scanner.eofPosition = this.cursorLocation < Integer.MAX_VALUE ? this.cursorLocation+1 : this.cursorLocation;
}
if (token == TokenNameimport) {
@@ -3705,7 +3706,7 @@ protected void consumeToken(int token) {
}
// if in a method or if in a field initializer
- if (isInsideMethod() || isInsideFieldInitialization() || isInsideAttributeValue()) {
+ if (isInsideMethod() || isInsideFieldInitialization() || isInsideAttributeValue() || isInsideEnumConstantnitialization()) {
switch (token) {
case TokenNameDOT:
switch (previous) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
index aa410212cc..e1c14a5eef 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -442,6 +442,8 @@ protected void consumeEnumConstantHeader() {
pushOnElementStack(K_TYPE_DELIMITER);
}
super.consumeEnumConstantHeader();
+ if (triggerRecoveryUponLambdaClosure((Statement) this.astStack[this.astPtr], true) && this.currentElement != null)
+ this.restartRecovery = true;
}
protected void consumeEnumConstantHeaderName() {
super.consumeEnumConstantHeaderName();
@@ -1209,8 +1211,7 @@ protected void consumeToken(int token) {
}
// register message send selector only if inside a method or if looking at a field initializer
// and if the current token is an open parenthesis
- if (isInsideMethod() || isInsideFieldInitialization() || isInsideAttributeValue()) {
- adjustBracket(token);
+ if (isInsideMethod() || isInsideFieldInitialization() || isInsideAttributeValue() || isInsideEnumConstantnitialization()) {
switch (token) {
case TokenNameLPAREN :
switch (this.previousToken) {
@@ -1633,6 +1634,15 @@ protected boolean isIndirectlyInsideFieldInitialization(){
}
return false;
}
+protected boolean isIndirectlyInsideEnumConstantnitialization(){
+ int i = this.elementPtr;
+ while(i > -1) {
+ if(this.elementKindStack[i] == K_ENUM_CONSTANT_DELIMITER)
+ return true;
+ i--;
+ }
+ return false;
+}
protected boolean isIndirectlyInsideMethod(){
int i = this.elementPtr;
while(i > -1) {
@@ -1688,7 +1698,21 @@ protected boolean isInsideFieldInitialization(){
switch (this.elementKindStack[i]) {
case K_TYPE_DELIMITER : return false;
case K_METHOD_DELIMITER : return false;
- case K_FIELD_INITIALIZER_DELIMITER : return true;
+ case K_FIELD_INITIALIZER_DELIMITER :
+ return true;
+ }
+ i--;
+ }
+ return false;
+}
+protected boolean isInsideEnumConstantnitialization(){
+ int i = this.elementPtr;
+ while(i > -1) {
+ switch (this.elementKindStack[i]) {
+ case K_TYPE_DELIMITER : return false;
+ case K_METHOD_DELIMITER : return false;
+ case K_ENUM_CONSTANT_DELIMITER :
+ return true;
}
i--;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
index dd6dd1b155..64d7df6ff2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
@@ -48,8 +48,6 @@ public class Assignment extends Expression {
public Expression expression;
public Assignment(Expression lhs, Expression expression, int sourceEnd) {
- //lhs is always a reference by construction ,
- //but is build as an expression ==> the checkcast cannot fail
this.lhs = lhs;
lhs.bits |= IsStrictlyAssigned; // tag lhs as assigned
this.expression = expression;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index 1c7dafb98c..0c12277070 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -37,6 +37,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -322,12 +323,31 @@ private static void checkAlternateBinding(BlockScope scope, Expression receiver,
for (int i = 0; i < argumentLength; i++) {
if (TypeBinding.notEquals(originalArgumentTypes[i], alternateArgumentTypes[i])
/*&& !originalArgumentTypes[i].needsUncheckedConversion(alternateArgumentTypes[i])*/) {
- scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]);
+ if (!preventsUnlikelyTypeWarning(originalArgumentTypes[i], alternateArgumentTypes[i], receiverType, binding, scope))
+ scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]);
}
}
}
}
+private static boolean preventsUnlikelyTypeWarning(TypeBinding castedType, TypeBinding uncastedType, TypeBinding receiverType, MethodBinding binding, BlockScope scope) {
+ if (!scope.compilerOptions().isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE))
+ return false;
+ if (binding.isStatic() || binding.parameters.length != 1)
+ return false;
+ // would using the uncastedType be considered as dangerous?
+ UnlikelyArgumentCheck argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod(
+ uncastedType, scope, binding.selector, receiverType, binding.parameters);
+ if (argumentChecks != null && argumentChecks.isDangerous(scope)) {
+ // does the cast help?
+ argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod(
+ castedType, scope, binding.selector, receiverType, binding.parameters);
+ if (argumentChecks == null || !argumentChecks.isDangerous(scope))
+ return true;
+ }
+ return false;
+}
+
public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
if (TypeBinding.equalsEquals(match, castType)) {
if (!isNarrowing && TypeBinding.equalsEquals(match, this.resolvedType.leafComponentType()) // do not tag as unnecessary when recursing through upper bounds
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
index bbe252b7fc..e2cf5d4e5b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
@@ -35,7 +35,6 @@ import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
-import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier;
import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -202,7 +201,6 @@ public abstract class FunctionalExpression extends Expression {
}
LookupEnvironment environment = blockScope.environment();
if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
- ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(sam, blockScope);
NullAnnotationMatching.checkForContradictions(sam, this, blockScope);
}
return this.resolvedType = this.expectedType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
index 2c4620c0b5..63e2c2ca84 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
@@ -944,7 +944,14 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
if (r1.isCompatibleWith(r2, skope))
return true;
- LambdaExpression copy = cachedResolvedCopy(s, true /* any resolved copy is good */, false, null); // we expect a cached copy - otherwise control won't reach here.
+ LambdaExpression copy;
+ try {
+ copy = cachedResolvedCopy(s, true /* any resolved copy is good */, false, null); // we expect a cached copy - otherwise control won't reach here.
+ } catch (CopyFailureException cfe) {
+ if (this.assistNode)
+ return false;
+ throw cfe;
+ }
Expression [] returnExpressions = copy.resultExpressions;
int returnExpressionsLength = returnExpressions == null ? 0 : returnExpressions.length;
if (returnExpressionsLength > 0) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index 7627374dde..ba19ce25e4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -247,20 +247,21 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx
}
// Process the lambda, taking care not to double report diagnostics. Don't expect any from resolve, Any from code generation should surface, but not those from flow analysis.
- implicitLambda.resolveType(currentScope, true);
- IErrorHandlingPolicy oldPolicy = currentScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
+ BlockScope lambdaScope = this.receiverVariable != null ? this.receiverVariable.declaringScope : currentScope;
+ implicitLambda.resolveType(lambdaScope, true);
+ IErrorHandlingPolicy oldPolicy = lambdaScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
try {
- implicitLambda.analyseCode(currentScope,
- new FieldInitsFakingFlowContext(null, this, Binding.NO_EXCEPTIONS, null, currentScope, FlowInfo.DEAD_END),
- UnconditionalFlowInfo.fakeInitializedFlowInfo(currentScope.outerMostMethodScope().analysisIndex, currentScope.referenceType().maxFieldCount));
+ implicitLambda.analyseCode(lambdaScope,
+ new FieldInitsFakingFlowContext(null, this, Binding.NO_EXCEPTIONS, null, lambdaScope, FlowInfo.DEAD_END),
+ UnconditionalFlowInfo.fakeInitializedFlowInfo(lambdaScope.outerMostMethodScope().analysisIndex, lambdaScope.referenceType().maxFieldCount));
} finally {
- currentScope.problemReporter().switchErrorHandlingPolicy(oldPolicy);
+ lambdaScope.problemReporter().switchErrorHandlingPolicy(oldPolicy);
}
SyntheticArgumentBinding[] outerLocals = this.receiverType.syntheticOuterLocalVariables();
for (int i = 0, length = outerLocals == null ? 0 : outerLocals.length; i < length; i++)
implicitLambda.addSyntheticArgument(outerLocals[i].actualOuterLocalVariable);
- implicitLambda.generateCode(currentScope, codeStream, valueRequired);
+ implicitLambda.generateCode(lambdaScope, codeStream, valueRequired);
if (generateSecretReceiverVariable) {
codeStream.removeVariable(this.receiverVariable);
this.receiverVariable = null;
@@ -280,8 +281,10 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx
// Handle some special cases up front and transform them into implicit lambdas.
if (shouldGenerateImplicitLambda(currentScope)) {
generateImplicitLambda(currentScope, codeStream, valueRequired);
+ cleanUp();
return;
}
+ cleanUp();
SourceTypeBinding sourceType = currentScope.enclosingSourceType();
if (this.receiverType.isArrayType()) {
char [] lambdaName = CharOperation.concat(TypeConstants.ANONYMOUS_METHOD, Integer.toString(this.ordinal).toCharArray());
@@ -367,6 +370,18 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
+ private void cleanUp() {
+ // no more rescanning needed beyond this point, so free the memory:
+ if (this.copiesPerTargetType != null) {
+ for (ReferenceExpression copy : this.copiesPerTargetType.values())
+ copy.scanner = null;
+ }
+ if (this.original != null && this.original != this) {
+ this.original.cleanUp();
+ }
+ this.scanner = null;
+ }
+
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 || this.binding == null || !this.binding.isValidBinding())
@@ -797,8 +812,16 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx
int len;
int expectedlen = this.binding.parameters.length;
int providedLen = this.descriptor.parameters.length;
- if (this.receiverPrecedesParameters)
+ if (this.receiverPrecedesParameters) {
providedLen--; // one parameter is 'consumed' as the receiver
+
+ TypeBinding descriptorParameter = this.descriptor.parameters[0];
+ if((descriptorParameter.tagBits & TagBits.AnnotationNullable) != 0) { // Note: normal dereferencing of 'unchecked' values is not reported, either
+ final TypeBinding receiver = scope.environment().createAnnotatedType(this.binding.declaringClass,
+ new AnnotationBinding[] { scope.environment().getNonNullAnnotation() });
+ scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, receiver, descriptorParameter, this.descriptor, -1, NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH);
+ }
+ }
boolean isVarArgs = false;
if (this.binding.isVarargs()) {
isVarArgs = (providedLen == expectedlen)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index 52f0c52188..e3643f6436 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -125,8 +125,8 @@ protected void analyseArguments(BlockScope currentScope, FlowContext flowContext
if (methodBinding.isVarargs()) {
varArgPos = numParamsToCheck-1;
// this if-block essentially copied from generateArguments(..):
+ varArgsType = methodBinding.parameters[varArgPos];
if (numParamsToCheck == arguments.length) {
- varArgsType = methodBinding.parameters[varArgPos];
TypeBinding lastType = arguments[varArgPos].resolvedType;
if (lastType == TypeBinding.NULL
|| (varArgsType.dimensions() == lastType.dimensions()
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index bd51350fd0..48850affe5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -82,7 +82,7 @@ public class SwitchStatement extends Statement {
this.expression.checkNPE(currentScope, flowContext, flowInfo, 1);
}
SwitchFlowContext switchContext =
- new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true);
+ new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true, true);
// analyse the block by considering specially the case/default statements (need to bind them
// to the entry point)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
index a215dda1c1..e5eeaae730 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -103,6 +103,7 @@ public class WhileStatement extends Statement {
this.continueLabel,
currentScope,
true);
+ loopingContext.copyNullCheckedFieldsFrom(condLoopContext);
if (isConditionFalse) {
actionInfo = FlowInfo.DEAD_END;
} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
index c12c04406a..893df8a3f2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -97,7 +97,7 @@ ExceptionHandlingFlowContext(
BlockScope scope,
UnconditionalFlowInfo flowInfo) {
- super(parent, associatedNode);
+ super(parent, associatedNode, true);
this.isMethodContext = scope == scope.methodScope();
this.handledExceptions = handledExceptions;
this.catchArguments = catchArguments;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
index ce65992f2b..d225440473 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -61,7 +61,7 @@ import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
public class FlowContext implements TypeConstants {
// preempt marks looping contexts
- public final static FlowContext NotContinuableContext = new FlowContext(null, null);
+ public final static FlowContext NotContinuableContext = new FlowContext(null, null, true);
public ASTNode associatedNode;
public FlowContext parent;
public FlowInfo initsOnFinally;
@@ -121,7 +121,7 @@ public static final int IN_INSTANCEOF = 0x0400;
// check happened in an instanceof expression
public static final int CONTEXT_MASK = ~CHECK_MASK & ~HIDE_NULL_COMPARISON_WARNING_MASK;
-public FlowContext(FlowContext parent, ASTNode associatedNode) {
+public FlowContext(FlowContext parent, ASTNode associatedNode, boolean inheritNullFieldChecks) {
this.parent = parent;
this.associatedNode = associatedNode;
if (parent != null) {
@@ -130,8 +130,16 @@ public FlowContext(FlowContext parent, ASTNode associatedNode) {
}
this.initsOnFinally = parent.initsOnFinally;
this.conditionalLevel = parent.conditionalLevel;
- this.nullCheckedFieldReferences = parent.nullCheckedFieldReferences; // re-use list if there is one
- this.timesToLiveForNullCheckInfo = parent.timesToLiveForNullCheckInfo;
+ if (inheritNullFieldChecks)
+ copyNullCheckedFieldsFrom(parent); // re-use list if there is one
+ }
+}
+
+public void copyNullCheckedFieldsFrom(FlowContext other) {
+ Reference[] fieldReferences = other.nullCheckedFieldReferences;
+ if (fieldReferences != null && fieldReferences.length > 0 && fieldReferences[0] != null) {
+ this.nullCheckedFieldReferences = other.nullCheckedFieldReferences;
+ this.timesToLiveForNullCheckInfo = other.timesToLiveForNullCheckInfo;
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
index 309eefc3a1..b279d47d7d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -26,7 +26,7 @@ public class LabelFlowContext extends SwitchFlowContext {
public char[] labelName;
public LabelFlowContext(FlowContext parent, ASTNode associatedNode, char[] labelName, BranchLabel breakLabel, BlockScope scope) {
- super(parent, associatedNode, breakLabel, false);
+ super(parent, associatedNode, breakLabel, false, true);
this.labelName = labelName;
checkLabelValidity(scope);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
index ec758b4d75..1fd26137cb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -105,7 +105,7 @@ public class LoopingFlowContext extends SwitchFlowContext {
BranchLabel continueLabel,
Scope associatedScope,
boolean isPreTest) {
- super(parent, associatedNode, breakLabel, isPreTest);
+ super(parent, associatedNode, breakLabel, isPreTest, false);
this.tagBits |= FlowContext.PREEMPT_NULL_DIAGNOSTIC;
// children will defer to this, which may defer to its own parent
this.continueLabel = continueLabel;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
index 279fff0a36..ce2ed9b7bf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -24,8 +24,8 @@ public class SwitchFlowContext extends FlowContext {
public BranchLabel breakLabel;
public UnconditionalFlowInfo initsOnBreak = FlowInfo.DEAD_END;
-public SwitchFlowContext(FlowContext parent, ASTNode associatedNode, BranchLabel breakLabel, boolean isPreTest) {
- super(parent, associatedNode);
+public SwitchFlowContext(FlowContext parent, ASTNode associatedNode, BranchLabel breakLabel, boolean isPreTest, boolean inheritNullFieldChecks) {
+ super(parent, associatedNode, inheritNullFieldChecks);
this.breakLabel = breakLabel;
if (isPreTest && parent.conditionalLevel > -1) {
this.conditionalLevel++;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
index 1623e51260..98f4fecfbc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 GK Software AG and others.
+ * Copyright (c) 2013, 2017 GK Software AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -25,7 +25,7 @@ public abstract class TryFlowContext extends FlowContext {
public FlowContext outerTryContext;
public TryFlowContext(FlowContext parent, ASTNode associatedNode) {
- super(parent, associatedNode);
+ super(parent, associatedNode, true);
}
public void markFinallyNullStatus(LocalVariableBinding local, int nullStatus) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
index 390d7a64dd..48b4c2b094 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
@@ -1076,7 +1076,7 @@ public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext,
if (!compilerOptions().analyseResourceLeaks) return;
if (this.trackingVariables == null) {
// at a method return we also consider enclosing scopes
- if (location != null && this.parent instanceof BlockScope)
+ if (location != null && this.parent instanceof BlockScope && !isLambdaScope())
((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, flowContext, location, locationScope);
return;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index b8ebe83982..f8e185dc72 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2016 GK Software AG.
+ * Copyright (c) 2013, 2017 GK Software AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -736,15 +736,15 @@ class BoundSet {
it = three.sameBounds.iterator();
while (it.hasNext()) {
TypeBound bound = it.next();
- if (InferenceContext18.SHOULD_WORKAROUND_BUG_JDK_8054721) {
- if (bound.right instanceof CaptureBinding && bound.right.isProperType(true))
- continue;
- }
if (!(bound.right instanceof InferenceVariable))
return false;
}
}
- if (three.subBounds != null && pi.firstBound != null) {
+ if (three.subBounds != null) {
+ TypeBinding bi1 = pi.firstBound;
+ if (bi1 == null) {
+ bi1 = context.object; // implicit bound
+ }
// If Bi is Object, α <: R implies ⟨T <: R⟩ (extends wildcard)
// α <: R implies ⟨θ Bi <: R⟩ (else)
it = three.subBounds.iterator();
@@ -752,7 +752,6 @@ class BoundSet {
TypeBound bound = it.next();
if (!(bound.right instanceof InferenceVariable)) {
TypeBinding r = bound.right;
- TypeBinding bi1 = pi.firstBound;
ReferenceBinding[] otherBounds = pi.superInterfaces;
TypeBinding bi;
if (otherBounds == Binding.NO_SUPERINTERFACES) {
@@ -765,13 +764,6 @@ class BoundSet {
bi = context.environment.createIntersectionType18(allBounds);
}
addTypeBoundsFromWildcardBound(context, theta, wildcardBinding.boundKind, t, r, bi);
- // if (otherBounds != null) {
- // for (int j = 0; j < otherBounds.length; j++) {
- // TypeBinding tj = otherBounds[j];
- // if (TypeBinding.notEquals(tj, t))
- // addTypeBoundsFromWildcardBound(context, wildcardBinding, tj, r, bij);
- // }
- // }
}
}
}
@@ -1256,8 +1248,8 @@ class BoundSet {
}
}
for (InferenceVariable iv : outerVariables) {
- three = this.boundsPerVariable.get(outerVariables);
- if (three != null) {
+ three = this.boundsPerVariable.get(iv);
+ if (three != null && three.sameBounds != null) {
for (TypeBound bound : three.sameBounds)
if (TypeBinding.equalsEquals(bound.right, variable))
return iv;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
index 63ec961496..bf7a147fd9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
@@ -60,8 +60,11 @@ public class CaptureBinding extends TypeVariableBinding {
super.setTypeAnnotations(wildcard.getTypeAnnotations(), wildcard.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
if (wildcard.hasNullTypeAnnotations())
this.tagBits |= TagBits.HasNullTypeAnnotation;
- } else {
+ } else {
computeId(this.environment);
+ if(wildcard.hasNullTypeAnnotations()) {
+ this.tagBits |= (wildcard.tagBits & TagBits.AnnotationNullMASK) | TagBits.HasNullTypeAnnotation;
+ }
}
}
@@ -133,10 +136,18 @@ public class CaptureBinding extends TypeVariableBinding {
}
public char[] genericTypeSignature() {
- if (this.genericTypeSignature == null) {
- this.genericTypeSignature = CharOperation.concat(TypeConstants.WILDCARD_CAPTURE, this.wildcard.genericTypeSignature());
+ // captures have no signature per JVMS 4.7.9.1, approximate one by erasure:
+ if (this.inRecursiveFunction) {
+ // catch "capture#1 of X<capture#1 ...>":
+ // prefer answering "Ljava.lang.Object;" instead of throwing StackOverflowError:
+ return CharOperation.concat(new char[] {'L'}, CharOperation.concatWith(TypeConstants.JAVA_LANG_OBJECT, '.'), new char[] {';'});
+ }
+ this.inRecursiveFunction = true;
+ try {
+ return erasure().genericTypeSignature();
+ } finally {
+ this.inRecursiveFunction = false;
}
- return this.genericTypeSignature;
}
/**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
index 8160c1a0f2..50ce75948b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
@@ -292,28 +292,6 @@ public class CaptureBinding18 extends CaptureBinding {
int recursionLevel = 0; // used to give a hint at recursive types without going into infinity
- public char[] genericTypeSignature() {
- // since we have no wildcard, we combine the logic from CaptureBinding plus WildcardBinding here:
- if (this.genericTypeSignature == null) {
- char[] boundSignature;
- try {
- if (this.prototype.recursionLevel++ > 0 || this.firstBound == null) {
- boundSignature = TypeConstants.WILDCARD_STAR;
- } else if (this.upperBounds != null) {
- boundSignature = CharOperation.concat(TypeConstants.WILDCARD_PLUS, this.firstBound.genericTypeSignature());
- } else if (this.lowerBound != null) {
- boundSignature = CharOperation.concat(TypeConstants.WILDCARD_MINUS, this.lowerBound.genericTypeSignature());
- } else {
- boundSignature = TypeConstants.WILDCARD_STAR;
- }
- this.genericTypeSignature = CharOperation.concat(TypeConstants.WILDCARD_CAPTURE, boundSignature);
- } finally {
- this.prototype.recursionLevel--;
- }
- }
- return this.genericTypeSignature;
- }
-
public char[] readableName() {
if (this.lowerBound == null && this.firstBound != null) {
if (this.prototype.recursionLevel < 2) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
index f903676f4c..65fc171f5d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2016 GK Software AG.
+ * Copyright (c) 2013, 2017 GK Software AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -27,6 +27,7 @@ import org.eclipse.jdt.internal.compiler.ast.Invocation;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord;
/**
@@ -382,8 +383,7 @@ class ConstraintExpressionFormula extends ConstraintFormula {
throw new InferenceFailureException("expression has no value"); //$NON-NLS-1$
if (inferenceContext.usesUncheckedConversion) {
- // spec says erasure, but we don't really have compatibility rules for erasure, use raw type instead:
- TypeBinding erasure = inferenceContext.environment.convertToRawType(returnType, false);
+ TypeBinding erasure = getRealErasure(returnType, inferenceContext.environment);
ConstraintTypeFormula newConstraint = ConstraintTypeFormula.create(erasure, targetType, COMPATIBLE);
return inferenceContext.reduceAndIncorporate(newConstraint);
}
@@ -396,12 +396,17 @@ class ConstraintExpressionFormula extends ConstraintFormula {
parameterizedType.genericType(), betas, parameterizedType.enclosingType(), parameterizedType.getTypeAnnotations());
inferenceContext.currentBounds.captures.put(gbeta, parameterizedType); // established: both types have nonnull arguments
if (InferenceContext18.SHOULD_WORKAROUND_BUG_JDK_8054721) {
- parameterizedType = parameterizedType.capture(inferenceContext.scope, invocationSite.sourceStart(), invocationSite.sourceEnd());
- arguments = parameterizedType.arguments;
for (int i = 0, length = arguments.length; i < length; i++) {
- if (arguments[i].isCapture() && arguments[i].isProperType(true)) {
- CaptureBinding capture = (CaptureBinding) arguments[i];
- inferenceContext.currentBounds.addBound(new TypeBound(betas[i], capture, SAME), inferenceContext.environment);
+ if (arguments[i].isWildcard()) {
+ WildcardBinding wc = (WildcardBinding) arguments[i];
+ switch (wc.boundKind) {
+ case Wildcard.EXTENDS:
+ inferenceContext.currentBounds.addBound(new TypeBound(betas[i], wc.bound(), SUBTYPE), inferenceContext.environment);
+ break;
+ case Wildcard.SUPER:
+ inferenceContext.currentBounds.addBound(new TypeBound(betas[i], wc.bound(), SUPERTYPE), inferenceContext.environment);
+ break;
+ }
}
}
}
@@ -440,6 +445,17 @@ class ConstraintExpressionFormula extends ConstraintFormula {
return true;
}
+ private static TypeBinding getRealErasure(TypeBinding type, LookupEnvironment environment) {
+ TypeBinding erasure = type.erasure();
+ // could still be / contain a generic type that needs to be converted to raw:
+ TypeBinding erasedLeaf = erasure.leafComponentType();
+ if (erasedLeaf.isGenericType())
+ erasedLeaf = environment.convertToRawType(erasedLeaf, false);
+ if (erasure.isArrayType())
+ return environment.createArrayType(erasedLeaf, erasure.dimensions());
+ return erasedLeaf;
+ }
+
Collection<InferenceVariable> inputVariables(final InferenceContext18 context) {
// from 18.5.2.
if (this.left instanceof LambdaExpression) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index 0c581672d1..17d5b7e825 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -1640,7 +1640,8 @@ public class InferenceContext18 {
* unless the given candidate is tolerable to be compatible with buggy javac.
*/
public MethodBinding getReturnProblemMethodIfNeeded(TypeBinding expectedType, MethodBinding method) {
- if (InferenceContext18.SIMULATE_BUG_JDK_8026527 && expectedType != null && method.returnType instanceof ReferenceBinding) {
+ if (InferenceContext18.SIMULATE_BUG_JDK_8026527 && expectedType != null
+ && (method.returnType instanceof ReferenceBinding || method.returnType instanceof ArrayBinding)) {
if (method.returnType.erasure().isCompatibleWith(expectedType))
return method; // don't count as problem.
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
index 6b78a5f68d..2091d9705a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
@@ -87,11 +87,17 @@ public class InferenceVariable extends TypeVariableBinding {
int varId; // this is used for constructing a source name like T#0.
private InferenceVariable(TypeBinding typeParameter, int parameterRank, int iVarId, InvocationSite site, LookupEnvironment environment, ReferenceBinding object) {
- this(typeParameter, parameterRank, site,
- CharOperation.concat(typeParameter.shortReadableName(), Integer.toString(iVarId).toCharArray(), '#'),
- environment, object);
+ this(typeParameter, parameterRank, site, makeName(typeParameter, iVarId), environment, object);
this.varId = iVarId;
}
+ private static char[] makeName(TypeBinding typeParameter, int iVarId) {
+ if (typeParameter.getClass() == TypeVariableBinding.class) {
+ return CharOperation.concat(typeParameter.shortReadableName(), Integer.toString(iVarId).toCharArray(), '#');
+ }
+ return CharOperation.concat(
+ CharOperation.concat('(', typeParameter.shortReadableName(), ')'),
+ Integer.toString(iVarId).toCharArray(), '#');
+ }
private InferenceVariable(TypeBinding typeParameter, int parameterRank, InvocationSite site, char[] sourceName, LookupEnvironment environment, ReferenceBinding object) {
super(sourceName, null/*declaringElement*/, parameterRank, environment);
this.site = site;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
index 798d16323a..22da49c265 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
@@ -54,12 +54,12 @@ public class IntersectionTypeBinding18 extends ReferenceBinding { // abstraction
}
@Override
- protected MethodBinding[] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards) throws InvalidInputException {
+ protected MethodBinding[] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards, boolean filterDefaultMethods) throws InvalidInputException {
int typesLength = this.intersectingTypes.length;
MethodBinding[][] methods = new MethodBinding[typesLength][];
int contractsLength = 0;
for (int i = 0; i < typesLength; i++) {
- methods[i] = this.intersectingTypes[i].getInterfaceAbstractContracts(scope, replaceWildcards);
+ methods[i] = this.intersectingTypes[i].getInterfaceAbstractContracts(scope, replaceWildcards, true);
contractsLength += methods[i].length;
}
MethodBinding[] contracts = new MethodBinding[contractsLength];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
index 57dd15d231..65a96c5da9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -610,7 +610,7 @@ public TypeBinding convertToRawType(TypeBinding type, boolean forceRawEnclosingT
needToConvert = false;
break;
}
- forceRawEnclosingType &= !type.isStatic();
+ forceRawEnclosingType &= !originalType.isStatic();
ReferenceBinding originalEnclosing = originalType.enclosingType();
TypeBinding convertedType;
if (originalEnclosing == null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index 934a4835f6..4636fdd8fe 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -192,31 +192,37 @@ public MethodBinding asRawMethod(LookupEnvironment env) {
int length = this.typeVariables.length;
TypeBinding[] arguments = new TypeBinding[length];
for (int i = 0; i < length; i++) {
- TypeVariableBinding var = this.typeVariables[i];
- if (var.boundsCount() <= 1) {
- arguments[i] = env.convertToRawType(var.upperBound(), false /*do not force conversion of enclosing types*/);
+ arguments[i] = makeRawArgument(env, this.typeVariables[i]);
+ }
+ return env.createParameterizedGenericMethod(this, arguments);
+}
+private TypeBinding makeRawArgument(LookupEnvironment env, TypeVariableBinding var) {
+ if (var.boundsCount() <= 1) {
+ TypeBinding upperBound = var.upperBound();
+ if (upperBound.isTypeVariable())
+ return makeRawArgument(env, (TypeVariableBinding) upperBound);
+ return env.convertToRawType(upperBound, false /*do not force conversion of enclosing types*/);
+ } else {
+ // use an intersection type to retain full bound information if more than 1 bound
+ TypeBinding[] itsSuperinterfaces = var.superInterfaces();
+ int superLength = itsSuperinterfaces.length;
+ TypeBinding rawFirstBound = null;
+ TypeBinding[] rawOtherBounds = null;
+ if (var.boundsCount() == superLength) {
+ rawFirstBound = env.convertToRawType(itsSuperinterfaces[0], false);
+ rawOtherBounds = new TypeBinding[superLength - 1];
+ for (int s = 1; s < superLength; s++)
+ rawOtherBounds[s - 1] = env.convertToRawType(itsSuperinterfaces[s], false);
} else {
- // use an intersection type to retain full bound information if more than 1 bound
- TypeBinding[] itsSuperinterfaces = var.superInterfaces();
- int superLength = itsSuperinterfaces.length;
- TypeBinding rawFirstBound = null;
- TypeBinding[] rawOtherBounds = null;
- if (var.boundsCount() == superLength) {
- rawFirstBound = env.convertToRawType(itsSuperinterfaces[0], false);
- rawOtherBounds = new TypeBinding[superLength - 1];
- for (int s = 1; s < superLength; s++)
- rawOtherBounds[s - 1] = env.convertToRawType(itsSuperinterfaces[s], false);
- } else {
- rawFirstBound = env.convertToRawType(var.superclass(), false);
- rawOtherBounds = new TypeBinding[superLength];
- for (int s = 0; s < superLength; s++)
- rawOtherBounds[s] = env.convertToRawType(itsSuperinterfaces[s], false);
- }
- arguments[i] = env.createWildcard(null, 0, rawFirstBound, rawOtherBounds, org.eclipse.jdt.internal.compiler.ast.Wildcard.EXTENDS);
+ rawFirstBound = env.convertToRawType(var.superclass(), false);
+ rawOtherBounds = new TypeBinding[superLength];
+ for (int s = 0; s < superLength; s++)
+ rawOtherBounds[s] = env.convertToRawType(itsSuperinterfaces[s], false);
}
+ return env.createWildcard(null, 0, rawFirstBound, rawOtherBounds, org.eclipse.jdt.internal.compiler.ast.Wildcard.EXTENDS);
}
- return env.createParameterizedGenericMethod(this, arguments);
}
+
/* Answer true if the receiver is visible to the type provided by the scope.
* InvocationSite implements isSuperAccess() to provide additional information
* if the receiver is protected.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index 1b714e5634..1a04f46fd3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -1411,7 +1411,7 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi
return this.fields;
}
@Override
- protected MethodBinding[] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards) throws InvalidInputException {
+ protected MethodBinding[] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards, boolean filterDefaultMethods) throws InvalidInputException {
if (replaceWildcards) {
TypeBinding[] types = getNonWildcardParameterization(scope);
if (types == null)
@@ -1425,11 +1425,11 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi
if (!typeParameters[j].boundCheck(declaringType, types[j], scope, null).isOKbyJLS())
return new MethodBinding[] { new ProblemMethodBinding(TypeConstants.ANONYMOUS_METHOD, null, ProblemReasons.NotAWellFormedParameterizedType) };
}
- return declaringType.getInterfaceAbstractContracts(scope, replaceWildcards);
+ return declaringType.getInterfaceAbstractContracts(scope, replaceWildcards, filterDefaultMethods);
}
}
}
- return super.getInterfaceAbstractContracts(scope, replaceWildcards);
+ return super.getInterfaceAbstractContracts(scope, replaceWildcards, filterDefaultMethods);
}
public MethodBinding getSingleAbstractMethod(final Scope scope, boolean replaceWildcards) {
return getSingleAbstractMethod(scope, replaceWildcards, -1, -1 /* do not capture */);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index e1349570e2..bc92b9c445 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1958,7 +1958,7 @@ protected int applyCloseableInterfaceWhitelists() {
return 0;
}
-protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards) throws InvalidInputException {
+protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards, boolean filterDefaultMethods) throws InvalidInputException {
if (!isInterface() || !isValidBinding()) {
throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
@@ -1971,7 +1971,8 @@ protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean re
ReferenceBinding [] superInterfaces = superInterfaces();
for (int i = 0, length = superInterfaces.length; i < length; i++) {
- MethodBinding [] superInterfaceContracts = superInterfaces[i].getInterfaceAbstractContracts(scope, replaceWildcards);
+ // filterDefaultMethods=false => keep default methods needed to filter out any abstract methods they may override:
+ MethodBinding [] superInterfaceContracts = superInterfaces[i].getInterfaceAbstractContracts(scope, replaceWildcards, false);
final int superInterfaceContractsLength = superInterfaceContracts == null ? 0 : superInterfaceContracts.length;
if (superInterfaceContractsLength == 0) continue;
if (contractsLength < contractsCount + superInterfaceContractsLength) {
@@ -1981,6 +1982,7 @@ protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean re
contractsCount += superInterfaceContractsLength;
}
+ LookupEnvironment environment = scope.environment();
for (int i = 0, length = methods == null ? 0 : methods.length; i < length; i++) {
final MethodBinding method = methods[i];
if (method == null || method.isStatic() || method.redeclaresPublicObjectMethod(scope))
@@ -1988,7 +1990,7 @@ protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean re
if (!method.isValidBinding())
throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
for (int j = 0; j < contractsCount;) {
- if ( contracts[j] != null && MethodVerifier.doesMethodOverride(method, contracts[j], scope.environment())) {
+ if ( contracts[j] != null && MethodVerifier.doesMethodOverride(method, contracts[j], environment)) {
contractsCount--;
// abstract method from super type overridden by present interface ==> contracts[j] = null;
if (j < contractsCount) {
@@ -1998,13 +2000,46 @@ protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean re
}
j++;
}
- if (method.isDefaultMethod())
+ if (filterDefaultMethods && method.isDefaultMethod())
continue; // skip default method itself
if (contractsCount == contractsLength) {
System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength += 16], 0, contractsCount);
}
+ if(environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
+ ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(method, scope);
+ }
contracts[contractsCount++] = method;
}
+ // check mutual overriding of inherited methods (i.e., not from current type):
+ for (int i = 0; i < contractsCount; i++) {
+ MethodBinding contractI = contracts[i];
+ if (TypeBinding.equalsEquals(contractI.declaringClass, this))
+ continue;
+ for (int j = 0; j < contractsCount; j++) {
+ MethodBinding contractJ = contracts[j];
+ if (i == j || TypeBinding.equalsEquals(contractJ.declaringClass, this))
+ continue;
+ if (contractI == contractJ || MethodVerifier.doesMethodOverride(contractI, contractJ, environment)) {
+ contractsCount--;
+ // abstract method from one super type overridden by other super interface ==> contracts[j] = null;
+ if (j < contractsCount) {
+ System.arraycopy(contracts, j+1, contracts, j, contractsCount - j);
+ }
+ j--;
+ if (j < i)
+ i--;
+ continue;
+ }
+ }
+ if (filterDefaultMethods && contractI.isDefaultMethod()) {
+ contractsCount--;
+ // remove default method after it has eliminated any matching abstract methods from contracts
+ if (i < contractsCount) {
+ System.arraycopy(contracts, i+1, contracts, i, contractsCount - i);
+ }
+ i--;
+ }
+ }
if (contractsCount < contractsLength) {
System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsCount], 0, contractsCount);
}
@@ -2024,7 +2059,7 @@ public MethodBinding getSingleAbstractMethod(Scope scope, boolean replaceWildcar
scope.compilationUnitScope().recordQualifiedReference(this.compoundName);
MethodBinding[] methods = null;
try {
- methods = getInterfaceAbstractContracts(scope, replaceWildcards);
+ methods = getInterfaceAbstractContracts(scope, replaceWildcards, true);
if (methods == null || methods.length == 0)
return this.singleAbstractMethod[index] = samProblemBinding;
int contractParameterLength = 0;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 2609803dc6..4de0914a85 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -900,7 +900,9 @@ public abstract class Scope {
break;
default :
if (((ReferenceBinding) superType).isFinal()) {
- problemReporter().finalVariableBound(typeVariable, typeRef);
+ if (!environment().usesNullTypeAnnotations() || (superType.tagBits & TagBits.AnnotationNullable) == 0) {
+ problemReporter().finalVariableBound(typeVariable, typeRef);
+ }
}
break;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
index 965f055739..e01b439ea5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
@@ -79,7 +79,7 @@ public class TypeSystem {
public int hashCode() {
int hashCode = this.type.hashCode() + 13 * (this.enclosingType != null ? this.enclosingType.hashCode() : 0);
for (int i = 0, length = this.arguments == null ? 0 : this.arguments.length; i < length; i++) {
- hashCode += (i + 1) * this.arguments[i].id * this.arguments[i].hashCode();
+ hashCode += (i + 1) * this.arguments[i].hashCode();
}
return hashCode;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
index 0d4e843ac2..f0dd9b277d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
@@ -141,7 +141,7 @@ public class TypeVariableBinding extends ReferenceBinding {
return BoundCheckStatus.OK;
BoundCheckStatus nullStatus = BoundCheckStatus.OK;
- boolean checkNullAnnotations = scope.environment().usesNullTypeAnnotations();
+ boolean checkNullAnnotations = scope.environment().usesNullTypeAnnotations() && (location == null || (location.bits & ASTNode.InsideJavadoc) == 0);
if (argumentType.kind() == Binding.WILDCARD_TYPE) {
WildcardBinding wildcard = (WildcardBinding) argumentType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
index 928720a41d..862e667767 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -18,6 +18,7 @@ import java.util.Set;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
@@ -89,9 +90,16 @@ public RecoveredElement add(Statement statement, int bracketBalanceValue) {
if (statement.sourceEnd > 0)
this.alreadyCompletedFieldInitialization = true;
// else we may still be inside the initialization, having parsed only a part of it yet
- this.fieldDeclaration.initialization = (Expression)statement;
- this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd;
- this.fieldDeclaration.declarationEnd = statement.sourceEnd;
+ if (!(statement instanceof AllocationExpression) &&
+ this.fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
+ AllocationExpression alloc = new AllocationExpression();
+ alloc.arguments = new Expression[] {(Expression) statement};
+ this.fieldDeclaration.initialization = alloc;
+ } else {
+ this.fieldDeclaration.initialization = (Expression) statement;
+ this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd;
+ this.fieldDeclaration.declarationEnd = statement.sourceEnd;
+ }
return this;
}
}
@@ -242,7 +250,8 @@ public FieldDeclaration updatedFieldDeclaration(int depth, Set<TypeDeclaration>
}
}
if (this.anonymousTypeCount > 0) this.fieldDeclaration.bits |= ASTNode.HasLocalType;
- } else if(this.fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
+ }
+ else if(this.fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
// fieldDeclaration is an enum constant
for (int i = 0; i < this.anonymousTypeCount; i++){
RecoveredType recoveredType = this.anonymousTypes[i];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index a2dce63581..be15f509e3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -752,7 +752,8 @@ public static int getProblemCategory(int severity, int problemID) {
case IProblem.IsClassPathCorrect :
case IProblem.CorruptedSignature :
return CategorizedProblem.CAT_BUILDPATH;
-
+ case IProblem.ProblemNotAnalysed :
+ return CategorizedProblem.CAT_UNNECESSARY_CODE;
default :
if ((problemID & IProblem.Syntax) != 0)
return CategorizedProblem.CAT_SYNTAX;
@@ -4342,7 +4343,6 @@ public void invalidMethod(MessageSend messageSend, MethodBinding method, Scope s
return;
case ProblemReasons.InferredApplicableMethodInapplicable:
case ProblemReasons.InvocationTypeInferenceFailure:
- // FIXME(stephan): construct suitable message (https://bugs.eclipse.org/404675)
problemMethod = (ProblemMethodBinding) method;
shownMethod = problemMethod.closestMatch;
if (problemMethod.returnType == shownMethod.returnType) { //$IDENTITY-COMPARISON$
@@ -4354,8 +4354,15 @@ public void invalidMethod(MessageSend messageSend, MethodBinding method, Scope s
new String[] { typeArguments, String.valueOf(shownMethod.original().shortReadableName()) },
messageSend.sourceStart,
messageSend.sourceEnd);
+ } else {
+ // FIXME(stephan): turn into an exception once we are sure about this
+ this.handle(IProblem.GenericInferenceError,
+ new String[] { "Unknown error at invocation of "+String.valueOf(shownMethod.readableName())}, //$NON-NLS-1$
+ new String[] { "Unknown error at invocation of "+String.valueOf(shownMethod.shortReadableName())}, //$NON-NLS-1$
+ messageSend.sourceStart,
+ messageSend.sourceEnd);
}
- return; // funnily this can happen in a deeply nested call, because the inner lies by stealing its closest match and the outer does not know so. See GRT1_8.testBug430296
+ return;
}
TypeBinding shownMethodReturnType = shownMethod.returnType.capture(scope, messageSend.sourceStart, messageSend.sourceEnd);
this.handle(
@@ -9656,11 +9663,11 @@ public void referenceExpressionArgumentNullityMismatch(ReferenceExpression locat
.append(descriptorMethod.shortReadableName());
this.handle(
status.isUnchecked() ? IProblem.ReferenceExpressionParameterNullityUnchecked : IProblem.ReferenceExpressionParameterNullityMismatch,
- new String[] { String.valueOf(idx+1),
+ new String[] { idx == -1 ? "'this'" : String.valueOf(idx + 1), //$NON-NLS-1$
String.valueOf(requiredType.nullAnnotatedReadableName(this.options, false)),
String.valueOf(providedType.nullAnnotatedReadableName(this.options, false)),
methodSignature.toString() },
- new String[] { String.valueOf(idx+1),
+ new String[] { idx == -1 ? "'this'" : String.valueOf(idx + 1), //$NON-NLS-1$
String.valueOf(requiredType.nullAnnotatedReadableName(this.options, true)),
String.valueOf(providedType.nullAnnotatedReadableName(this.options, true)),
shortSignature.toString() },
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
index 1ceacdf3ec..52a6946df2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
@@ -1463,6 +1463,8 @@ public final class ImportRewrite {
private void annotateList(List annotations, IAnnotationBinding [] annotationBindings, AST ast,
ImportRewriteContext context, TypeLocation location, ITypeBinding type) {
+ if (context == null)
+ context= this.defaultContext;
annotationBindings = context.removeRedundantTypeAnnotations(annotationBindings, location, type);
for (int i = 0; i< annotationBindings.length; i++) {
Annotation annotation = addAnnotation(annotationBindings[i], ast, context);
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
index fbebe530b0..494e7ab46d 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -61,7 +61,7 @@ public CodeSnippetMessageSend(EvaluationContext evaluationContext) {
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
int pc = codeStream.position;
MethodBinding codegenBinding = this.binding.original();
- if (codegenBinding.canBeSeenBy(this.actualReceiverType, this, currentScope)) {
+ if (codegenBinding.canBeSeenBy(this.actualReceiverType.original(), this, currentScope)) {
// generate receiver/enclosing instance access
boolean isStatic = codegenBinding.isStatic();
// outer access ?
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index a442121c57..0d782c1368 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -1081,7 +1081,7 @@ public class DefaultCodeFormatterConstants {
* FORMATTER / Option to control whether comments' line length will be counted from their starting position
* - option id: "org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position"
* - possible values: { TRUE, FALSE }
- * - default: FALSE
+ * - default: TRUE
* </pre>
* @since 3.13
*/
@@ -4400,6 +4400,7 @@ public class DefaultCodeFormatterConstants {
public static Map getEclipse21Settings() {
DefaultCodeFormatterOptions options = DefaultCodeFormatterOptions.getDefaultSettings();
options.page_width = 80; // changed with bug 356841
+ options.comment_count_line_length_from_starting_position = false;
return options.getMap();
}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
index b915ae12b0..b196404f1e 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
@@ -40,7 +40,6 @@ import org.eclipse.jdt.core.dom.MemberRef;
import org.eclipse.jdt.core.dom.MethodRef;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.TagElement;
-import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
@@ -1061,8 +1060,7 @@ public class CommentsPreparator extends ASTVisitor {
// ^ index: original source position (minus startPosition), value: position in code string
getCodeToFormat(codeStartPosition, codeEndPosition, codeBuilder, positionMapping);
- List<Token> formattedTokens = getCommentCodeFormatter().prepareFormattedCode(codeBuilder.toString(),
- CodeFormatter.K_UNKNOWN);
+ List<Token> formattedTokens = getCommentCodeFormatter().prepareFormattedCode(codeBuilder.toString());
if (formattedTokens == null) {
disableFormattingExclusively(openingTagLastIndex, closingTagFirstIndex);
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
index 19ce52ba8c..683d70d384 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -25,6 +25,7 @@ import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameC
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -93,7 +94,7 @@ public class DefaultCodeFormatter extends CodeFormatter {
private String sourceString;
char[] sourceArray;
- private IRegion[] formatRegions;
+ private List<IRegion> formatRegions;
private ASTNode astRoot;
private List<Token> tokens = new ArrayList<>();
@@ -166,7 +167,7 @@ public class DefaultCodeFormatter extends CodeFormatter {
if (!regionsSatisfiesPreconditions(regions, source.length())) {
throw new IllegalArgumentException();
}
- this.formatRegions = regions;
+ this.formatRegions = Arrays.asList(regions);
updateWorkingOptions(indentationLevel, lineSeparator, kind);
@@ -177,7 +178,7 @@ public class DefaultCodeFormatter extends CodeFormatter {
return this.tokens.isEmpty() ? new MultiTextEdit() : null;
MultiTextEdit result = new MultiTextEdit();
- TextEditsBuilder resultBuilder = new TextEditsBuilder(this.sourceString, regions, this.tokenManager,
+ TextEditsBuilder resultBuilder = new TextEditsBuilder(this.sourceString, this.formatRegions, this.tokenManager,
this.workingOptions);
this.tokenManager.traverse(0, resultBuilder);
for (TextEdit edit : resultBuilder.getEdits()) {
@@ -200,7 +201,12 @@ public class DefaultCodeFormatter extends CodeFormatter {
return !this.tokens.isEmpty();
}
- List<Token> prepareFormattedCode(String source, int kind) {
+ List<Token> prepareFormattedCode(String source) {
+ this.formatRegions = Arrays.asList(new Region(0, source.length()));
+ return prepareFormattedCode(source, CodeFormatter.K_UNKNOWN);
+ }
+
+ private List<Token> prepareFormattedCode(String source, int kind) {
if (!init(source, kind))
return null;
@@ -216,8 +222,6 @@ public class DefaultCodeFormatter extends CodeFormatter {
prepareComments();
prepareWraps(kind);
- this.tokenManager.applyFormatOff();
-
return this.tokens;
}
@@ -282,7 +286,7 @@ public class DefaultCodeFormatter extends CodeFormatter {
throw new AssertionError(String.valueOf(kind));
}
- this.tokenManager.applyFormatOff();
+ applyFormatOff();
TextEditsBuilder resultBuilder = new TextEditsBuilder(source, this.formatRegions, this.tokenManager,
this.workingOptions);
@@ -400,9 +404,37 @@ public class DefaultCodeFormatter extends CodeFormatter {
private void prepareWraps(int kind) {
WrapPreparator wrapPreparator = new WrapPreparator(this.tokenManager, this.workingOptions, kind);
this.astRoot.accept(wrapPreparator);
+ applyFormatOff();
wrapPreparator.finishUp(this.astRoot, this.formatRegions);
}
+ private void applyFormatOff() {
+ for (Token[] offPair : this.tokenManager.getDisableFormatTokenPairs()) {
+ final int offStart = offPair[0].originalStart;
+ final int offEnd = offPair[1].originalEnd;
+
+ offPair[0].setWrapPolicy(null);
+ offPair[0]
+ .setIndent(Math.min(offPair[0].getIndent(), this.tokenManager.findSourcePositionInLine(offStart)));
+
+ final List<IRegion> result = new ArrayList<>();
+ for (IRegion region : this.formatRegions) {
+ final int start = region.getOffset(), end = region.getOffset() + region.getLength() - 1;
+ if (offEnd < start || end < offStart) {
+ result.add(region);
+ } else if (offStart <= start && end <= offEnd) {
+ // whole region off
+ } else {
+ if (start < offStart)
+ result.add(new Region(start, offStart - start));
+ if (offEnd < end)
+ result.add(new Region(offEnd + 1, end - offEnd));
+ }
+ }
+ this.formatRegions = result;
+ }
+ }
+
/**
* True if
* <li>1. All regions are within maxLength
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
index 5120ed4145..c38b76dbe4 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
@@ -2491,7 +2491,7 @@ public class DefaultCodeFormatterOptions {
this.comment_new_lines_at_block_boundaries = true;
this.comment_new_lines_at_javadoc_boundaries = true;
this.comment_line_length = 80;
- this.comment_count_line_length_from_starting_position = false;
+ this.comment_count_line_length_from_starting_position = true;
this.comment_preserve_white_space_between_code_and_line_comments= false;
this.continuation_indentation = 2;
this.continuation_indentation_for_array_initializer = 2;
@@ -2802,7 +2802,7 @@ public class DefaultCodeFormatterOptions {
this.comment_new_lines_at_block_boundaries = true;
this.comment_new_lines_at_javadoc_boundaries = true;
this.comment_line_length = 80;
- this.comment_count_line_length_from_starting_position = false;
+ this.comment_count_line_length_from_starting_position = true;
this.comment_preserve_white_space_between_code_and_line_comments= false;
this.continuation_indentation = 2;
this.continuation_indentation_for_array_initializer = 2;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
index 04fec25f21..c47d13d7e8 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
@@ -35,7 +35,6 @@ import org.eclipse.text.edits.TextEdit;
public class TextEditsBuilder extends TokenTraverser {
private final String source;
- private List<IRegion> regions;
private TokenManager tm;
private final DefaultCodeFormatterOptions options;
private final StringBuilder buffer;
@@ -43,6 +42,7 @@ public class TextEditsBuilder extends TokenTraverser {
private final List<Token> stringLiteralsInLine = new ArrayList<Token>();
private final List<TextEdit> edits = new ArrayList<TextEdit>();
+ private final List<IRegion> regions;
private int currentRegion = 0;
private TextEditsBuilder childBuilder;
@@ -51,7 +51,7 @@ public class TextEditsBuilder extends TokenTraverser {
private int sourceLimit;
private int parentTokenIndex;
- public TextEditsBuilder(String source, IRegion[] regions, TokenManager tokenManager,
+ public TextEditsBuilder(String source, List<IRegion> regions, TokenManager tokenManager,
DefaultCodeFormatterOptions options) {
this.source = source;
this.tm = tokenManager;
@@ -74,9 +74,7 @@ public class TextEditsBuilder extends TokenTraverser {
this.alignChar = DefaultCodeFormatterOptions.SPACE;
}
- private List<IRegion> adaptRegions(IRegion[] givenRegions) {
- if (givenRegions == null)
- return null;
+ private List<IRegion> adaptRegions(List<IRegion> givenRegions) {
// make sure regions don't begin or end inside multiline comments
ArrayList<IRegion> result = new ArrayList<IRegion>();
IRegion previous = null;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
index 2dee8f9814..cfc64f2f74 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
@@ -15,7 +15,6 @@ import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameC
import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLBRACE;
import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameNotAToken;
import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameStringLiteral;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameWHITESPACE;
import java.util.ArrayList;
import java.util.HashMap;
@@ -49,7 +48,7 @@ public class TokenManager implements Iterable<Token> {
final CommentWrapExecutor commentWrapper;
private HashMap<Integer, Integer> tokenIndexToNLSAlign;
- private List<Token[]> formatOffTagPairs;
+ private List<Token[]> formatOffTagPairs = new ArrayList<>();
private int headerEndIndex = 0;
public TokenManager(List<Token> tokens, String source, DefaultCodeFormatterOptions options) {
@@ -430,29 +429,10 @@ public class TokenManager implements Iterable<Token> {
}
public void addDisableFormatTokenPair(Token formatOffTag, Token formatOnTag) {
- if (this.formatOffTagPairs == null)
- this.formatOffTagPairs = new ArrayList<Token[]>();
this.formatOffTagPairs.add(new Token[] { formatOffTag, formatOnTag });
}
- public void applyFormatOff() {
- if (this.formatOffTagPairs == null)
- return;
- for (Token[] pair : this.formatOffTagPairs) {
- int index1 = findIndex(pair[0].originalStart, -1, false);
- int index2 = findIndex(pair[1].originalEnd, -1, false);
- pair[0] = get(index1);
- pair[1] = get(index2);
- Token unformatted = new Token(pair[0].originalStart, pair[1].originalEnd, TokenNameWHITESPACE);
- unformatted.setIndent(Math.min(pair[0].getIndent(), findSourcePositionInLine(pair[0].originalStart)));
- unformatted.putLineBreaksBefore(pair[0].getLineBreaksBefore());
- if (pair[0].isSpaceBefore())
- unformatted.spaceBefore();
- unformatted.putLineBreaksAfter(pair[1].getLineBreaksAfter());
- if (pair[1].isSpaceAfter())
- unformatted.spaceAfter();
- this.tokens.set(index1, unformatted);
- this.tokens.subList(index1 + 1, index2 + 1).clear();
- }
+ public List<Token[]> getDisableFormatTokenPairs() {
+ return this.formatOffTagPairs;
}
}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
index 16d1fbaabd..38a5605a06 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
@@ -641,13 +641,6 @@ public class WrapExecutor {
if (policy == null)
return token.getIndent();
- if (this.options.never_indent_line_comments_on_first_column && token.tokenType == TokenNameCOMMENT_LINE
- && token.getIndent() == 0)
- return 0;
- if (this.options.never_indent_block_comments_on_first_column && token.tokenType == TokenNameCOMMENT_BLOCK
- && token.getIndent() == 0)
- return 0;
-
Token wrapParent = this.tm.get(policy.wrapParentIndex);
int wrapIndent = wrapParent.getIndent();
if (policy.indentOnColumn) {
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
index 41a5cdf8a0..5daa0d1005 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
@@ -940,6 +940,12 @@ public class WrapPreparator extends ASTVisitor {
Token previous = this.tm.get(i);
if (!previous.isComment())
break;
+ if (this.options.never_indent_line_comments_on_first_column
+ && previous.tokenType == TokenNameCOMMENT_LINE && previous.getIndent() == 0)
+ break;
+ if (this.options.never_indent_block_comments_on_first_column
+ && previous.tokenType == TokenNameCOMMENT_BLOCK && previous.getIndent() == 0)
+ break;
if (previous.getLineBreaksAfter() == 0 && i == index - 1)
index = i;
if (previous.getLineBreaksBefore() > 0)
@@ -1022,10 +1028,9 @@ public class WrapPreparator extends ASTVisitor {
penaltyMultiplier, isFirst, indentOnColumn);
}
- public void finishUp(ASTNode astRoot, IRegion[] regions) {
+ public void finishUp(ASTNode astRoot, List<IRegion> regions) {
preserveExistingLineBreaks();
- if (regions != null)
- applyBreaksOutsideRegions(regions);
+ applyBreaksOutsideRegions(regions);
new WrapExecutor(this.tm, this.options).executeWraps();
this.fieldAligner.alignComments();
wrapComments();
@@ -1086,7 +1091,7 @@ public class WrapPreparator extends ASTVisitor {
return Math.min(lineBreaks, toPreserve);
}
- private void applyBreaksOutsideRegions(IRegion[] regions) {
+ private void applyBreaksOutsideRegions(List<IRegion> regions) {
String source = this.tm.getSource();
int previousRegionEnd = 0;
for (IRegion region : regions) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index f4db023aeb..44a8946f99 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -4707,10 +4707,10 @@ public final class JavaCore extends Plugin {
} else if (containerPath.segmentCount() < 1) {
throw new ClasspathEntry.AssertionFailedException("Illegal classpath container path: \'" + containerPath.makeRelative().toString() + "\', must have at least one segment (containerID+hints)"); //$NON-NLS-1$//$NON-NLS-2$
}
- if (accessRules == null) {
+ if (accessRules == null || accessRules.length == 0) {
accessRules = ClasspathEntry.NO_ACCESS_RULES;
}
- if (extraAttributes == null) {
+ if (extraAttributes == null || extraAttributes.length == 0) {
extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
}
return new ClasspathEntry(
@@ -4906,10 +4906,10 @@ public final class JavaCore extends Plugin {
boolean isExported) {
if (path == null) throw new ClasspathEntry.AssertionFailedException("Library path cannot be null"); //$NON-NLS-1$
- if (accessRules == null) {
+ if (accessRules == null || accessRules.length==0) {
accessRules = ClasspathEntry.NO_ACCESS_RULES;
}
- if (extraAttributes == null) {
+ if (extraAttributes == null || extraAttributes.length==0) {
extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
}
boolean hasDotDot = ClasspathEntry.hasDotDot(path);
@@ -5037,10 +5037,10 @@ public final class JavaCore extends Plugin {
boolean isExported) {
if (!path.isAbsolute()) throw new ClasspathEntry.AssertionFailedException("Path for IClasspathEntry must be absolute"); //$NON-NLS-1$
- if (accessRules == null) {
+ if (accessRules == null || accessRules.length == 0) {
accessRules = ClasspathEntry.NO_ACCESS_RULES;
}
- if (extraAttributes == null) {
+ if (extraAttributes == null || extraAttributes.length == 0) {
extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
}
return new ClasspathEntry(
@@ -5401,10 +5401,10 @@ public final class JavaCore extends Plugin {
if (variablePath.segmentCount() < 1) {
throw new ClasspathEntry.AssertionFailedException("Illegal classpath variable path: \'" + variablePath.makeRelative().toString() + "\', must have at least one segment"); //$NON-NLS-1$//$NON-NLS-2$
}
- if (accessRules == null) {
+ if (accessRules == null || accessRules.length == 0) {
accessRules = ClasspathEntry.NO_ACCESS_RULES;
}
- if (extraAttributes == null) {
+ if (extraAttributes == null || extraAttributes.length == 0) {
extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
}
@@ -5533,7 +5533,8 @@ public final class JavaCore extends Plugin {
}
/**
- * Deletes and rebuilds the java index.
+ * Deletes the index, then rebuilds any portions of the index that are
+ * currently needed by the workspace.
*
* @param monitor a progress monitor, or <code>null</code> if progress
* reporting and cancellation are not desired
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
index 204fd8c462..e3e7414b17 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -327,7 +327,7 @@ public class ClasspathEntry implements IClasspathEntry {
// }
this.combineAccessRules = combineAccessRules;
- this.extraAttributes = extraAttributes;
+ this.extraAttributes = extraAttributes.length > 0 ? extraAttributes : NO_EXTRA_ATTRIBUTES;
if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
this.fullInclusionPatternChars = UNINIT_PATTERNS;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
index 9064454af3..fdfb9ad6f0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -1145,39 +1145,43 @@ protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelE
// synchronize to ensure that 2 threads are not putting 2 different buffers at the same time
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146331
+ IBuffer existingBuffer;
synchronized(bufManager) {
- IBuffer existingBuffer = bufManager.getBuffer(this);
- if (existingBuffer != null)
- return existingBuffer;
-
- // set the buffer source
- if (buffer.getCharacters() == null) {
- if (isWorkingCopy) {
- if (mustSetToOriginalContent) {
- buffer.setContents(original.getSource());
- } else {
- IFile file = (IFile)getResource();
- if (file == null || !file.exists()) {
- // initialize buffer with empty contents
- buffer.setContents(CharOperation.NO_CHAR);
+ existingBuffer = bufManager.getBuffer(this);
+ if (existingBuffer == null) {
+ // set the buffer source
+ if (buffer.getCharacters() == null) {
+ if (isWorkingCopy) {
+ if (mustSetToOriginalContent) {
+ buffer.setContents(original.getSource());
} else {
- buffer.setContents(Util.getResourceContentsAsCharArray(file));
+ IFile file = (IFile)getResource();
+ if (file == null || !file.exists()) {
+ // initialize buffer with empty contents
+ buffer.setContents(CharOperation.NO_CHAR);
+ } else {
+ buffer.setContents(Util.getResourceContentsAsCharArray(file));
+ }
}
+ } else {
+ IFile file = (IFile)getResource();
+ if (file == null || !file.exists()) throw newNotPresentException();
+ buffer.setContents(Util.getResourceContentsAsCharArray(file));
}
- } else {
- IFile file = (IFile)getResource();
- if (file == null || !file.exists()) throw newNotPresentException();
- buffer.setContents(Util.getResourceContentsAsCharArray(file));
}
+
+ // add buffer to buffer cache
+ // note this may cause existing buffers to be removed from the buffer cache, but only primary compilation unit's buffer
+ // can be closed, thus no call to a client's IBuffer#close() can be done in this synchronized block.
+ bufManager.addBuffer(buffer);
+
+ // listen to buffer changes
+ buffer.addBufferChangedListener(this);
}
-
- // add buffer to buffer cache
- // note this may cause existing buffers to be removed from the buffer cache, but only primary compilation unit's buffer
- // can be closed, thus no call to a client's IBuffer#close() can be done in this synchronized block.
- bufManager.addBuffer(buffer);
-
- // listen to buffer changes
- buffer.addBufferChangedListener(this);
+ }
+ if(existingBuffer != null) {
+ buffer.close();
+ return existingBuffer;
}
return buffer;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
index 8388c820ce..24cbbe0e2b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
@@ -19,6 +19,7 @@ import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.core.nd.db.ChunkCache;
+import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
/**
* JavaCore eclipse preferences initializer.
@@ -40,6 +41,13 @@ public class JavaCorePreferenceInitializer extends AbstractPreferenceInitializer
// Compiler settings
Map defaultOptionsMap = new CompilerOptions().getMap(); // compiler defaults
+ String testDefaults = System.getProperty("jdt.default.test.compliance"); //$NON-NLS-1$
+ if (testDefaults != null) {
+ defaultOptionsMap.put(JavaCore.COMPILER_SOURCE, testDefaults);
+ defaultOptionsMap.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, testDefaults);
+ defaultOptionsMap.put(JavaCore.COMPILER_COMPLIANCE, testDefaults);
+ }
+
// Override some compiler defaults
defaultOptionsMap.put(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, JavaCore.GENERATE);
defaultOptionsMap.put(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL, JavaCore.PRESERVE);
@@ -100,6 +108,8 @@ public class JavaCorePreferenceInitializer extends AbstractPreferenceInitializer
defaultOptionsMap.put(ChunkCache.CHUNK_CACHE_SIZE_MB, Double.toString(ChunkCache.CHUNK_CACHE_SIZE_MB_DEFAULT));
defaultOptionsMap.put(ChunkCache.CHUNK_CACHE_SIZE_PERCENT,
Double.toString(ChunkCache.CHUNK_CACHE_SIZE_PERCENT_DEFAULT));
+ defaultOptionsMap.put(JavaIndex.ENABLE_NEW_JAVA_INDEX,
+ Boolean.toString(JavaIndex.ENABLE_NEW_JAVA_INDEX_DEFAULT));
// Time out for parameter names
defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index bcad047348..757abde4f0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -372,14 +372,16 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
private static final String SEARCH_DEBUG = JavaCore.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$
private static final String SOURCE_MAPPER_DEBUG_VERBOSE = JavaCore.PLUGIN_ID + "/debug/sourcemapper" ; //$NON-NLS-1$
private static final String FORMATTER_DEBUG = JavaCore.PLUGIN_ID + "/debug/formatter" ; //$NON-NLS-1$
- private static final String INDEX_DEBUG_LARGE_CHUNKS = JavaCore.PLUGIN_ID + "/debug/index/largechunks" ; //$NON-NLS-1$
+ private static final String INDEX_DEBUG_LARGE_CHUNKS = JavaCore.PLUGIN_ID + "/debug/index/freespacetest" ; //$NON-NLS-1$
private static final String INDEX_DEBUG_PAGE_CACHE = JavaCore.PLUGIN_ID + "/debug/index/pagecache" ; //$NON-NLS-1$
private static final String INDEX_INDEXER_DEBUG = JavaCore.PLUGIN_ID + "/debug/index/indexer" ; //$NON-NLS-1$
private static final String INDEX_INDEXER_INSERTIONS = JavaCore.PLUGIN_ID + "/debug/index/insertions" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_SCHEDULING = JavaCore.PLUGIN_ID + "/debug/index/scheduling" ; //$NON-NLS-1$
private static final String INDEX_INDEXER_SELFTEST = JavaCore.PLUGIN_ID + "/debug/index/selftest" ; //$NON-NLS-1$
private static final String INDEX_LOCKS_DEBUG = JavaCore.PLUGIN_ID + "/debug/index/locks" ; //$NON-NLS-1$
private static final String INDEX_INDEXER_SPACE = JavaCore.PLUGIN_ID + "/debug/index/space" ; //$NON-NLS-1$
private static final String INDEX_INDEXER_TIMING = JavaCore.PLUGIN_ID + "/debug/index/timing" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_LOG_SIZE_MEGS = JavaCore.PLUGIN_ID + "/debug/index/logsizemegs"; //$NON-NLS-1$
public static final String COMPLETION_PERF = JavaCore.PLUGIN_ID + "/perf/completion" ; //$NON-NLS-1$
public static final String SELECTION_PERF = JavaCore.PLUGIN_ID + "/perf/selection" ; //$NON-NLS-1$
@@ -1855,13 +1857,15 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
JavaModelManager.ZIP_ACCESS_VERBOSE = debug && options.getBooleanOption(ZIP_ACCESS_DEBUG, false);
SourceMapper.VERBOSE = debug && options.getBooleanOption(SOURCE_MAPPER_DEBUG_VERBOSE, false);
DefaultCodeFormatter.DEBUG = debug && options.getBooleanOption(FORMATTER_DEBUG, false);
- Database.DEBUG_LARGE_CHUNKS = debug && options.getBooleanOption(INDEX_DEBUG_LARGE_CHUNKS, false);
+ Database.DEBUG_FREE_SPACE = debug && options.getBooleanOption(INDEX_DEBUG_LARGE_CHUNKS, false);
Database.DEBUG_PAGE_CACHE = debug && options.getBooleanOption(INDEX_DEBUG_PAGE_CACHE, false);
Indexer.DEBUG = debug && options.getBooleanOption(INDEX_INDEXER_DEBUG, false);
Indexer.DEBUG_INSERTIONS = debug && options.getBooleanOption(INDEX_INDEXER_INSERTIONS, false);
Indexer.DEBUG_ALLOCATIONS = debug && options.getBooleanOption(INDEX_INDEXER_SPACE, false);
Indexer.DEBUG_TIMING = debug && options.getBooleanOption(INDEX_INDEXER_TIMING, false);
+ Indexer.DEBUG_SCHEDULING = debug && options.getBooleanOption(INDEX_INDEXER_SCHEDULING, false);
Indexer.DEBUG_SELFTEST = debug && options.getBooleanOption(INDEX_INDEXER_SELFTEST, false);
+ Indexer.DEBUG_LOG_SIZE_MB = debug ? options.getIntegerOption(INDEX_INDEXER_LOG_SIZE_MEGS, 0) : 0;
Nd.sDEBUG_LOCKS = debug && options.getBooleanOption(INDEX_LOCKS_DEBUG, false);
// configure performance options
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java
index c65a7e569e..5973987cf9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2016 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -96,8 +96,10 @@ public abstract class NamedMember extends Member {
// selector
key.append('.');
- String selector = method.getElementName();
- key.append(selector);
+ if (!method.isConstructor()) { // empty selector for ctors, cf. BindingKeyResolver.consumeMethod()
+ String selector = method.getElementName();
+ key.append(selector);
+ }
// type parameters
if (forceOpen) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java
index c47fd85d0e..fce7e7491a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -368,7 +368,8 @@ public class ChangeCollector {
private void getAllTypesFromHierarchy(JavaElement element, ArrayList allTypes) {
switch (element.getElementType()) {
case IJavaElement.COMPILATION_UNIT:
- ArrayList types = this.hierarchy.files.get(element);
+ IOpenable o = (IOpenable) element;
+ ArrayList types = this.hierarchy.files.get(o);
if (types != null) {
allTypes.addAll(types);
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
index aefb34182f..43aa70c540 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
@@ -1042,7 +1042,8 @@ protected boolean isAffectedByOpenable(IJavaElementDelta delta, IJavaElement ele
} else if (element instanceof ClassFile) {
switch (delta.getKind()) {
case IJavaElementDelta.REMOVED:
- return this.files.get(element) != null;
+ IOpenable o = (IOpenable) element;
+ return this.files.get(o) != null;
case IJavaElementDelta.ADDED:
IType type = ((ClassFile)element).getType();
String typeName = type.getElementName();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java
deleted file mode 100644
index ef24eb6fbe..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdNode.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd;
-
-import org.eclipse.jdt.internal.core.nd.db.IndexException;
-
-/**
- * Interface for all nodes that can be visited by a {@link INdVisitor}.
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
- */
-public interface INdNode {
-
- /**
- * Visits the children of this node.
- */
- public void accept(INdVisitor visitor) throws IndexException;
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java
new file mode 100644
index 0000000000..909fd562ce
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdStruct.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd;
+
+/**
+ * Implementations of this interface wrap content in the database as a java object.
+ * All such objects have an address and a pointer to the database.
+ */
+public interface INdStruct {
+ /**
+ * Returns the database address at which the struct begins.
+ */
+ public long getAddress();
+
+ /**
+ * Returns the database backing this struct.
+ */
+ public Nd getNd();
+
+ /**
+ * Given a nullable {@link INdStruct}, this returns the address of the struct
+ * or 0 if the object was null.
+ */
+ static long addressOf(INdStruct nullable) {
+ if (nullable == null) {
+ return 0;
+ }
+ return nullable.getAddress();
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java
deleted file mode 100644
index 034e233021..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/INdVisitor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd;
-
-import org.eclipse.core.runtime.CoreException;
-
-public interface INdVisitor {
-
- /**
- * Walk the nodes in a {@link Nd}. Return true to visit the children of
- * this node, or false to skip to the next sibling of this node.
- * Throw CoreException to stop the visit.
- *
- * @param node being visited
- * @return whether to visit children
- */
- public boolean visit(INdNode node) throws CoreException;
-
- /**
- * All children have been visited, about to go back to the parent.
- *
- * @param node that has just completed visitation
- * @throws CoreException
- */
- public void leave(INdNode node) throws CoreException;
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java
new file mode 100644
index 0000000000..7994234d9a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.MemoryAccessLog;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.IndexException;
+import org.eclipse.jdt.internal.core.nd.db.RelatedAddress;
+import org.eclipse.jdt.internal.core.nd.field.IField;
+
+/**
+ * Given a set of memory ranges, this class constructs detailed error messages.
+ */
+public final class IndexExceptionBuilder {
+ private final Database db;
+ private final List<RelatedAddress> relatedAddresses = new ArrayList<>();
+
+ /**
+ * Constructs a new {@link IndexExceptionBuilder}
+ */
+ public IndexExceptionBuilder(Database db) {
+ this.db = db;
+ }
+
+ /**
+ * Adds an address range to this problem description, given the first address that may be corrupt,
+ * the size of the possibly-corrupt address range, and a custom description for the memory at this
+ * address range.
+ */
+ public IndexExceptionBuilder addProblemAddress(String description, long dataBlockAddress, int rangeSize) {
+ MemoryAccessLog lastWrite = this.db.getLog().getReportFor(dataBlockAddress, rangeSize);
+ this.relatedAddresses.add(new RelatedAddress(description, dataBlockAddress, rangeSize, lastWrite));
+ return this;
+ }
+
+ /**
+ * Adds an address range to this problem description, given a field that may be corrupt, the base
+ * address for its struct, and a custom description for the field.
+ *
+ * @return this
+ */
+ public IndexExceptionBuilder addProblemAddress(String description, IField field, long address) {
+ long offset = field.getOffset();
+ int size = field.getRecordSize();
+ return addProblemAddress(description, address + offset, size);
+ }
+
+ /**
+ * Adds an address range to this problem description, given the field that may be corrupt
+ * and the base address for its struct.
+ *
+ * @return this
+ */
+ public IndexExceptionBuilder addProblemAddress(IField field, long address) {
+ return addProblemAddress(field.getFieldName(), field, address);
+ }
+
+ /**
+ * Returns a newly constructed {@link IndexException} containing the given message and all the addresses collected
+ * by this object.
+ */
+ public IndexException build(String description) {
+ IndexException toThrow = new IndexException(description);
+ if (this.db.getLog().enabled()) {
+ toThrow.setTime(this.db.getLog().getWriteCount());
+ }
+ attachTo(toThrow);
+ return toThrow;
+ }
+
+ /**
+ * Attaches the addresses collected by the receiver to the given exception.
+ */
+ public void attachTo(IndexException exception) {
+ for (RelatedAddress next : this.relatedAddresses) {
+ exception.addRelatedAddress(next);
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
index e4f477b0b3..a8acff19f7 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
@@ -215,20 +215,19 @@ public final class Nd {
private void loadDatabase(File dbPath, ChunkCache cache) throws IndexException {
this.fPath= dbPath;
- final boolean lockDB= this.db == null || this.lockCount != 0;
clearCaches();
this.db = new Database(this.fPath, cache, getDefaultVersion(), isPermanentlyReadOnly());
-
- this.db.setLocked(lockDB);
+ this.db.setExclusiveLock();
if (!isSupportedVersion()) {
Package.logInfo("Index database uses the unsupported version " + this.db.getVersion() //$NON-NLS-1$
+ ". Deleting and recreating."); //$NON-NLS-1$
this.db.close();
this.fPath.delete();
this.db = new Database(this.fPath, cache, getDefaultVersion(), isPermanentlyReadOnly());
- this.db.setLocked(lockDB);
+ this.db.setExclusiveLock();
}
+ this.db.giveUpExclusiveLock();
this.fWriteNumber = this.db.getLong(Database.WRITE_NUMBER_OFFSET);
this.db.setLocked(this.lockCount != 0);
}
@@ -651,7 +650,7 @@ public final class Nd {
/**
* Returns the type ID for the given class
*/
- public short getNodeType(Class<? extends NdNode> toQuery) {
+ public short getNodeType(Class<?> toQuery) {
return this.fNodeTypeRegistry.getTypeForClass(toQuery);
}
@@ -707,4 +706,12 @@ public final class Nd {
public boolean isValidAddress(long address) {
return address > 0 && address < (long) getDB().getChunkCount() * Database.CHUNK_SIZE;
}
+
+ /**
+ * Creates a {@link IndexExceptionBuilder} object that collects information about database corruption after it is
+ * detected.
+ */
+ public IndexExceptionBuilder describeProblem() {
+ return this.db.describeProblem();
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java
index 2fc229cd15..ddf646e6ed 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNode.java
@@ -16,29 +16,22 @@ import org.eclipse.jdt.internal.core.nd.field.FieldShort;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
/**
- * This is a basic node in the network database.
+ * This is a basic polymorphic node in the network database. Pointers to NdNode or any of their
+ * subclasses will be resolved to the correct subclass of NdNode such that the correct version of an
+ * overloaded method will be invoked.
*/
-public abstract class NdNode implements IDestructable {
+public abstract class NdNode extends NdStruct implements IDestructable {
public static final FieldShort NODE_TYPE;
+ @SuppressWarnings("hiding")
public static final StructDef<NdNode> type;
static {
- type = StructDef.create(NdNode.class);
+ type = StructDef.create(NdNode.class, NdStruct.type);
NODE_TYPE = type.addShort();
type.done();
}
- public final long address;
- private Nd nd;
-
- public static long addressOf(NdNode nullable) {
- if (nullable == null) {
- return 0;
- }
- return nullable.address;
- }
-
/**
* Load a node from the specified address in the given database. Return null if a node cannot
* be loaded.
@@ -53,23 +46,40 @@ public abstract class NdNode implements IDestructable {
return null;
}
- return nd.getNode(address, NODE_TYPE.get(nd, address));
+ try {
+ return nd.getNode(address, NODE_TYPE.get(nd, address));
+ } catch (IndexException e) {
+ // Add metadata to the exception describing where we obtained the node type from
+ nd.describeProblem().addProblemAddress(NODE_TYPE, address).attachTo(e);
+ throw e;
+ }
}
@SuppressWarnings("unchecked")
- public static <T extends NdNode> T load(Nd nd, long address, Class<T> clazz) {
+ public static <T extends INdStruct> T load(Nd nd, long address, StructDef<T> typeToLoad) {
if (address == 0) {
return null;
}
- NdNode result = nd.getNode(address, NODE_TYPE.get(nd, address));
+ NdNode result;
+ try {
+ // Polymorphic types (that subclass NdNode) store a header with their type ID
+ result = nd.getNode(address, NODE_TYPE.get(nd, address));
+ } catch (IndexException e) {
+ // Add metadata to the exception describing where we obtained the node type from
+ nd.describeProblem().addProblemAddress(NODE_TYPE, address).attachTo(e);
+ throw e;
+ }
+ Class<T> clazz = typeToLoad.getStructClass();
if (!clazz.isAssignableFrom(result.getClass())) {
- throw new IndexException("Found wrong data type at address " + address + ". Expected a subclass of " + //$NON-NLS-1$//$NON-NLS-2$
+ throw nd.describeProblem()
+ .addProblemAddress(NODE_TYPE, address)
+ .build("Found wrong data type at address " + address + ". Expected a subclass of " + //$NON-NLS-1$//$NON-NLS-2$
clazz + " but found " + result.getClass()); //$NON-NLS-1$
}
- return (T)result;
+ return (T) result;
}
/**
@@ -80,13 +90,12 @@ public abstract class NdNode implements IDestructable {
}
protected NdNode(Nd nd, long address) {
- this.nd = nd;
- this.address = address;
+ super(nd, address);
}
protected NdNode(Nd nd) {
+ super(nd, 0);
Database db = nd.getDB();
- this.nd = nd;
short nodeType = nd.getNodeType(getClass());
ITypeFactory<? extends NdNode> factory1 = nd.getTypeFactory(nodeType);
@@ -96,14 +105,6 @@ public abstract class NdNode implements IDestructable {
NODE_TYPE.put(nd, this.address, nodeType);
}
- protected Database getDB() {
- return this.nd.getDB();
- }
-
- public final Nd getNd() {
- return this.nd;
- }
-
/**
* Return a value to uniquely identify the node within the factory that is responsible for loading
* instances of this node from the {@link Nd}.
@@ -138,10 +139,6 @@ public abstract class NdNode implements IDestructable {
return (int) (this.address >> Database.BLOCK_SIZE_DELTA_BITS);
}
- public void accept(INdVisitor visitor) {
- // No children here.
- }
-
/**
* Return an value to globally identify the given node within the given linkage. This value
* can be used for comparison with other {@link NdNode}s.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java
index 20b31b600e..12c2fd72e8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdNodeTypeRegistry.java
@@ -36,7 +36,7 @@ public class NdNodeTypeRegistry<R> {
short shortTypeId = (short)typeId;
String fullyQualifiedClassName = toRegister.getElementClass().getName();
- if (this.types.containsKey(typeId) || this.reserved.get(typeId)) {
+ if (this.types.containsKey(shortTypeId) || this.reserved.get(typeId)) {
throw new IllegalArgumentException(
"The type id " + typeId + " for class " + fullyQualifiedClassName + " is already in use."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@@ -75,7 +75,11 @@ public class NdNodeTypeRegistry<R> {
return typeFactory.create(nd, address);
}
- public short getTypeForClass(Class<? extends R> toQuery) {
+ public boolean isRegisteredClass(Class<?> toQuery) {
+ return this.registeredClasses.containsKey(toQuery);
+ }
+
+ public short getTypeForClass(Class<?> toQuery) {
Short classId = this.registeredClasses.get(toQuery);
if (classId == null) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java
new file mode 100644
index 0000000000..5bdec2ab78
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/NdStruct.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd;
+
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+/**
+ * Base class for standard implementations of {@link INdStruct}. Holds the address of the struct
+ * and the pointer to the database.
+ */
+public class NdStruct implements INdStruct {
+ public long address;
+ protected final Nd nd;
+
+ public static final StructDef<NdStruct> type;
+
+ static {
+ type = StructDef.createAbstract(NdStruct.class);
+ type.done();
+ }
+
+ protected NdStruct(Nd nd, long address) {
+ this.nd = nd;
+ this.address = address;
+ }
+
+ @Override
+ public long getAddress() {
+ return this.address;
+ }
+
+ @Override
+ public Nd getNd() {
+ return this.nd;
+ }
+
+ protected final Database getDB() {
+ return this.nd.getDB();
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
index 93b4e6f3ad..67117526e7 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
@@ -16,6 +16,7 @@ import org.eclipse.jdt.internal.core.nd.field.FieldInt;
import org.eclipse.jdt.internal.core.nd.field.FieldPointer;
import org.eclipse.jdt.internal.core.nd.field.FieldShort;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.nd.util.MathUtils;
/**
* Implements a growable array of pointers that supports constant-time insertions and removals. Items are inserted at
@@ -204,10 +205,17 @@ public final class RawGrowableArray {
int insertionIndex = size(nd, address);
int newSize = insertionIndex + 1;
- ensureCapacity(nd, address, newSize);
- long recordAddress = getAddressOfRecord(nd, address, insertionIndex);
- db.putRecPtr(recordAddress, value);
- setSize(nd, address, newSize);
+ try {
+ ensureCapacity(nd, address, newSize);
+ long recordAddress = getAddressOfRecord(nd, address, insertionIndex);
+ db.putRecPtr(recordAddress, value);
+ setSize(nd, address, newSize);
+ } catch (IndexException e) {
+ IndexExceptionBuilder descriptor = nd.describeProblem();
+ addSizeTo(nd, address, descriptor);
+ descriptor.attachTo(e);
+ throw e;
+ }
return insertionIndex;
}
@@ -378,7 +386,12 @@ public final class RawGrowableArray {
// We use reads of 1 past the end of the array to handle insertions.
if (index > size) {
- throw new IndexException(
+ IndexExceptionBuilder builder = nd.describeProblem();
+
+ addSizeTo(nd, address, builder);
+
+ builder.addProblemAddress(GROWABLE_BLOCK_ADDRESS, address);
+ throw builder.build(
"Record index " + index + " out of range. Array contains " + size + " elements"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@@ -390,8 +403,15 @@ public final class RawGrowableArray {
int blockRelativeIndex = growableBlockRelativeIndex % GrowableBlockHeader.MAX_GROWABLE_SIZE;
int block = growableBlockRelativeIndex / GrowableBlockHeader.MAX_GROWABLE_SIZE;
- growableBlockAddress = db.getRecPtr(growableBlockAddress + MetaBlockHeader.META_BLOCK_HEADER_BYTES
- + block * Database.PTR_SIZE);
+ long dataBlockAddress = growableBlockAddress + MetaBlockHeader.META_BLOCK_HEADER_BYTES
+ + block * Database.PTR_SIZE;
+ growableBlockAddress = db.getRecPtr(dataBlockAddress);
+ if (growableBlockAddress == 0) {
+ throw nd.describeProblem()
+ .addProblemAddress("backpointer number " + block, dataBlockAddress, Database.PTR_SIZE) //$NON-NLS-1$
+ .addProblemAddress(GROWABLE_BLOCK_ADDRESS, address)
+ .build("Null data block found in metablock"); //$NON-NLS-1$
+ }
growableBlockRelativeIndex = blockRelativeIndex;
}
@@ -403,6 +423,13 @@ public final class RawGrowableArray {
}
}
+ private void addSizeTo(Nd nd, long address, IndexExceptionBuilder builder) {
+ long growableBlockAddress = GROWABLE_BLOCK_ADDRESS.get(nd, address);
+ if (growableBlockAddress != 0) {
+ builder.addProblemAddress(GrowableBlockHeader.ARRAY_SIZE, growableBlockAddress);
+ }
+ }
+
/**
* Removes an entry from the array, given an element index. If the given index is not the last element
* in the list, the last element will have its index swapped with the removed element. If another element
@@ -415,7 +442,9 @@ public final class RawGrowableArray {
Database db = nd.getDB();
if (index > lastElementIndex || index < 0) {
- throw new IndexException("Attempt to remove nonexistent element " + index //$NON-NLS-1$
+ IndexExceptionBuilder descriptor = nd.describeProblem().addProblemAddress(GROWABLE_BLOCK_ADDRESS, address);
+ addSizeTo(nd, address, descriptor);
+ throw descriptor.build("Attempt to remove nonexistent element " + index //$NON-NLS-1$
+ " from an array of size " + (lastElementIndex + 1)); //$NON-NLS-1$
}
@@ -557,7 +586,7 @@ public final class RawGrowableArray {
// For sizes larger than the max block size, we need to use a metablock. In this case, the allocated size
// will be a multiple of the max block size.
- return roundUpToMultipleOf(GrowableBlockHeader.MAX_GROWABLE_SIZE, growableRegionSize);
+ return MathUtils.roundUpToNearestMultiple(growableRegionSize, GrowableBlockHeader.MAX_GROWABLE_SIZE);
}
return nextGrowableSize;
@@ -590,15 +619,6 @@ public final class RawGrowableArray {
}
/**
- * Rounds a value up to the nearest multiple of another value
- */
- private static int roundUpToMultipleOf(int unit, int valueToRound) {
- int numberOfMetablocks = (valueToRound + unit - 1) / unit;
-
- return numberOfMetablocks * unit;
- }
-
- /**
* Returns the record size for a RawGrowableSize with the given number of inline records
*/
public int getRecordSize() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/BTree.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/BTree.java
index 2c9ec0b388..6ed80067d5 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/BTree.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/BTree.java
@@ -347,7 +347,7 @@ public class BTree {
}
public void makeWritable() {
- this.chunk = chunk.getWritableChunk();
+ this.chunk = this.chunk.getWritableChunk();
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java
index 92fcd7ae9a..820ff74da9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java
@@ -102,13 +102,14 @@ final class Chunk {
return wasCanceled;
}
- private static int recPtrToIndex(final long offset) {
+ static int recPtrToIndex(final long offset) {
return (int) (offset & Database.OFFSET_IN_CHUNK_MASK);
}
public void putByte(final long offset, final byte value) {
makeDirty();
this.fBuffer[recPtrToIndex(offset)]= value;
+ recordWrite(offset, 1);
}
public byte getByte(final long offset) {
@@ -133,12 +134,14 @@ final class Chunk {
public void putBytes(final long offset, final byte[] bytes) {
makeDirty();
System.arraycopy(bytes, 0, this.fBuffer, recPtrToIndex(offset), bytes.length);
+ recordWrite(offset, bytes.length);
}
public void putInt(final long offset, final int value) {
makeDirty();
int idx= recPtrToIndex(offset);
putInt(value, this.fBuffer, idx);
+ recordWrite(offset, 4);
}
static final void putInt(final int value, final byte[] buffer, int idx) {
@@ -194,6 +197,7 @@ final class Chunk {
makeDirty();
int idx = recPtrToIndex(offset);
Database.putRecPtr(value, this.fBuffer, idx);
+ recordWrite(offset, 4);
}
/**
@@ -204,6 +208,7 @@ final class Chunk {
makeDirty();
int idx = recPtrToIndex(offset);
putInt(compressFreeRecPtr(value), this.fBuffer, idx);
+ recordWrite(offset, 4);
}
public long getRecPtr(final long offset) {
@@ -223,6 +228,7 @@ final class Chunk {
this.fBuffer[idx]= (byte) (value >> 16);
this.fBuffer[++idx]= (byte) (value >> 8);
this.fBuffer[++idx]= (byte) (value);
+ recordWrite(offset, 3);
}
public int get3ByteUnsignedInt(final long offset) {
@@ -237,6 +243,11 @@ final class Chunk {
int idx= recPtrToIndex(offset);
this.fBuffer[idx]= (byte) (value >> 8);
this.fBuffer[++idx]= (byte) (value);
+ recordWrite(offset, 2);
+ }
+
+ private void recordWrite(long offset, int size) {
+ this.fDatabase.getLog().recordWrite(offset, size);
}
public short getShort(final long offset) {
@@ -276,6 +287,7 @@ final class Chunk {
this.fBuffer[++idx]= (byte) (value >> 16);
this.fBuffer[++idx]= (byte) (value >> 8);
this.fBuffer[++idx]= (byte) (value);
+ recordWrite(offset, 8);
}
public void putChar(final long offset, final char value) {
@@ -283,6 +295,7 @@ final class Chunk {
int idx= recPtrToIndex(offset);
this.fBuffer[idx]= (byte) (value >> 8);
this.fBuffer[++idx]= (byte) (value);
+ recordWrite(offset, 2);
}
public void putChars(final long offset, char[] chars, int start, int len) {
@@ -294,6 +307,7 @@ final class Chunk {
this.fBuffer[++idx]= (byte) (value >> 8);
this.fBuffer[++idx]= (byte) (value);
}
+ recordWrite(offset, len * 2);
}
public void putCharsAsBytes(final long offset, char[] chars, int start, int len) {
@@ -304,6 +318,7 @@ final class Chunk {
char value= chars[i];
this.fBuffer[++idx]= (byte) (value);
}
+ recordWrite(offset, len);
}
public void putDouble(final long offset, double value) {
@@ -336,9 +351,14 @@ final class Chunk {
makeDirty();
int idx = recPtrToIndex(offset);
final int end = idx + length;
+ if (end > this.fBuffer.length) {
+ throw new IndexException("Attempting to clear beyond end of chunk. Chunk = " + this.fSequenceNumber //$NON-NLS-1$
+ + ", offset = " + offset + ", length = " + length); //$NON-NLS-1$//$NON-NLS-2$
+ }
for (; idx < end; idx++) {
this.fBuffer[idx] = 0;
}
+ recordWrite(offset, length);
}
void put(final long offset, final byte[] data, final int len) {
@@ -349,6 +369,7 @@ final class Chunk {
makeDirty();
int idx = recPtrToIndex(offset);
System.arraycopy(data, dataPos, this.fBuffer, idx, len);
+ recordWrite(offset, len);
}
public void get(final long offset, byte[] data) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkCache.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkCache.java
index e320a2cea7..7771a6429f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkCache.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkCache.java
@@ -24,8 +24,8 @@ public final class ChunkCache {
public static final String CHUNK_CACHE_SIZE_MB = "chunkCacheSizeMb"; //$NON-NLS-1$
public static final String CHUNK_CACHE_SIZE_PERCENT = "chunkCacheSizePercent"; //$NON-NLS-1$
- public static final double CHUNK_CACHE_SIZE_MB_DEFAULT = 256.0;
- public static final double CHUNK_CACHE_SIZE_PERCENT_DEFAULT = 10.0;
+ public static final double CHUNK_CACHE_SIZE_MB_DEFAULT = 128.0;
+ public static final double CHUNK_CACHE_SIZE_PERCENT_DEFAULT = 5.0;
static {
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID);
@@ -99,10 +99,10 @@ public final class ChunkCache {
while (true) {
Chunk chunk = this.fPageTable[this.fPointer];
if (chunk.fCacheHitFlag) {
- chunk.fCacheHitFlag= false;
- this.fPointer= (this.fPointer + 1) % this.fPageTable.length;
+ chunk.fCacheHitFlag = false;
+ this.fPointer = (this.fPointer + 1) % this.fPageTable.length;
} else {
- chunk.fCacheIndex= -1;
+ chunk.fCacheIndex = -1;
chunk.fDatabase.checkIfChunkReleased(chunk);
this.fPageTable[this.fPointer] = null;
return;
@@ -149,10 +149,10 @@ public final class ChunkCache {
this.fPointer= oldLength;
this.fPageTable= newTable;
} else {
- for (int i= newLength; i < oldLength; i++) {
- final Chunk chunk= this.fPageTable[i];
+ for (int i = newLength; i < oldLength; i++) {
+ Chunk chunk = this.fPageTable[i];
+ chunk.fCacheIndex = -1;
chunk.fDatabase.checkIfChunkReleased(chunk);
- chunk.fCacheIndex= -1;
}
Chunk[] newTable= new Chunk[newLength];
System.arraycopy(this.fPageTable, 0, newTable, 0, newLength);
@@ -166,4 +166,18 @@ public final class ChunkCache {
long maxLength= Math.min(maxSize / Database.CHUNK_SIZE, Integer.MAX_VALUE);
return Math.max(1, (int) maxLength);
}
+
+ public synchronized void clear() {
+ for (int i = 0; i < this.fPageTable.length; i++) {
+ Chunk chunk = this.fPageTable[i];
+ if (chunk == null) {
+ continue;
+ }
+ chunk.fCacheIndex = -1;
+ chunk.fDatabase.checkIfChunkReleased(chunk);
+ this.fPageTable[i] = null;
+ }
+ this.fTableIsFull = false;
+ this.fPointer = 0;
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
index 16250f754a..cbccd07ac6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
@@ -31,11 +31,21 @@ import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.internal.core.nd.IndexExceptionBuilder;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.osgi.util.NLS;
/**
* Database encapsulates access to a flat binary format file with a memory-manager-like API for
* obtaining and releasing areas of storage (memory).
+ * <p>
+ * Some terminology is used throughout this class: A block is a variable-size piece of
+ * contiguous memory returned by malloc. A chunk is a fixed-size piece of contiguous memory
+ * that is the atomic unit for paging, caching, reads, and writes. A free block is contiguous
+ * variable-length piece of memory that is created by free and is potentially usable by malloc.
+ * Most chunks contain multiple blocks and free blocks, but it is possible for a single block
+ * to use multiple chunks. Such blocks are referred to as "large blocks". A free block is always
+ * smaller than a chunk.
*/
/*
* The file encapsulated is divided into Chunks of size CHUNK_SIZE, and a table of contents
@@ -157,7 +167,7 @@ public class Database {
/**
* True iff large chunk self-diagnostics should be enabled.
*/
- public static boolean DEBUG_LARGE_CHUNKS;
+ public static boolean DEBUG_FREE_SPACE;
public static boolean DEBUG_PAGE_CACHE;
@@ -196,8 +206,14 @@ public class Database {
private long totalFlushTime;
private long totalWriteTimeMs;
private long pageWritesBytes;
+ private long nextValidation;
+ private long validateCounter;
public static final double MIN_BYTES_PER_MILLISECOND = 20480.0;
+ private final ModificationLog log = new ModificationLog(0);
+ private final Tag mallocTag;
+ private final Tag freeTag;
+
/**
* Construct a new Database object, creating a backing file if necessary.
* @param location the local file path for the database
@@ -207,6 +223,8 @@ public class Database {
* @throws IndexException
*/
public Database(File location, ChunkCache cache, int version, boolean openReadOnly) throws IndexException {
+ this.mallocTag = ModificationLog.createTag("Calling Database.malloc"); //$NON-NLS-1$
+ this.freeTag = ModificationLog.createTag("Calling Database.free"); //$NON-NLS-1$
try {
this.fLocation = location;
this.fReadOnly= openReadOnly;
@@ -265,6 +283,10 @@ public class Database {
} while (true);
}
+ public ModificationLog getLog() {
+ return this.log;
+ }
+
/**
* Attempts to write to the given position in the file. Will retry if interrupted by Thread.interrupt() until,
* the write succeeds. It will return true if any call to Thread.interrupt() was detected.
@@ -347,6 +369,7 @@ public class Database {
boolean wasCanceled = false;
removeChunksFromCache();
+ this.log.clear();
this.fVersion= version;
// Clear the first chunk.
this.fHeaderChunk.clear(0, CHUNK_SIZE);
@@ -380,6 +403,7 @@ public class Database {
wasCanceled = flush() || wasCanceled;
}
this.memoryUsage.refresh();
+ this.fHeaderChunk.makeDirty();
return wasCanceled;
}
@@ -502,65 +526,84 @@ public class Database {
assert this.fExclusiveLock;
assert datasize >= 0;
assert datasize <= MAX_MALLOC_SIZE;
-
+
long result;
int usedSize;
- if (datasize >= MAX_SINGLE_BLOCK_MALLOC_SIZE) {
- int newChunkNum = createLargeBlock(datasize);
- usedSize = Math.abs(getBlockHeaderForChunkNum(newChunkNum)) * CHUNK_SIZE;
- result = (long) newChunkNum * CHUNK_SIZE + LargeBlock.HEADER_SIZE;
- // Note that we identify large blocks by setting their block size to 0.
- clearRange(result, usedSize - LargeBlock.HEADER_SIZE - LargeBlock.FOOTER_SIZE);
- result = result + BLOCK_HEADER_SIZE;
- } else {
- long freeBlock = 0;
- int needDeltas = divideRoundingUp(datasize + BLOCK_HEADER_SIZE, BLOCK_SIZE_DELTA);
- if (needDeltas < MIN_BLOCK_DELTAS) {
- needDeltas = MIN_BLOCK_DELTAS;
- }
-
- // Which block size.
- int useDeltas;
- for (useDeltas = needDeltas; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
- freeBlock = getFirstBlock(useDeltas * BLOCK_SIZE_DELTA);
- if (freeBlock != 0)
- break;
- }
-
- // Get the block.
- Chunk chunk;
- if (freeBlock == 0) {
- // Allocate a new chunk.
- freeBlock = (long) (createLargeBlock(datasize)) * (long) CHUNK_SIZE + LargeBlock.HEADER_SIZE;
- useDeltas = MAX_BLOCK_DELTAS;
- chunk = getChunk(freeBlock);
+ this.log.start(this.mallocTag);
+ try {
+ if (datasize >= MAX_SINGLE_BLOCK_MALLOC_SIZE) {
+ int newChunkNum = createLargeBlock(datasize);
+ usedSize = Math.abs(getBlockHeaderForChunkNum(newChunkNum)) * CHUNK_SIZE;
+ result = (long) newChunkNum * CHUNK_SIZE + LargeBlock.HEADER_SIZE;
+ // Note that we identify large blocks by setting their block size to 0.
+ clearRange(result, usedSize - LargeBlock.HEADER_SIZE - LargeBlock.FOOTER_SIZE);
+ result = result + BLOCK_HEADER_SIZE;
} else {
- chunk = getChunk(freeBlock);
- chunk.makeDirty();
- removeBlock(chunk, useDeltas * BLOCK_SIZE_DELTA, freeBlock);
- }
-
- final int unusedDeltas = useDeltas - needDeltas;
- if (unusedDeltas >= MIN_BLOCK_DELTAS) {
- // Add in the unused part of our block.
- addBlock(chunk, unusedDeltas * BLOCK_SIZE_DELTA, freeBlock + needDeltas * BLOCK_SIZE_DELTA);
- useDeltas = needDeltas;
+ long freeBlock = 0;
+ int needDeltas = divideRoundingUp(datasize + BLOCK_HEADER_SIZE, BLOCK_SIZE_DELTA);
+ if (needDeltas < MIN_BLOCK_DELTAS) {
+ needDeltas = MIN_BLOCK_DELTAS;
+ }
+
+ // Which block size.
+ int useDeltas;
+ for (useDeltas = needDeltas; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
+ freeBlock = getFirstBlock(useDeltas * BLOCK_SIZE_DELTA);
+ if (freeBlock != 0)
+ break;
+ }
+
+ // Get the block.
+ Chunk chunk;
+ if (freeBlock == 0) {
+ // Allocate a new chunk.
+ freeBlock = (long) (createLargeBlock(datasize)) * (long) CHUNK_SIZE + LargeBlock.HEADER_SIZE;
+ useDeltas = MAX_BLOCK_DELTAS;
+ chunk = getChunk(freeBlock);
+ } else {
+ chunk = getChunk(freeBlock);
+ chunk.makeDirty();
+ int blockReportedSize = chunk.getShort(freeBlock);
+ if (blockReportedSize != useDeltas * BLOCK_SIZE_DELTA) {
+ throw describeProblem()
+ .addProblemAddress("block size", freeBlock, SHORT_SIZE) //$NON-NLS-1$
+ .build(
+ "Heap corruption detected in free space list. Block " + freeBlock //$NON-NLS-1$
+ + " reports a size of " + blockReportedSize + " but was in the list for blocks of size " //$NON-NLS-1$//$NON-NLS-2$
+ + useDeltas * BLOCK_SIZE_DELTA);
+ }
+ removeBlock(chunk, useDeltas * BLOCK_SIZE_DELTA, freeBlock);
+ }
+
+ final int unusedDeltas = useDeltas - needDeltas;
+ if (unusedDeltas >= MIN_BLOCK_DELTAS) {
+ // Add in the unused part of our block.
+ addBlock(chunk, unusedDeltas * BLOCK_SIZE_DELTA, freeBlock + needDeltas * BLOCK_SIZE_DELTA);
+ useDeltas = needDeltas;
+ }
+
+ // Make our size negative to show in use.
+ usedSize = useDeltas * BLOCK_SIZE_DELTA;
+ chunk.putShort(freeBlock, (short) -usedSize);
+
+ // Clear out the block, lots of people are expecting this.
+ chunk.clear(freeBlock + BLOCK_HEADER_SIZE, usedSize - BLOCK_HEADER_SIZE);
+ result = freeBlock + BLOCK_HEADER_SIZE;
}
-
- // Make our size negative to show in use.
- usedSize = useDeltas * BLOCK_SIZE_DELTA;
- chunk.putShort(freeBlock, (short) -usedSize);
-
- // Clear out the block, lots of people are expecting this.
- chunk.clear(freeBlock + BLOCK_HEADER_SIZE, usedSize - BLOCK_HEADER_SIZE);
- result = freeBlock + BLOCK_HEADER_SIZE;
+ } finally {
+ this.log.end(this.mallocTag);
}
+ this.log.recordMalloc(result, usedSize - BLOCK_HEADER_SIZE);
this.malloced += usedSize;
this.memoryUsage.recordMalloc(poolId, usedSize);
- if (DEBUG_LARGE_CHUNKS) {
- validateFreeSpaceTries();
+ if (DEBUG_FREE_SPACE) {
+ boolean performedValidation = periodicValidateFreeSpace();
+
+ if (performedValidation) {
+ verifyNotInFreeSpaceList(result);
+ }
}
return result;
@@ -631,6 +674,22 @@ public class Database {
} else {
numChunks = getBlockHeaderForChunkNum(freeBlockChunkNum);
+ if (numChunks < neededChunks) {
+ throw describeProblem()
+ .addProblemAddress("chunk header", freeBlockChunkNum * CHUNK_SIZE, INT_SIZE) //$NON-NLS-1$
+ .build("A block in the free space trie was too small or wasn't actually free. Reported size = " //$NON-NLS-1$
+ + numChunks + " chunks, requested size = " + neededChunks + " chunks"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ int footer = getBlockFooterForChunkBefore(freeBlockChunkNum + numChunks);
+ if (footer != numChunks) {
+ throw describeProblem()
+ .addProblemAddress("chunk header", freeBlockChunkNum * CHUNK_SIZE, INT_SIZE) //$NON-NLS-1$
+ .addProblemAddress("chunk footer", (freeBlockChunkNum + numChunks) * CHUNK_SIZE - INT_SIZE, INT_SIZE) //$NON-NLS-1$
+ .build("The header and footer didn't match for a block in the free space trie. Expected " //$NON-NLS-1$
+ + numChunks + " but found " + footer); //$NON-NLS-1$
+ }
+
unlinkFreeBlock(freeBlockChunkNum);
}
@@ -653,7 +712,7 @@ public class Database {
linkFreeBlockToTrie(freeBlockChunkNum + neededChunks, unusedChunks);
} else {
// Use the end of the block
- resultChunkNum = freeBlockChunkNum + neededChunks;
+ resultChunkNum = freeBlockChunkNum + unusedChunks;
// Return the first half of the block to the free block pool
linkFreeBlockToTrie(freeBlockChunkNum, unusedChunks);
}
@@ -687,9 +746,15 @@ public class Database {
putInt(prevBlockChunkNum * CHUNK_SIZE + LargeBlock.NEXT_BLOCK_OFFSET, nextBlockChunkNum);
}
+ /**
+ * True iff this block was a block in the trie. False if it was attached to to the list of siblings but some
+ * other node in the list is the one in the trie.
+ */
+ boolean wasInTrie = false;
long root = getInt(FREE_BLOCK_OFFSET);
if (root == freeBlockChunkNum) {
putInt(FREE_BLOCK_OFFSET, 0);
+ wasInTrie = true;
}
int freeBlockSize = getBlockHeaderForChunkNum(freeBlockChunkNum);
@@ -701,18 +766,31 @@ public class Database {
int firstDifference = LargeBlock.SIZE_OF_SIZE_FIELD * 8 - Integer.numberOfLeadingZeros(difference) - 1;
long locationOfChildPointer = parentChunkNum * CHUNK_SIZE + LargeBlock.CHILD_TABLE_OFFSET
+ (firstDifference * INT_SIZE);
- putInt(locationOfChildPointer, 0);
+ int childChunkNum = getInt(locationOfChildPointer);
+ if (childChunkNum == freeBlockChunkNum) {
+ wasInTrie = true;
+ putInt(locationOfChildPointer, 0);
+ }
}
}
- if (anotherBlockOfSameSize != 0) {
+ // If the removed block was the head of the linked list, we need to reinsert the following entry as the
+ // new head.
+ if (wasInTrie && anotherBlockOfSameSize != 0) {
insertChild(parentChunkNum, anotherBlockOfSameSize);
}
int currentParent = parentChunkNum;
for (int childIdx = 0; childIdx < LargeBlock.ENTRIES_IN_CHILD_TABLE; childIdx++) {
- int nextChildChunkNum = getInt(freeBlockAddress + LargeBlock.CHILD_TABLE_OFFSET + (childIdx * INT_SIZE));
+ long childAddress = freeBlockAddress + LargeBlock.CHILD_TABLE_OFFSET + (childIdx * INT_SIZE);
+ int nextChildChunkNum = getInt(childAddress);
if (nextChildChunkNum != 0) {
+ if (!wasInTrie) {
+ throw describeProblem()
+ .addProblemAddress("non-null child pointer", childAddress, INT_SIZE) //$NON-NLS-1$
+ .build("All child pointers should be null for a free chunk that is in the sibling list but" //$NON-NLS-1$
+ + " not part of the trie. Problematic chunk number: " + freeBlockChunkNum); //$NON-NLS-1$
+ }
insertChild(currentParent, nextChildChunkNum);
// Parent all subsequent children under the child that was most similar to the old parent
if (currentParent == parentChunkNum) {
@@ -774,7 +852,7 @@ public class Database {
for (int testPosition = firstDifference; testPosition < LargeBlock.ENTRIES_IN_CHILD_TABLE; testPosition++) {
if (((currentSize & bitMask) != 0) == lookingForSmallerChild) {
int nextChildChunkNum = getInt(
- (long) trieNodeChunkNum * CHUNK_SIZE + LargeBlock.CHILD_TABLE_OFFSET + (testPosition * PTR_SIZE));
+ (long) trieNodeChunkNum * CHUNK_SIZE + LargeBlock.CHILD_TABLE_OFFSET + (testPosition * INT_SIZE));
int childResultChunkNum = getSmallestChildNoSmallerThan(nextChildChunkNum, numChunks);
if (childResultChunkNum != 0) {
return childResultChunkNum;
@@ -807,6 +885,111 @@ public class Database {
insertChild(getInt(FREE_BLOCK_OFFSET), freeBlockChunkNum);
}
+ public void validateFreeSpace() {
+ validateFreeSpaceLists();
+ validateFreeSpaceTries();
+ }
+
+ /**
+ * Performs a self-test on the free space lists used by malloc to check for corruption
+ */
+ private void validateFreeSpaceLists() {
+ int useDeltas;
+ for (useDeltas = MIN_BLOCK_DELTAS; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
+ validateFreeBlocksFor(useDeltas);
+ }
+ }
+
+ private void verifyNotInFreeSpaceList(long result) {
+ int useDeltas;
+ for (useDeltas = MIN_BLOCK_DELTAS; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
+ int correctSize = useDeltas * BLOCK_SIZE_DELTA;
+ long block = getFirstBlock(correctSize);
+ long addressOfPrevBlockPointer = getAddressOfFirstBlockPointer(correctSize);
+ while (block != 0) {
+ if (block == result) {
+ throw describeProblem()
+ .addProblemAddress("incoming pointer", addressOfPrevBlockPointer, PTR_SIZE) //$NON-NLS-1$
+ .build("Block " + result //$NON-NLS-1$
+ + " was found in the free space list, even though it wasn't free"); //$NON-NLS-1$
+ }
+ addressOfPrevBlockPointer = block + BLOCK_NEXT_OFFSET;
+ long followingBlock = getFreeRecPtr(addressOfPrevBlockPointer);
+ block = followingBlock;
+ }
+ }
+
+ int currentChunkNum = getInt(FREE_BLOCK_OFFSET);
+
+ if (currentChunkNum == 0) {
+ return;
+ }
+ int targetChunkNum = (int) (result / CHUNK_SIZE);
+
+ if (currentChunkNum == targetChunkNum) {
+ throw describeProblem().build("Block " + result //$NON-NLS-1$
+ + " was not supposed to be in the free space list, but was linked as the root of the list"); //$NON-NLS-1$
+ }
+
+ verifyNotInLargeBlockFreeSpaceTrie(targetChunkNum, currentChunkNum, 0);
+ }
+
+ private void verifyNotInLargeBlockFreeSpaceTrie(int targetChunkNum, int chunkNum, int parent) {
+ long chunkStart = chunkNum * CHUNK_SIZE;
+
+ for (int testPosition = 0; testPosition < LargeBlock.ENTRIES_IN_CHILD_TABLE; testPosition++) {
+ long chunkAddress = chunkStart + LargeBlock.CHILD_TABLE_OFFSET + (testPosition * INT_SIZE);
+ int nextChildChunkNum = getInt(chunkAddress);
+
+ if (nextChildChunkNum == 0) {
+ continue;
+ }
+
+ if (nextChildChunkNum == targetChunkNum) {
+ throw describeProblem()
+ .addProblemAddress("trie child address", chunkAddress, INT_SIZE) //$NON-NLS-1$
+ .build("Chunk number " + nextChildChunkNum //$NON-NLS-1$
+ + " was found in the free space trie even though it was in use"); //$NON-NLS-1$
+ }
+
+ verifyNotInLargeBlockFreeSpaceTrie(targetChunkNum, nextChildChunkNum, chunkNum);
+ }
+ }
+
+ private void validateFreeBlocksFor(int numberOfDeltas) {
+ int correctSize = numberOfDeltas * BLOCK_SIZE_DELTA;
+ long lastBlock = 0;
+ long block = getFirstBlock(correctSize);
+ long addressOfPrevBlockPointer = getAddressOfFirstBlockPointer(correctSize);
+ while (block != 0) {
+ long measuredLastBlock = getFreeRecPtr(block + BLOCK_PREV_OFFSET);
+ int blockReportedSize = getShort(block);
+ long followingBlock = getFreeRecPtr(block + BLOCK_NEXT_OFFSET);
+ if (measuredLastBlock != lastBlock) {
+ throw describeProblem()
+ .addProblemAddress("last block", block + BLOCK_PREV_OFFSET, PTR_SIZE) //$NON-NLS-1$
+ .addProblemAddress("incoming pointer", addressOfPrevBlockPointer, PTR_SIZE) //$NON-NLS-1$
+ .build("The free space block (" + block //$NON-NLS-1$
+ + ") of size " + correctSize + " had an incorrect prev pointer to " //$NON-NLS-1$//$NON-NLS-2$
+ + measuredLastBlock + ", but it should have been pointing to " //$NON-NLS-1$
+ + lastBlock);
+ }
+ if (blockReportedSize != correctSize) {
+ throw describeProblem()
+ .addProblemAddress("block size", block, SHORT_SIZE) //$NON-NLS-1$
+ .addProblemAddress("incoming pointer", addressOfPrevBlockPointer, PTR_SIZE) //$NON-NLS-1$
+ .build("A block (" + block + ") of size " + measuredLastBlock //$NON-NLS-1$ //$NON-NLS-2$
+ + " was in the free space list for blocks of size " + correctSize); //$NON-NLS-1$
+ }
+ addressOfPrevBlockPointer = block + BLOCK_NEXT_OFFSET;
+ lastBlock = block;
+ block = followingBlock;
+ }
+ }
+
+ /**
+ * Performs a self-test on the free space trie list (used by the large block allocator) to check for corruption
+ */
private void validateFreeSpaceTries() {
int currentChunkNum = getInt(FREE_BLOCK_OFFSET);
@@ -820,22 +1003,24 @@ public class Database {
private void validateFreeSpaceNode(Set<Integer> visited, int chunkNum, int parent) {
if (visited.contains(chunkNum)) {
- throw new IndexException("Chunk " + chunkNum + "(parent = " + parent //$NON-NLS-1$//$NON-NLS-2$
+ throw describeProblem().build("Chunk " + chunkNum + "(parent = " + parent //$NON-NLS-1$//$NON-NLS-2$
+ " appeared twice in the free space tree"); //$NON-NLS-1$
}
-
+
long chunkStart = chunkNum * CHUNK_SIZE;
int parentChunk = getInt(chunkStart + LargeBlock.PARENT_OFFSET);
if (parentChunk != parent) {
- throw new IndexException("Chunk " + chunkNum + " has the wrong parent. Expected " + parent //$NON-NLS-1$//$NON-NLS-2$
+ throw describeProblem()
+ .addProblemAddress("parent pointer", chunkStart + LargeBlock.PARENT_OFFSET, Database.INT_SIZE) //$NON-NLS-1$
+ .build("Chunk " + chunkNum + " has the wrong parent. Expected " + parent //$NON-NLS-1$//$NON-NLS-2$
+ " but found " + parentChunk); //$NON-NLS-1$
}
-
+
visited.add(chunkNum);
int numChunks = getBlockHeaderForChunkNum(chunkNum);
for (int testPosition = 0; testPosition < LargeBlock.ENTRIES_IN_CHILD_TABLE; testPosition++) {
- int nextChildChunkNum = getInt(
- chunkStart + LargeBlock.CHILD_TABLE_OFFSET + (testPosition * PTR_SIZE));
+ long nextChildChunkNumAddress = chunkStart + LargeBlock.CHILD_TABLE_OFFSET + (testPosition * INT_SIZE);
+ int nextChildChunkNum = getInt(nextChildChunkNumAddress);
if (nextChildChunkNum == 0) {
continue;
@@ -845,14 +1030,25 @@ public class Database {
int sizeDifference = nextSize ^ numChunks;
int firstDifference = LargeBlock.SIZE_OF_SIZE_FIELD * 8 - Integer.numberOfLeadingZeros(
Integer.highestOneBit(sizeDifference)) - 1;
-
+
if (firstDifference != testPosition) {
- throw new IndexException("Chunk " + nextChildChunkNum + " contained an incorrect size of " //$NON-NLS-1$//$NON-NLS-2$
+ IndexExceptionBuilder descriptor = describeProblem();
+ attachBlockHeaderForChunkNum(descriptor, chunkNum);
+ attachBlockHeaderForChunkNum(descriptor, nextChildChunkNum);
+ throw descriptor.build("Chunk " + nextChildChunkNum + " contained an incorrect size of " //$NON-NLS-1$//$NON-NLS-2$
+ nextSize + ". It was at position " + testPosition + " in parent " + chunkNum //$NON-NLS-1$ //$NON-NLS-2$
+ " which had size " + numChunks); //$NON-NLS-1$
}
- validateFreeSpaceNode(visited, nextChildChunkNum, chunkNum);
+ try {
+ validateFreeSpaceNode(visited, nextChildChunkNum, chunkNum);
+ } catch (IndexException e) {
+ describeProblem()
+ .addProblemAddress("child pointer from parent " + chunkNum, nextChildChunkNumAddress, //$NON-NLS-1$
+ Database.INT_SIZE)
+ .attachTo(e);
+ throw e;
+ }
}
}
@@ -956,6 +1152,14 @@ public class Database {
return getInt((long) firstChunkNum * CHUNK_SIZE);
}
+ private void attachBlockHeaderForChunkNum(IndexExceptionBuilder builder, int firstChunkNum) {
+ if (firstChunkNum >= this.fChunksUsed) {
+ return;
+ }
+ builder.addProblemAddress("block header for chunk " + firstChunkNum, ((long) firstChunkNum * CHUNK_SIZE), //$NON-NLS-1$
+ Database.INT_SIZE);
+ }
+
/**
* Returns the size of the block (in number of chunks), given the (non-inclusive) address that the block ends at.
* The return value is positive if the block is free and negative if the block is allocated.
@@ -1013,21 +1217,26 @@ public class Database {
}
}
+ private long getAddressOfFirstBlockPointer(int blockSize) {
+ return MALLOC_TABLE_OFFSET + (blockSize / BLOCK_SIZE_DELTA - MIN_BLOCK_DELTAS) * INT_SIZE;
+ }
+
/**
- * @param blocksize (must be a multiple of BLOCK_SIZE_DELTA)
+ * @param blockSize (must be a multiple of BLOCK_SIZE_DELTA)
*/
- private long getFirstBlock(int blocksize) throws IndexException {
+ private long getFirstBlock(int blockSize) throws IndexException {
assert this.fLocked;
- return this.fHeaderChunk.getFreeRecPtr(MALLOC_TABLE_OFFSET + (blocksize / BLOCK_SIZE_DELTA - MIN_BLOCK_DELTAS) * INT_SIZE);
+ return this.fHeaderChunk.getFreeRecPtr(getAddressOfFirstBlockPointer(blockSize));
}
- private void setFirstBlock(int blocksize, long block) throws IndexException {
+ private void setFirstBlock(int blockSize, long block) throws IndexException {
assert this.fExclusiveLock;
- this.fHeaderChunk.putFreeRecPtr(MALLOC_TABLE_OFFSET + (blocksize / BLOCK_SIZE_DELTA - MIN_BLOCK_DELTAS) * INT_SIZE, block);
+ this.fHeaderChunk.putFreeRecPtr(getAddressOfFirstBlockPointer(blockSize), block);
}
private void removeBlock(Chunk chunk, int blocksize, long block) throws IndexException {
assert this.fExclusiveLock;
+
long prevblock = chunk.getFreeRecPtr(block + BLOCK_PREV_OFFSET);
long nextblock = chunk.getFreeRecPtr(block + BLOCK_NEXT_OFFSET);
if (prevblock != 0) {
@@ -1063,45 +1272,79 @@ public class Database {
* the same ID that was previously passed into malloc when allocating this memory address
*/
public void free(long address, short poolId) throws IndexException {
- assert this.fExclusiveLock;
- if (address == 0) {
- return;
- }
- long blockSize;
- long block = address - BLOCK_HEADER_SIZE;
- Chunk chunk = getChunk(block);
- blockSize = -chunk.getShort(block);
- // We use a block size of 0 to indicate a large block that fills a range of chunks
- if (blockSize == 0) {
- int offsetIntoChunk = (int) (address % CHUNK_SIZE);
- assert offsetIntoChunk == LargeBlock.HEADER_SIZE + BLOCK_HEADER_SIZE;
- // Deallocating a large block
- // This was a large block. It uses a sequence of full chunks.
- int chunkNum = (int) (address / CHUNK_SIZE);
- int numChunks = -getBlockHeaderForChunkNum(chunkNum);
- if (numChunks < 0) {
- // Already freed.
- throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, 0,
- "Already freed large block " + address, new Exception())); //$NON-NLS-1$
+ getLog().start(this.freeTag);
+ try {
+ assert this.fExclusiveLock;
+ if (address == 0) {
+ return;
}
- blockSize = (long) numChunks * CHUNK_SIZE;
- freeLargeChunk(chunkNum, numChunks);
- if (DEBUG_LARGE_CHUNKS) {
- validateFreeSpaceTries();
+ long blockSize;
+ long block = address - BLOCK_HEADER_SIZE;
+ Chunk chunk = getChunk(block);
+ blockSize = -chunk.getShort(block);
+ // We use a block size of 0 to indicate a large block that fills a range of chunks
+ if (blockSize == 0) {
+ int offsetIntoChunk = (int) (address % CHUNK_SIZE);
+ assert offsetIntoChunk == LargeBlock.HEADER_SIZE + BLOCK_HEADER_SIZE;
+ // Deallocating a large block
+ // This was a large block. It uses a sequence of full chunks.
+ int chunkNum = (int) (address / CHUNK_SIZE);
+ int numChunks = -getBlockHeaderForChunkNum(chunkNum);
+ if (numChunks < 0) {
+ IndexExceptionBuilder builder = describeProblem();
+ if (chunkNum < this.fChunksUsed) {
+ builder.addProblemAddress("block header", (long) chunkNum * CHUNK_SIZE, INT_SIZE); //$NON-NLS-1$
+ }
+ throw builder.build("Already freed large block " + address); //$NON-NLS-1$
+ }
+ blockSize = (long) numChunks * CHUNK_SIZE;
+ this.log.recordFree(address, (int)(blockSize - BLOCK_HEADER_SIZE));
+ freeLargeChunk(chunkNum, numChunks);
+ } else {
+ // Deallocating a normal block
+ // TODO Look for opportunities to merge small blocks
+ if (blockSize < 0) {
+ throw describeProblem()
+ .addProblemAddress("block size", block, SHORT_SIZE) //$NON-NLS-1$
+ .build("Already freed record " + address); //$NON-NLS-1$
+ }
+ this.log.recordFree(address, (int)(blockSize - BLOCK_HEADER_SIZE));
+ int offset = Chunk.recPtrToIndex(address);
+ if (offset + blockSize > CHUNK_SIZE) {
+ throw describeProblem()
+ .addProblemAddress("block size", block, SHORT_SIZE) //$NON-NLS-1$
+ .build("Attempting to free chunk of impossible size. The block at address " //$NON-NLS-1$
+ + address + " in chunk " + chunk.fSequenceNumber + " offset " + offset //$NON-NLS-1$//$NON-NLS-2$
+ + " can't be as large as " //$NON-NLS-1$
+ + blockSize + " bytes since that would make it extend beyond the end of the chunk"); //$NON-NLS-1$
+ }
+ addBlock(chunk, (int) blockSize, block);
}
- } else {
- // Deallocating a normal block
- // TODO Look for opportunities to merge small blocks
- if (blockSize < 0) {
- // Already freed.
- throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, 0,
- "Already freed record " + address, new Exception())); //$NON-NLS-1$
+
+ if (DEBUG_FREE_SPACE) {
+ periodicValidateFreeSpace();
}
- addBlock(chunk, (int) blockSize, block);
+
+ this.freed += blockSize;
+ this.memoryUsage.recordFree(poolId, blockSize);
+ } finally {
+ getLog().end(this.freeTag);
}
+ }
- this.freed += blockSize;
- this.memoryUsage.recordFree(poolId, blockSize);
+ /**
+ * Periodically performs validation of the free space in the database. Validation is very expensive, so the
+ * validation period uses exponential falloff so validations happen less and less frequently over
+ * time. Returns true iff validation happened on this iteration.
+ */
+ private boolean periodicValidateFreeSpace() {
+ this.validateCounter++;
+ if (this.validateCounter > this.nextValidation) {
+ validateFreeSpace();
+ this.nextValidation = this.validateCounter * 2;
+ return true;
+ }
+ return false;
}
private void freeLargeChunk(int chunkNum, int numChunks) {
@@ -1320,6 +1563,7 @@ public class Database {
flush();
removeChunksFromCache();
+ this.log.clear();
// Chunks have been removed from the cache, so we are fine.
this.fHeaderChunk.clear(0, CHUNK_SIZE);
this.memoryUsage.refresh();
@@ -1629,4 +1873,8 @@ public class Database {
return new ChunkStats(this.fChunks.length, count, dirtyChunks, nonDirtyChunksNotInCache);
}
}
+
+ public IndexExceptionBuilder describeProblem() {
+ return new IndexExceptionBuilder(this);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java
index f6ecf9a792..f971fb8db4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java
@@ -10,6 +10,9 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.db;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -19,9 +22,10 @@ import org.eclipse.core.runtime.Status;
public class IndexException extends RuntimeException {
private IStatus status;
+ private List<RelatedAddress> relatedAddresses = new ArrayList<>();
+ private long time = -1;
public IndexException(IStatus status) {
- super(status.getMessage());
this.status = status;
}
@@ -29,6 +33,16 @@ public class IndexException extends RuntimeException {
this(new Status(IStatus.ERROR, "org.eclipse.jdt.core", message)); //$NON-NLS-1$
}
+ /**
+ * Sets the time that the exception occurred at (in terms of the write number
+ * from the modification log)
+ *
+ * @param writeNumber
+ */
+ public void setTime(long writeNumber) {
+ this.time = writeNumber;
+ }
+
@Override
public synchronized Throwable getCause() {
return this.status.getException();
@@ -43,4 +57,37 @@ public class IndexException extends RuntimeException {
private static final long serialVersionUID = -6561893929558916225L;
+ public void addRelatedAddress(RelatedAddress related) {
+ // Don't include dupes
+ for (RelatedAddress next : this.relatedAddresses) {
+ if (next.isSameAddressAs(related)) {
+ return;
+ }
+ }
+ this.relatedAddresses.add(related);
+ }
+
+ @Override
+ public String getMessage() {
+ StringBuilder result = new StringBuilder();
+ if (this.time != -1) {
+ result.append("(time "); //$NON-NLS-1$
+ result.append(this.time);
+ result.append(") "); //$NON-NLS-1$
+ }
+ result.append(this.status.getMessage());
+
+ if (!this.relatedAddresses.isEmpty()) {
+ boolean isFirst = true;
+ result.append("\nRelated addresses:\n"); //$NON-NLS-1$
+ for (RelatedAddress next : this.relatedAddresses) {
+ if (!isFirst) {
+ result.append("\n"); //$NON-NLS-1$
+ }
+ isFirst = false;
+ result.append(next.toString());
+ }
+ }
+ return result.toString();
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java
new file mode 100644
index 0000000000..b81b37fa83
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java
@@ -0,0 +1,443 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd.db;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Records a record of every modification to the database, in a circular buffer of fixed size. Whenever anything writes
+ * to the database, the log records the address and size of the write, along with a call stack describing what was going
+ * on at the time of the write. The actual bytes written to the database are not recorded. In addition to writes, it
+ * also records every invocation of malloc and free.
+ * <p>
+ * Given a memory address range, we can trace the log backwards to find everything that ever happened to that address
+ * range since the start of the log.
+ * </p>
+ * "call stacks" don't use java call stacks. They use explicit tags that are pushed and popped at the start and
+ * end of operations related to modifying the database.
+ */
+public class ModificationLog {
+ /**
+ * Used to attach messages to events in the log. Tags should be allocated in static initializers at application
+ * startup by calling {@link ModificationLog#createTag(String)}. Once allocated, the tag can be pushed and popped on to
+ * the stack in the log to mark the beginning and end of operations.
+ */
+ public static class Tag {
+ public final String name;
+ public final int opNum;
+
+ Tag(String name, int opNum) {
+ this.name = name;
+ this.opNum = opNum;
+ }
+
+ @Override
+ public String toString() {
+ return this.opNum + ":" + this.name; //$NON-NLS-1$
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + this.opNum;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Tag other = (Tag) obj;
+ if (this.opNum != other.opNum)
+ return false;
+ return true;
+ }
+ }
+
+ /**
+ * Represents a single entry in a {@link MemoryAccessLog}. That is, a single read, write, malloc, or free event that
+ * affected the memory range of interest.
+ */
+ public static class MemoryOperation {
+ private final List<Tag> stack;
+ private final long time;
+ private final long startAddress;
+ private final int addressSize;
+ private final byte operationType;
+
+ public MemoryOperation(byte operationType, long time, long startAddress, int size, List<Tag> stack) {
+ super();
+ this.operationType = operationType;
+ this.time = time;
+ this.startAddress = startAddress;
+ this.addressSize = size;
+ this.stack = stack;
+ }
+
+ public List<Tag> getStack() {
+ return this.stack;
+ }
+
+ public long getTime() {
+ return this.time;
+ }
+
+ public long getStartAddress() {
+ return this.startAddress;
+ }
+
+ public int getSize() {
+ return this.addressSize;
+ }
+
+ public byte getOperationType() {
+ return this.operationType;
+ }
+
+ public void printTo(StringBuilder builder, int indent) {
+ indent(builder, indent);
+ switch (getOperationType()) {
+ case FREE_OPERATION: builder.append("freed"); break; //$NON-NLS-1$
+ case MALLOC_OPERATION: builder.append("malloc'd"); break; //$NON-NLS-1$
+ case WRITE_OPERATION: builder.append("wrote"); break; //$NON-NLS-1$
+ }
+ builder.append(" [address "); //$NON-NLS-1$
+ builder.append(this.startAddress);
+ builder.append(", size "); //$NON-NLS-1$
+ builder.append(this.addressSize);
+ builder.append("] at time "); //$NON-NLS-1$
+ builder.append(this.time);
+ builder.append("\n"); //$NON-NLS-1$
+ List<Tag> theStack = new ArrayList<>();
+ theStack.addAll(getStack());
+ Collections.reverse(theStack);
+ for (Tag next : theStack) {
+ indent(builder, indent + 1);
+ builder.append(next.name + "\n"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Contains a log of events related to a specific range of database addresses, in reverse chronological order.
+ */
+ public static class MemoryAccessLog {
+ private final List<MemoryOperation> operations;
+
+ public MemoryAccessLog(List<MemoryOperation> operations) {
+ super();
+ this.operations = operations;
+ }
+
+ /**
+ * Returns a list of operations, in reverse order of time.
+ */
+ public List<MemoryOperation> getOperations() {
+ return this.operations;
+ }
+
+ /**
+ * Returns true iff this log contains a double malloc or a double free
+ */
+ public boolean hasInconsistentMemoryAllocation() {
+ boolean known = false;
+ boolean allocated = false;
+ for (MemoryOperation next : this.operations) {
+ boolean newAllocatedState;
+ if (next.getOperationType() == MALLOC_OPERATION) {
+ newAllocatedState = false;
+ } else if (next.getOperationType() == FREE_OPERATION) {
+ newAllocatedState = true;
+ } else {
+ continue;
+ }
+
+ if (!known) {
+ known = true;
+ } else if (allocated == newAllocatedState) {
+ return true;
+ }
+ allocated = newAllocatedState;
+ }
+ return false;
+ }
+
+ /**
+ * Search for anomalies in the log and produce a reduced report
+ *
+ * @return a log containing the most interesting results
+ */
+ public MemoryAccessLog reduce(int maxWrites) {
+ boolean includeAllMallocs = hasInconsistentMemoryAllocation();
+ int numWrites = 0;
+
+ List<MemoryOperation> result = new ArrayList<>();
+ for (MemoryOperation next : this.operations) {
+ boolean keepGoing = true;
+ switch (next.getOperationType()) {
+ case MALLOC_OPERATION: {
+ result.add(next);
+ keepGoing = includeAllMallocs;
+ break;
+ }
+ case FREE_OPERATION: {
+ result.add(next);
+ break;
+ }
+ case WRITE_OPERATION: {
+ if (numWrites < maxWrites) {
+ result.add(next);
+ }
+ numWrites++;
+ }
+ }
+ if (!keepGoing) {
+ break;
+ }
+ }
+
+ return new MemoryAccessLog(result);
+ }
+ }
+
+ private static Map<Integer, Tag> activeTags = new HashMap<>();
+ private final ArrayDeque<Tag> operationStack = new ArrayDeque<>();
+ private long[] buffer0;
+ private int[] buffer1;
+ private byte[] operation;
+ private int insertionPosition;
+ private int currentEntries;
+ private long timer;
+
+ public static final byte PUSH_OPERATION = 0;
+ public static final byte POP_OPERATION = 1;
+ public static final byte WRITE_OPERATION = 2;
+ public static final byte MALLOC_OPERATION = 3;
+ public static final byte FREE_OPERATION = 4;
+
+ public ModificationLog(int size) {
+ allocateBuffers(size);
+ }
+
+ public void clear() {
+ this.currentEntries = 0;
+ }
+
+ private void allocateBuffers(int sizeInMegs) {
+ int entries = getBufferEntriesFor(sizeInMegs);
+ if (entries != 0) {
+ this.buffer0 = new long[entries];
+ this.buffer1 = new int[entries];
+ this.operation = new byte[entries];
+ } else {
+ this.buffer0 = null;
+ this.buffer1 = null;
+ this.operation = null;
+ }
+ }
+
+ private static int getBufferEntriesFor(int sizeInMegs) {
+ int sizeOfABufferEntry = 8 + 4 + 1; // size, in bytes, of one long, one int, and one byte
+ return sizeInMegs * 1024 * 1024 / sizeOfABufferEntry;
+ }
+
+ public int getBufferEntries() {
+ return this.buffer0 == null ? 0 : this.buffer0.length;
+ }
+
+ public void setBufferSize(int megs) {
+ int oldBufferLength = getBufferEntries();
+ int newBufferLength = getBufferEntriesFor(megs);
+
+ if (oldBufferLength == newBufferLength) {
+ return;
+ }
+
+ long[] oldBuffer0 = this.buffer0;
+ int[] oldBuffer1 = this.buffer1;
+ byte[] oldOperation = this.operation;
+
+ allocateBuffers(megs);
+
+ if (this.buffer0 == null) {
+ this.currentEntries = 0;
+ this.insertionPosition = 0;
+ this.operationStack.clear();
+ return;
+ }
+ int newBufferSize = Math.min(this.buffer0.length, this.currentEntries);
+ if (oldBufferLength > 0) {
+ int readStart = (this.insertionPosition + oldBufferLength - newBufferSize) % oldBufferLength;
+ if (readStart >= this.insertionPosition) {
+ int entriesFromEnd = oldBufferLength - readStart;
+ System.arraycopy(oldBuffer0, readStart, this.buffer0, 0, entriesFromEnd);
+ System.arraycopy(oldBuffer1, readStart, this.buffer1, 0, entriesFromEnd);
+ System.arraycopy(oldOperation, readStart, this.operation, 0, entriesFromEnd);
+
+ System.arraycopy(oldBuffer0, 0, this.buffer0, entriesFromEnd, this.insertionPosition);
+ System.arraycopy(oldBuffer1, 0, this.buffer1, entriesFromEnd, this.insertionPosition);
+ System.arraycopy(oldOperation, 0, this.operation, entriesFromEnd, this.insertionPosition);
+ } else {
+ int entriesToCopy = this.insertionPosition - readStart;
+ System.arraycopy(oldBuffer0, readStart, this.buffer0, 0, entriesToCopy);
+ System.arraycopy(oldBuffer1, readStart, this.buffer1, 0, entriesToCopy);
+ System.arraycopy(oldOperation, readStart, this.operation, 0, entriesToCopy);
+ }
+ }
+
+ this.currentEntries = newBufferSize;
+ this.insertionPosition = newBufferSize % this.buffer0.length;
+ }
+
+ public static void indent(StringBuilder builder, int indent) {
+ for (int count = 0; count < indent; count++) {
+ builder.append(" "); //$NON-NLS-1$
+ }
+ }
+
+ public boolean enabled() {
+ return this.buffer0 != null;
+ }
+
+ public void start(Tag tag) {
+ if (!enabled()) {
+ return;
+ }
+
+ this.operationStack.add(tag);
+ addToQueue(PUSH_OPERATION, 0, tag.opNum);
+ }
+
+ public void end(Tag tag) {
+ if (!enabled()) {
+ return;
+ }
+ if (!this.operationStack.getLast().equals(tag)) {
+ throw new IllegalStateException();
+ }
+ this.operationStack.removeLast();
+ addToQueue(POP_OPERATION, 0, tag.opNum);
+ }
+
+ public void recordWrite(long address, int size) {
+ if (!enabled()) {
+ return;
+ }
+ this.timer++;
+ addToQueue(WRITE_OPERATION, address, size);
+ }
+
+ public void recordMalloc(long address, int size) {
+ if (!enabled()) {
+ return;
+ }
+ this.timer++;
+ addToQueue(MALLOC_OPERATION, address, size);
+ }
+
+ public void recordFree(long address, int size) {
+ if (!enabled()) {
+ return;
+ }
+ this.timer++;
+ addToQueue(FREE_OPERATION, address, size);
+ }
+
+ private void addToQueue(byte opConstant, long arg0, int arg1) {
+ this.buffer0[this.insertionPosition] = arg0;
+ this.buffer1[this.insertionPosition] = arg1;
+ this.operation[this.insertionPosition] = opConstant;
+ this.insertionPosition = (this.insertionPosition + 1) % this.buffer0.length;
+
+ if (this.currentEntries < this.buffer0.length) {
+ this.currentEntries++;
+ }
+ }
+
+ public long getWriteCount() {
+ return this.timer;
+ }
+
+ /**
+ * Returns information about the last write to the given address range
+ */
+ public MemoryAccessLog getReportFor(long address, int size) {
+ List<Tag> tags = new ArrayList<>();
+ tags.addAll(this.operationStack);
+
+ List<MemoryOperation> operations = new ArrayList<>();
+ if (this.buffer0 != null) {
+ int pointerToStart = (this.insertionPosition + this.buffer0.length - this.currentEntries) % this.buffer0.length;
+ int currentPosition = (this.insertionPosition + this.buffer0.length - 1) % this.buffer0.length;
+ long currentWrite = this.timer;
+ do {
+ long nextAddress = this.buffer0[currentPosition];
+ int nextArgument = this.buffer1[currentPosition];
+ byte nextOp = this.operation[currentPosition];
+
+ switch (nextOp) {
+ case POP_OPERATION: {
+ tags.add(getTagForId(nextArgument));
+ break;
+ }
+ case PUSH_OPERATION: {
+ tags.remove(tags.size() - 1);
+ break;
+ }
+ default: {
+ boolean isMatch = false;
+ if (address < nextAddress) {
+ long diff = nextAddress - address;
+ if (diff < size) {
+ isMatch = true;
+ }
+ } else {
+ long diff = address - nextAddress;
+ if (diff < nextArgument) {
+ isMatch = true;
+ }
+ }
+
+ if (isMatch) {
+ List<Tag> stack = new ArrayList<>();
+ stack.addAll(tags);
+ MemoryOperation nextOperation = new MemoryOperation(nextOp, currentWrite, nextAddress,
+ nextArgument, stack);
+ operations.add(nextOperation);
+ }
+
+ currentWrite--;
+ }
+ }
+ currentPosition = (currentPosition + this.buffer0.length - 1) % this.buffer0.length;
+ } while (currentPosition != pointerToStart);
+ }
+ return new MemoryAccessLog(operations);
+ }
+
+ public static Tag createTag(String tagName) {
+ Tag result = new Tag(tagName, activeTags.size());
+ activeTags.put(activeTags.size(), result);
+ return result;
+ }
+
+ private Tag getTagForId(int nextArgument) {
+ return activeTags.get(nextArgument);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/RelatedAddress.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/RelatedAddress.java
new file mode 100644
index 0000000000..c665b916c3
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/RelatedAddress.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd.db;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.MemoryAccessLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.MemoryOperation;
+
+/**
+ * Holds information about a memory range that was related to the cause of data corruption.
+ */
+public class RelatedAddress {
+ private final String description;
+ private final long address;
+ private final int size;
+ private final MemoryAccessLog modificationReport;
+
+ public RelatedAddress(String description, long address, int size, MemoryAccessLog lastModification) {
+ this.description = description;
+ this.address = address;
+ this.size = size;
+ this.modificationReport = lastModification;
+ }
+
+ boolean isSameAddressAs(RelatedAddress other) {
+ return other.address == this.address && other.size == this.size;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(this.description);
+ builder.append(" [address "); //$NON-NLS-1$
+ builder.append(this.address);
+ builder.append(", size "); //$NON-NLS-1$
+ builder.append(this.size);
+ builder.append("]: "); //$NON-NLS-1$
+ MemoryAccessLog reducedReport = this.modificationReport.reduce(5);
+ List<MemoryOperation> operations = reducedReport.getOperations();
+ if (operations.isEmpty()) {
+ builder.append("No modification report"); //$NON-NLS-1$
+ } else {
+ builder.append("\n"); //$NON-NLS-1$
+ for (MemoryOperation nextOperation : operations) {
+ nextOperation.printTo(builder, 1);
+ }
+ }
+ return builder.toString();
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/BaseField.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/BaseField.java
new file mode 100644
index 0000000000..28f4478df8
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/BaseField.java
@@ -0,0 +1,25 @@
+package org.eclipse.jdt.internal.core.nd.field;
+
+abstract class BaseField implements IField {
+ protected int offset;
+ private String fieldName;
+
+ protected final void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public final void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ @Override
+ public final int getOffset() {
+ return this.offset;
+ }
+
+ @Override
+ public final String getFieldName() {
+ return this.fieldName;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java
index bab45d4ddb..f596d883de 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java
@@ -12,6 +12,7 @@ package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.ITypeFactory;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Used to represent a single field of an object stored in the database. Objects
@@ -28,11 +29,12 @@ import org.eclipse.jdt.internal.core.nd.Nd;
*
* @param <T>
*/
-public final class Field<T> implements IField, IDestructableField {
- private int offset;
+public final class Field<T> extends BaseField implements IDestructableField {
public final ITypeFactory<T> factory;
- public Field(ITypeFactory<T> objectFactory) {
+ public Field(ITypeFactory<T> objectFactory, String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
this.factory = objectFactory;
}
@@ -50,12 +52,34 @@ public final class Field<T> implements IField, IDestructableField {
}
@Override
- public void setOffset(int offset) {
- this.offset = offset;
+ public int getRecordSize() {
+ return this.factory.getRecordSize();
}
@Override
- public int getRecordSize() {
- return this.factory.getRecordSize();
+ public int getAlignment() {
+ // This sort of field is almost always used for embedding NdStructs within
+ // other data types. Since most NdStructs allow incoming record pointers, they need to
+ // be properly aligned. If we ever want to use this sort of field for other data types
+ // that don't require alignment, we may want to replace this with something smarter
+ // that can figure out the correct alignment based on the requirements of the actual
+ // data type.
+ return Database.BLOCK_SIZE_DELTA;
+ }
+
+ /**
+ * Creates a new {@link Field} in the given struct with the given type.
+ *
+ * @param struct the struct that will contain the newly-created field (must not have had
+ * {@link StructDef#done()} called on it yet).
+ * @param fieldType the data type for the contents of the newly created field
+ * @return the newly-constructed field
+ */
+ public static <T> Field<T> create(StructDef<?> struct, StructDef<T> fieldType) {
+ Field<T> result = new Field<>(fieldType.getFactory(), struct.getStructName(), struct.getNumFields());
+ struct.add(result);
+ struct.addDestructableField(result);
+ fieldType.addDependency(struct);
+ return result;
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldByte.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldByte.java
index c7a9ef5e03..4bb0b88d51 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldByte.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldByte.java
@@ -11,16 +11,20 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Declares a Nd field of type byte. Can be used in place of {@link Field}&lt{@link Byte}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldByte implements IField {
- private int offset;
+public class FieldByte extends BaseField {
+ private final Tag tag;
- public FieldByte() {
+ public FieldByte(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() + " in struct " + structName); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ this.tag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public byte get(Nd nd, long address) {
@@ -29,12 +33,13 @@ public class FieldByte implements IField {
}
public void put(Nd nd, long address, byte newValue) {
- nd.getDB().putByte(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.tag);
+ try {
+ db.putByte(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.tag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldChar.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldChar.java
index e4b0e178a6..95f50d4680 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldChar.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldChar.java
@@ -11,16 +11,20 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Declares a Nd field of type char. Can be used in place of {@link Field}&lt{@link Character}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldChar implements IField {
- private int offset;
+public class FieldChar extends BaseField {
+ private final Tag tag;
- public FieldChar() {
+ public FieldChar(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() + " in struct " + structName); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ this.tag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public char get(Nd nd, long address) {
@@ -29,12 +33,13 @@ public class FieldChar implements IField {
}
public void put(Nd nd, long address, char newValue) {
- nd.getDB().putChar(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.tag);
+ try {
+ nd.getDB().putChar(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.tag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldDouble.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldDouble.java
index f0932e2098..535085fc80 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldDouble.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldDouble.java
@@ -11,16 +11,20 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
/**
- * Declares a Nd field of type double. Can be used in place of {@link Field}&lt{@link Double}&gt in order to
+ * Declares a Nd field of type double. Can be used in place of {@link Field}&lt{@link Double}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldDouble implements IField {
- private int offset;
+public class FieldDouble extends BaseField {
+ private final Tag tag;
- public FieldDouble() {
+ public FieldDouble(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() + " in struct " + structName); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ this.tag = ModificationLog.createTag("Writing "); //$NON-NLS-1$
}
public double get(Nd nd, long address) {
@@ -29,12 +33,13 @@ public class FieldDouble implements IField {
}
public void put(Nd nd, long address, double newValue) {
- nd.getDB().putDouble(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.tag);
+ try {
+ nd.getDB().putDouble(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.tag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldFloat.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldFloat.java
index 4ddd093111..5c8b0844e9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldFloat.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldFloat.java
@@ -11,16 +11,20 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Declares a Nd field of type float. Can be used in place of {@link Field}&lt{@link Float}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldFloat implements IField {
- private int offset;
+public class FieldFloat extends BaseField {
+ private final Tag tag;
- public FieldFloat() {
+ public FieldFloat(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() + " in struct " + structName); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ this.tag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public float get(Nd nd, long address) {
@@ -29,12 +33,13 @@ public class FieldFloat implements IField {
}
public void put(Nd nd, long address, float newValue) {
- nd.getDB().putFloat(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.tag);
+ try {
+ nd.getDB().putFloat(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.tag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldInt.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldInt.java
index 06e9b8a717..a524a9f602 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldInt.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldInt.java
@@ -11,16 +11,20 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
/**
* Declares a Nd field of type int. Can be used in place of {@link Field}&lt{@link Integer}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldInt implements IField {
- private int offset;
+public class FieldInt extends BaseField {
+ private final Tag tag;
- public FieldInt() {
+ public FieldInt(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() + " in struct " + structName); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ this.tag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public int get(Nd nd, long address) {
@@ -29,12 +33,13 @@ public class FieldInt implements IField {
}
public void put(Nd nd, long address, int newValue) {
- nd.getDB().putInt(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.tag);
+ try {
+ nd.getDB().putInt(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.tag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java
new file mode 100644
index 0000000000..b2c5ec70a6
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd.field;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.ITypeFactory;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
+import org.eclipse.jdt.internal.core.nd.util.MathUtils;
+
+/**
+ * Stores a singly-linked list of blocks, each of which contains a variable number of embedded elements.
+ * Each block contains a header containing the size of the block and pointer to the next block, followed
+ * by the embedded elements themselves.
+ */
+public class FieldList<T> extends BaseField implements IDestructableField {
+ /**
+ * Pointer to the first block.
+ */
+ public final static FieldPointer FIRST_BLOCK;
+ /**
+ * Pointer to the block where insertions are currently happening. This is only null if there are no allocated
+ * blocks. If there are any blocks containing elements, this points to the last block with a nonzero number of
+ * elements.
+ */
+ public final static FieldPointer LAST_BLOCK_WITH_ELEMENTS;
+
+ @SuppressWarnings("rawtypes")
+ private static final StructDef<FieldList> type;
+ private static final int LIST_HEADER_BYTES;
+ private static final long MAX_BYTES_IN_A_CHUNK = Database.getBytesThatFitInChunks(1);
+
+ private final StructDef<T> elementType;
+ private final int elementsPerBlock;
+ private final StructDef<?> ownerType;
+ private final Tag allocateTag;
+ private final Tag appendTag;
+ private final Tag destructTag;
+
+ static {
+ type = StructDef.createAbstract(FieldList.class);
+ FIRST_BLOCK = type.addPointer();
+ LAST_BLOCK_WITH_ELEMENTS = type.addPointer();
+
+ type.done();
+ LIST_HEADER_BYTES = MathUtils.roundUpToNearestMultipleOfPowerOfTwo(type.size(), Database.BLOCK_SIZE_DELTA);
+ }
+
+ private static class BlockHeader {
+ // This points to the next block if there is one, or null if not.
+ public final static FieldPointer NEXT_BLOCK;
+ public final static FieldShort BLOCK_SIZE;
+ public final static FieldShort ELEMENTS_IN_USE;
+ public static final int BLOCK_HEADER_BYTES;
+
+ @SuppressWarnings("hiding")
+ private static final StructDef<BlockHeader> type;
+
+ static {
+ type = StructDef.createAbstract(BlockHeader.class);
+
+ NEXT_BLOCK = type.addPointer();
+ BLOCK_SIZE = type.addShort();
+ ELEMENTS_IN_USE = type.addShort();
+ type.done();
+
+ BLOCK_HEADER_BYTES = MathUtils.roundUpToNearestMultipleOfPowerOfTwo(type.size(), Database.BLOCK_SIZE_DELTA);
+ }
+ }
+
+ private FieldList(StructDef<?> ownerType, StructDef<T> elementType, int elementsPerBlock) {
+ this.elementType = elementType;
+ this.elementsPerBlock = elementsPerBlock;
+ this.ownerType = ownerType;
+ int fieldNumber = ownerType.getNumFields();
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + ownerType.getStructName());//$NON-NLS-1$
+ this.allocateTag = ModificationLog.createTag("Allocating elements for " + getFieldName()); //$NON-NLS-1$
+ this.appendTag = ModificationLog.createTag("Appending to " + getFieldName()); //$NON-NLS-1$
+ this.destructTag = ModificationLog.createTag("Deallocating " + getFieldName()); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a new {@link FieldList} in the given struct which contains elements of the given type. The resulting list
+ * will grow by 1 element each time it overflows.
+ *
+ * @param ownerStruct
+ * the struct to which the new list field will be added. Must not have had {@link StructDef#done()}
+ * invoked on it yet.
+ * @param elementType
+ * the type of elements that will be contained in the struct.
+ * @return a newly-constructed list field in the given struct.
+ */
+ public static <T> FieldList<T> create(StructDef<?> ownerStruct, StructDef<T> elementType) {
+ return create(ownerStruct, elementType, 1);
+ }
+
+ /**
+ * Creates a new {@link FieldList} in the given struct which contains elements of the given type. The resulting list
+ * will grow by the given number of elements each time it overflows.
+ *
+ * @param ownerStruct
+ * the struct to which the new list field will be added. Must not have had {@link StructDef#done()}
+ * invoked on it yet.
+ * @param elementType
+ * the type of elements that will be contained in the struct.
+ * @param elementsPerBlock
+ * the number of elements that will be allocated each time the list overflows.
+ * @return a newly-constructed list field in the given struct.
+ */
+ public static <T> FieldList<T> create(StructDef<?> ownerStruct, StructDef<T> elementType, int elementsPerBlock) {
+ FieldList<T> result = new FieldList<>(ownerStruct, elementType, elementsPerBlock);
+ ownerStruct.add(result);
+ ownerStruct.addDestructableField(result);
+ return result;
+ }
+
+ private int getElementSize() {
+ int recordSize = this.elementType.getFactory().getRecordSize();
+ return MathUtils.roundUpToNearestMultipleOfPowerOfTwo(recordSize, Database.BLOCK_SIZE_DELTA);
+ }
+
+ @Override
+ public int getRecordSize() {
+ return LIST_HEADER_BYTES;
+ }
+
+ /**
+ * Returns the contents of the receiver as a {@link List}.
+ *
+ * @param nd the database to be queried.
+ * @param address the address of the parent struct
+ */
+ public List<T> asList(Nd nd, long address) {
+ long headerStartAddress = address + this.offset;
+ long firstBlockAddress = FIRST_BLOCK.get(nd, headerStartAddress);
+
+ List<T> result = new ArrayList<>();
+
+ long nextBlockAddress = firstBlockAddress;
+ while (nextBlockAddress != 0) {
+ long currentBlockAddress = nextBlockAddress;
+ nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress);
+ int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress);
+ long firstElementInBlockAddress = currentBlockAddress + BlockHeader.BLOCK_HEADER_BYTES;
+
+ readElements(result, nd, firstElementInBlockAddress, elementsInBlock);
+ }
+
+ return result;
+ }
+
+ private void readElements(List<T> result, Nd nd, long nextElementAddress, int count) {
+ ITypeFactory<T> factory = this.elementType.getFactory();
+
+ int size = getElementSize();
+ for (; count > 0; count--) {
+ result.add(factory.create(nd, nextElementAddress));
+ nextElementAddress += size;
+ }
+ }
+
+ public T append(Nd nd, long address) {
+ Database db = nd.getDB();
+ db.getLog().start(this.appendTag);
+ try {
+ long headerStartAddress = address + this.offset;
+ long nextBlockAddress = LAST_BLOCK_WITH_ELEMENTS.get(nd, headerStartAddress);
+
+ // Ensure that there's at least one block
+ long insertionBlockAddress = nextBlockAddress;
+ if (nextBlockAddress == 0) {
+ long newBlockAddress = allocateNewBlock(nd, this.elementsPerBlock);
+ LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, newBlockAddress);
+ FIRST_BLOCK.put(nd, headerStartAddress, newBlockAddress);
+ insertionBlockAddress = newBlockAddress;
+ }
+
+ // Check if there's any free space in this block
+ int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress);
+ int blockSize = BlockHeader.BLOCK_SIZE.get(nd, insertionBlockAddress);
+
+ if (elementsInBlock >= blockSize) {
+ long nextBlock = BlockHeader.NEXT_BLOCK.get(nd, insertionBlockAddress);
+ if (nextBlock == 0) {
+ nextBlock = allocateNewBlock(nd, this.elementsPerBlock);
+ BlockHeader.NEXT_BLOCK.put(nd, insertionBlockAddress, nextBlock);
+ }
+ LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, nextBlock);
+ insertionBlockAddress = nextBlock;
+ elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress);
+ }
+
+ BlockHeader.ELEMENTS_IN_USE.put(nd, insertionBlockAddress, (short) (elementsInBlock + 1));
+ int elementSize = getElementSize();
+
+ long resultAddress = insertionBlockAddress + BlockHeader.BLOCK_HEADER_BYTES + elementsInBlock * elementSize;
+ assert ((resultAddress - Database.BLOCK_HEADER_SIZE) & (Database.BLOCK_SIZE_DELTA - 1)) == 0;
+ return this.elementType.getFactory().create(nd, resultAddress);
+ } finally {
+ db.getLog().end(this.appendTag);
+ }
+ }
+
+ /**
+ * Ensures that the receiver will have space for the given number of elements without additional
+ * allocation. Callers should invoke this prior to a sequence of {@link FieldList#append(Nd, long)}
+ * calls if they know in advance how many elements will be appended. Will create the minimum number
+ * of extra blocks needed to the given number of additional elements.
+ */
+ public void allocate(Nd nd, long address, int numElements) {
+ Database db = nd.getDB();
+ db.getLog().start(this.allocateTag);
+ try {
+ if (numElements == 0) {
+ // Not an error, but there's nothing to do if the caller didn't actually ask for anything to be allocated.
+ return;
+ }
+ long headerStartAddress = address + this.offset;
+ long nextBlockAddress = LAST_BLOCK_WITH_ELEMENTS.get(nd, headerStartAddress);
+
+ int maxBlockSizeThatFitsInAChunk = (int) ((MAX_BYTES_IN_A_CHUNK - BlockHeader.BLOCK_HEADER_BYTES)
+ / getElementSize());
+
+ // Ensure that there's at least one block
+ if (nextBlockAddress == 0) {
+ int firstAllocation = Math.min(numElements, maxBlockSizeThatFitsInAChunk);
+ nextBlockAddress = allocateNewBlock(nd, firstAllocation);
+ LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, nextBlockAddress);
+ FIRST_BLOCK.put(nd, headerStartAddress, nextBlockAddress);
+ }
+
+ // Check if there's any free space in this block
+ int remainingToAllocate = numElements;
+ while (true) {
+ long currentBlockAddress = nextBlockAddress;
+ nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress);
+ int elementsInUse = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress);
+ int blockSize = BlockHeader.BLOCK_SIZE.get(nd, currentBlockAddress);
+
+ remainingToAllocate -= (blockSize - elementsInUse);
+ if (remainingToAllocate <= 0) {
+ break;
+ }
+
+ if (nextBlockAddress == 0) {
+ nextBlockAddress = allocateNewBlock(nd, Math.min(maxBlockSizeThatFitsInAChunk, numElements));
+ BlockHeader.NEXT_BLOCK.put(nd, currentBlockAddress, nextBlockAddress);
+ }
+ }
+ } finally {
+ db.getLog().end(this.allocateTag);
+ }
+ }
+
+ private long allocateNewBlock(Nd nd, int blockSize) {
+ short poolId = getMemoryPoolId(nd);
+ int elementSize = getElementSize();
+ long bytesNeeded = BlockHeader.BLOCK_HEADER_BYTES + blockSize * elementSize;
+ // If we're close enough to filling the chunk that we wouldn't be able to fit any more elements anyway, allocate
+ // the entire chunk. Although it wastes a small amount of space, it ensures that the blocks can be more easily
+ // reused rather than being fragmented. It also allows freed blocks to be merged via the large block allocator.
+ if (MAX_BYTES_IN_A_CHUNK - bytesNeeded < elementSize) {
+ bytesNeeded = MAX_BYTES_IN_A_CHUNK;
+ }
+ long result = nd.getDB().malloc(bytesNeeded, poolId);
+ BlockHeader.BLOCK_SIZE.put(nd, result, (short) blockSize);
+ return result;
+ }
+
+ private short getMemoryPoolId(Nd nd) {
+ short poolId = Database.POOL_LINKED_LIST;
+ if (this.ownerType != null) {
+ Class<?> structClass = this.ownerType.getStructClass();
+ if (nd.getTypeRegistry().isRegisteredClass(structClass)) {
+ poolId = (short) (Database.POOL_FIRST_NODE_TYPE + nd.getNodeType(structClass));
+ }
+ }
+ return poolId;
+ }
+
+ @Override
+ public void destruct(Nd nd, long address) {
+ Database db = nd.getDB();
+ db.getLog().start(this.destructTag);
+ try {
+ short poolId = getMemoryPoolId(nd);
+ long headerStartAddress = address + this.offset;
+ long firstBlockAddress = FIRST_BLOCK.get(nd, headerStartAddress);
+
+ long nextBlockAddress = firstBlockAddress;
+ while (nextBlockAddress != 0) {
+ long currentBlockAddress = nextBlockAddress;
+ nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress);
+ int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress);
+ destructElements(nd, currentBlockAddress + BlockHeader.BLOCK_HEADER_BYTES, elementsInBlock);
+ db.free(currentBlockAddress, poolId);
+ }
+
+ db.clearRange(headerStartAddress, getRecordSize());
+ } finally {
+ db.getLog().end(this.destructTag);
+ }
+ }
+
+ private void destructElements(Nd nd, long nextElementAddress, int count) {
+ ITypeFactory<T> factory = this.elementType.getFactory();
+
+ int size = getElementSize();
+ while (--count >= 0) {
+ factory.destruct(nd, nextElementAddress);
+ nextElementAddress += size;
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldLong.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldLong.java
index 6a66ac26ff..93ad1ba11f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldLong.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldLong.java
@@ -11,16 +11,20 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Declares a Nd field of type long. Can be used in place of {@link Field}&lt{@link Long}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldLong implements IField {
- private int offset;
+public class FieldLong extends BaseField {
+ private final Tag tag;
- public FieldLong() {
+ public FieldLong(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() + " in struct " + structName); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ this.tag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public long get(Nd nd, long address) {
@@ -29,12 +33,13 @@ public class FieldLong implements IField {
}
public void put(Nd nd, long address, long newValue) {
- nd.getDB().putLong(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.tag);
+ try {
+ nd.getDB().putLong(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.tag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java
index ed644953d0..4d3d4b1acb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java
@@ -10,9 +10,13 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.field;
+import org.eclipse.jdt.internal.core.nd.INdStruct;
import org.eclipse.jdt.internal.core.nd.ITypeFactory;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
/**
* Holds the n side of a n..1 relationship. Declares a Nd field which is a pointer of a NdNode of the specified
@@ -20,13 +24,12 @@ import org.eclipse.jdt.internal.core.nd.NdNode;
* {@link FieldManyToOne} points to an object, the inverse pointer is automatically inserted into the matching back
* pointer list.
*/
-public class FieldManyToOne<T extends NdNode> implements IDestructableField, IField, IRefCountedField {
+public class FieldManyToOne<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField {
public final static FieldPointer TARGET;
public final static FieldInt BACKPOINTER_INDEX;
- private int offset;
- Class<T> targetType;
- final Class<? extends NdNode> localType;
+ StructDef<T> targetType;
+ final StructDef<? extends INdStruct> localType;
FieldOneToMany<?> backPointer;
@SuppressWarnings("rawtypes")
private final static StructDef<FieldManyToOne> type;
@@ -34,6 +37,9 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
* True iff the other end of this pointer should delete this object when its end of the pointer is cleared.
*/
public final boolean pointsToOwner;
+ private final Tag putTag;
+ private final Tag destructTag;
+ private boolean permitsNull = true;
static {
type = StructDef.createAbstract(FieldManyToOne.class);
@@ -43,7 +49,7 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- private FieldManyToOne(Class<? extends NdNode> localType, FieldOneToMany<?> backPointer, boolean pointsToOwner) {
+ private FieldManyToOne(StructDef<? extends INdStruct> localType, FieldOneToMany<?> backPointer, boolean pointsToOwner) {
this.localType = localType;
this.pointsToOwner = pointsToOwner;
@@ -53,16 +59,27 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
"Attempted to construct a FieldNodePointer referring to a backpointer list that is already in use" //$NON-NLS-1$
+ " by another field"); //$NON-NLS-1$
}
- backPointer.targetType = (Class) localType;
- this.targetType = (Class) backPointer.localType;
+ backPointer.targetType = (StructDef) localType;
+ this.targetType = (StructDef) backPointer.localType;
backPointer.forwardPointer = this;
}
this.backPointer = backPointer;
+ setFieldName("field " + localType.getNumFields() + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + localType.getStructName()); //$NON-NLS-1$
+ this.putTag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
+ this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$
}
- public static <T extends NdNode, B extends NdNode> FieldManyToOne<T> create(StructDef<B> builder,
+ public static <T extends INdStruct, B extends INdStruct> FieldManyToOne<T> createNonNull(StructDef<B> builder,
FieldOneToMany<B> forwardPointer) {
- FieldManyToOne<T> result = new FieldManyToOne<T>(builder.getStructClass(), forwardPointer, false);
+ FieldManyToOne<T> result = create(builder, forwardPointer);
+ result.permitsNull = false;
+ return result;
+ }
+
+ public static <T extends INdStruct, B extends INdStruct> FieldManyToOne<T> create(StructDef<B> builder,
+ FieldOneToMany<B> forwardPointer) {
+ FieldManyToOne<T> result = new FieldManyToOne<T>(builder, forwardPointer, false);
builder.add(result);
builder.addDestructableField(result);
return result;
@@ -76,22 +93,48 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
* @param forwardPointer the field which holds the pointer in the other direction
* @return a newly constructed field
*/
- public static <T extends NdNode, B extends NdNode> FieldManyToOne<T> createOwner(StructDef<B> builder,
+ public static <T extends INdStruct, B extends INdStruct> FieldManyToOne<T> createOwner(StructDef<B> builder,
FieldOneToMany<B> forwardPointer) {
+ // Although it would work to have a non-NdNode owned in this manner, we currently have no legitimate use-cases
+ // for this to occur. If this happens it is almost certainly an accidental copy-paste error where someone
+ // intended to call create but called this method instead. If we ever discover a legitimate use-case for it,
+ // this could be removed and things would probably still work.
+ if (!NdNode.class.isAssignableFrom(builder.getStructClass())) {
+ throw new IllegalArgumentException(FieldManyToOne.class.getSimpleName() + " can't be the owner of " //$NON-NLS-1$
+ + builder.getStructClass().getSimpleName() + " because the latter isn't a subclass of " //$NON-NLS-1$
+ + NdNode.class.getSimpleName());
+ }
- FieldManyToOne<T> result = new FieldManyToOne<T>(builder.getStructClass(), forwardPointer, true);
+ FieldManyToOne<T> result = new FieldManyToOne<T>(builder, forwardPointer, true);
builder.add(result);
builder.addDestructableField(result);
builder.addOwnerField(result);
return result;
}
+ /**
+ * Sets whether or not this field permits nulls to be assigned.
+ *
+ * @param permitted true iff the field permits nulls
+ * @return this
+ */
+ public FieldManyToOne<T> permitNull(boolean permitted) {
+ this.permitsNull = permitted;
+ return this;
+ }
+
public T get(Nd nd, long address) {
return NdNode.load(nd, getAddress(nd, address), this.targetType);
}
public long getAddress(Nd nd, long address) {
- return nd.getDB().getRecPtr(address + this.offset);
+ long result = nd.getDB().getRecPtr(address + this.offset);
+ if (!this.permitsNull && result == 0) {
+ throw nd.describeProblem()
+ .addProblemAddress(this, address)
+ .build("Database contained a null in a non-null field"); //$NON-NLS-1$
+ }
+ return result;
}
/**
@@ -100,34 +143,43 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
*/
public void put(Nd nd, long address, T value) {
if (value != null) {
- put(nd, address, value.address);
- } else {
+ put(nd, address, value.getAddress());
+ } else if (this.permitsNull) {
put(nd, address, 0);
+ } else {
+ throw new IllegalArgumentException("Attempted to write a null into a non-null field"); //$NON-NLS-1$
}
}
public void put(Nd nd, long address, long newTargetAddress) {
- long fieldStart = address + this.offset;
- if (this.backPointer == null) {
- throw new IllegalStateException("FieldNodePointer must be associated with a FieldBackPointer"); //$NON-NLS-1$
- }
-
- long oldTargetAddress = TARGET.get(nd, fieldStart);
- if (oldTargetAddress == newTargetAddress) {
- return;
- }
-
- detachFromOldTarget(nd, address, oldTargetAddress);
-
- TARGET.put(nd, fieldStart, newTargetAddress);
- if (newTargetAddress != 0) {
- // Note that newValue is the address of the backpointer list and record (the address of the struct
- // containing the forward pointer) is the value being inserted into the list.
- BACKPOINTER_INDEX.put(nd, fieldStart, this.backPointer.add(nd, newTargetAddress, address));
- } else {
- if (this.pointsToOwner) {
- nd.scheduleDeletion(address);
+ Database db = nd.getDB();
+ db.getLog().start(this.putTag);
+ try {
+ long fieldStart = address + this.offset;
+ if (this.backPointer == null) {
+ throw new IllegalStateException(
+ getClass().getSimpleName() + " must be associated with a " + FieldOneToMany.class.getSimpleName()); //$NON-NLS-1$
+ }
+
+ long oldTargetAddress = TARGET.get(nd, fieldStart);
+ if (oldTargetAddress == newTargetAddress) {
+ return;
}
+
+ detachFromOldTarget(nd, address, oldTargetAddress);
+
+ TARGET.put(nd, fieldStart, newTargetAddress);
+ if (newTargetAddress != 0) {
+ // Note that newValue is the address of the backpointer list and record (the address of the struct
+ // containing the forward pointer) is the value being inserted into the list.
+ BACKPOINTER_INDEX.put(nd, fieldStart, this.backPointer.add(nd, newTargetAddress, address));
+ } else {
+ if (this.pointsToOwner) {
+ nd.scheduleDeletion(address);
+ }
+ }
+ } finally {
+ db.getLog().end(this.putTag);
}
}
@@ -138,13 +190,14 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
this.backPointer.remove(nd, oldTargetAddress, oldIndex);
- short targetTypeId = NdNode.NODE_TYPE.get(nd, oldTargetAddress);
-
- ITypeFactory<T> typeFactory = nd.getTypeFactory(targetTypeId);
+ if (this.targetType.isNdNode()) {
+ short targetTypeId = NdNode.NODE_TYPE.get(nd, oldTargetAddress);
+ ITypeFactory<? extends NdNode> typeFactory = nd.getTypeFactory(targetTypeId);
- if (typeFactory.getDeletionSemantics() == StructDef.DeletionSemantics.REFCOUNTED
- && typeFactory.isReadyForDeletion(nd, oldTargetAddress)) {
- nd.scheduleDeletion(oldTargetAddress);
+ if (typeFactory.getDeletionSemantics() == StructDef.DeletionSemantics.REFCOUNTED
+ && typeFactory.isReadyForDeletion(nd, oldTargetAddress)) {
+ nd.scheduleDeletion(oldTargetAddress);
+ }
}
}
}
@@ -161,10 +214,16 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
@Override
public void destruct(Nd nd, long address) {
- long fieldStart = address + this.offset;
- long oldTargetAddress = TARGET.get(nd, fieldStart);
- detachFromOldTarget(nd, address, oldTargetAddress);
- TARGET.put(nd, fieldStart, 0);
+ Database db = nd.getDB();
+ db.getLog().start(this.destructTag);
+ try {
+ long fieldStart = address + this.offset;
+ long oldTargetAddress = TARGET.get(nd, fieldStart);
+ detachFromOldTarget(nd, address, oldTargetAddress);
+ TARGET.put(nd, fieldStart, 0);
+ } finally {
+ db.getLog().end(this.destructTag);
+ }
}
void clearedByBackPointer(Nd nd, long address) {
@@ -174,11 +233,6 @@ public class FieldManyToOne<T extends NdNode> implements IDestructableField, IFi
}
@Override
- public void setOffset(int offset) {
- this.offset = offset;
- }
-
- @Override
public int getRecordSize() {
return type.size();
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java
index ce1ebca78b..5b3952fabd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java
@@ -13,6 +13,7 @@ package org.eclipse.jdt.internal.core.nd.field;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jdt.internal.core.nd.INdStruct;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
import org.eclipse.jdt.internal.core.nd.RawGrowableArray;
@@ -21,10 +22,9 @@ import org.eclipse.jdt.internal.core.nd.RawGrowableArray;
* Holds the 1 side of a 1..n relationship between two objects. FieldNodePointer and FieldBackPointer fields always go
* together in pairs.
*/
-public class FieldOneToMany<T extends NdNode> implements IDestructableField, IRefCountedField, IField {
- private int offset;
- public Class<T> targetType;
- public final Class<? extends NdNode> localType;
+public class FieldOneToMany<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField {
+ public StructDef<T> targetType;
+ public final StructDef<? extends INdStruct> localType;
private final RawGrowableArray backPointerArray;
FieldManyToOne<?> forwardPointer;
@@ -33,7 +33,7 @@ public class FieldOneToMany<T extends NdNode> implements IDestructableField, IRe
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private FieldOneToMany(Class<? extends NdNode> localType, FieldManyToOne<? extends NdNode> forwardPointer,
+ private FieldOneToMany(StructDef<? extends INdStruct> localType, FieldManyToOne<? extends INdStruct> forwardPointer,
int inlineElements) {
this.localType = localType;
@@ -43,11 +43,13 @@ public class FieldOneToMany<T extends NdNode> implements IDestructableField, IRe
"Attempted to construct a FieldBackPointer referring to a forward pointer that is already in use" //$NON-NLS-1$
+ " by another field"); //$NON-NLS-1$
}
- forwardPointer.targetType = (Class)localType;
- this.targetType = (Class)forwardPointer.localType;
+ forwardPointer.targetType = (StructDef) localType;
+ this.targetType = (StructDef) forwardPointer.localType;
forwardPointer.backPointer = this;
}
this.forwardPointer = forwardPointer;
+ setFieldName("field " + localType.getNumFields() + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + localType.getStructName()); //$NON-NLS-1$
this.backPointerArray = new RawGrowableArray(inlineElements);
}
@@ -63,21 +65,20 @@ public class FieldOneToMany<T extends NdNode> implements IDestructableField, IRe
* offer a performance improvement. For relationships that will normally be empty, this should be 0.
* @return the newly constructed backpointer field
*/
- public static <T extends NdNode, B extends NdNode> FieldOneToMany<T> create(StructDef<B> builder,
+ public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder,
FieldManyToOne<B> forwardPointer, int inlineElementCount) {
- FieldOneToMany<T> result = new FieldOneToMany<T>(builder.getStructClass(), forwardPointer,
- inlineElementCount);
+ FieldOneToMany<T> result = new FieldOneToMany<T>(builder, forwardPointer, inlineElementCount);
builder.add(result);
builder.addDestructableField(result);
builder.addRefCountedField(result);
return result;
}
- public static <T extends NdNode, B extends NdNode> FieldOneToMany<T> create(StructDef<B> builder,
+ public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder,
FieldManyToOne<B> forwardPointer) {
return create(builder, forwardPointer, 0);
}
-
+
public void accept(Nd nd, long address, Visitor<T> visitor) {
int size = size(nd, address);
@@ -184,9 +185,4 @@ public class FieldOneToMany<T extends NdNode> implements IDestructableField, IRe
}
return !isEmpty(nd, address);
}
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
- }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java
index 00cb29345e..47d1d714dd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java
@@ -10,24 +10,28 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.field;
+import org.eclipse.jdt.internal.core.nd.INdStruct;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Represents a 1-to-0..1 relationship in a Nd database.
*/
-public class FieldOneToOne<T extends NdNode> implements IField, IDestructableField, IRefCountedField {
- private int offset;
- public final Class<T> nodeType;
+public class FieldOneToOne<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField {
+ public final StructDef<T> nodeType;
FieldOneToOne<?> backPointer;
private boolean pointsToOwner;
+ private final Tag putTag;
+ private final Tag destructTag;
/**
* @param nodeType
* @param backPointer
*/
- private FieldOneToOne(Class<T> nodeType, FieldOneToOne<?> backPointer, boolean pointsToOwner) {
+ private FieldOneToOne(StructDef<T> nodeType, FieldOneToOne<?> backPointer, boolean pointsToOwner) {
this.nodeType = nodeType;
if (backPointer != null) {
@@ -40,10 +44,14 @@ public class FieldOneToOne<T extends NdNode> implements IField, IDestructableFie
}
this.backPointer = backPointer;
this.pointsToOwner = pointsToOwner;
+ setFieldName("field " + nodeType.getNumFields() + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + nodeType.getStructName()); //$NON-NLS-1$
+ this.putTag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
+ this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$
}
- public static <T extends NdNode, B extends NdNode> FieldOneToOne<T> create(StructDef<B> builder,
- Class<T> nodeType, FieldOneToOne<B> forwardPointer) {
+ public static <T extends INdStruct, B extends INdStruct> FieldOneToOne<T> create(StructDef<B> builder,
+ StructDef<T> nodeType, FieldOneToOne<B> forwardPointer) {
FieldOneToOne<T> result = new FieldOneToOne<T>(nodeType, forwardPointer, false);
builder.add(result);
@@ -51,8 +59,8 @@ public class FieldOneToOne<T extends NdNode> implements IField, IDestructableFie
return result;
}
- public static <T extends NdNode, B extends NdNode> FieldOneToOne<T> createOwner(StructDef<B> builder,
- Class<T> nodeType, FieldOneToOne<B> forwardPointer) {
+ public static <T extends INdStruct, B extends INdStruct> FieldOneToOne<T> createOwner(StructDef<B> builder,
+ StructDef<T> nodeType, FieldOneToOne<B> forwardPointer) {
FieldOneToOne<T> result = new FieldOneToOne<T>(nodeType, forwardPointer, true);
builder.add(result);
@@ -68,21 +76,32 @@ public class FieldOneToOne<T extends NdNode> implements IField, IDestructableFie
public void put(Nd nd, long address, T target) {
Database db = nd.getDB();
- cleanup(nd, address);
- if (target == null) {
- db.putRecPtr(address + this.offset, 0);
- if (this.pointsToOwner) {
- nd.scheduleDeletion(address);
+ db.getLog().start(this.putTag);
+ try {
+ cleanup(nd, address);
+ if (target == null) {
+ db.putRecPtr(address + this.offset, 0);
+ if (this.pointsToOwner) {
+ nd.scheduleDeletion(address);
+ }
+ } else {
+ db.putRecPtr(address + this.offset, target.getAddress());
+ db.putRecPtr(target.getAddress() + this.backPointer.offset, address);
}
- } else {
- db.putRecPtr(address + this.offset, target.address);
- db.putRecPtr(target.address + this.backPointer.offset, address);
+ } finally {
+ db.getLog().end(this.putTag);
}
}
@Override
public void destruct(Nd nd, long address) {
- cleanup(nd, address);
+ Database db = nd.getDB();
+ db.getLog().start(this.destructTag);
+ try {
+ cleanup(nd, address);
+ } finally {
+ db.getLog().end(this.destructTag);
+ }
}
private void cleanup(Nd nd, long address) {
@@ -98,11 +117,6 @@ public class FieldOneToOne<T extends NdNode> implements IField, IDestructableFie
}
@Override
- public void setOffset(int offset) {
- this.offset = offset;
- }
-
- @Override
public int getRecordSize() {
return Database.PTR_SIZE;
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldPointer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldPointer.java
index fef317623c..e67e2519b4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldPointer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldPointer.java
@@ -11,12 +11,17 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
-public class FieldPointer implements IField {
- private int offset;
+public class FieldPointer extends BaseField {
+ private final Tag putTag;
- public FieldPointer() {
+ public FieldPointer(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
+ this.putTag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public long get(Nd nd, long address) {
@@ -25,12 +30,13 @@ public class FieldPointer implements IField {
}
public void put(Nd nd, long address, long newValue) {
- nd.getDB().putRecPtr(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.putTag);
+ try {
+ nd.getDB().putRecPtr(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.putTag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java
index c7f6a3a7d8..247da7d4ca 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java
@@ -17,6 +17,9 @@ import org.eclipse.jdt.internal.core.nd.ITypeFactory;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
import org.eclipse.jdt.internal.core.nd.db.BTree;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.IBTreeComparator;
import org.eclipse.jdt.internal.core.nd.db.IBTreeVisitor;
import org.eclipse.jdt.internal.core.nd.db.IString;
@@ -25,10 +28,10 @@ import org.eclipse.jdt.internal.core.nd.db.IndexException;
/**
* Declares a field representing a case-insensitive search tree over elements which are a subtype of NdNode.
*/
-public class FieldSearchIndex<T extends NdNode> implements IField, IDestructableField {
- private int offset;
+public class FieldSearchIndex<T extends NdNode> extends BaseField implements IDestructableField {
private final ITypeFactory<BTree> btreeFactory;
FieldSearchKey<?> searchKey;
+ private final Tag destructTag;
private static IResultRank anything = new IResultRank() {
@Override
public long getRank(Nd nd, long address) {
@@ -163,7 +166,7 @@ public class FieldSearchIndex<T extends NdNode> implements IField, IDestructable
protected abstract boolean acceptResult(long address);
}
- private FieldSearchIndex(FieldSearchKey<?> searchKey) {
+ private FieldSearchIndex(FieldSearchKey<?> searchKey, String structName, int fieldNumber) {
this.btreeFactory = BTree.getFactory(new IBTreeComparator() {
@Override
public int compare(Nd nd, long record1, long record2) {
@@ -188,12 +191,15 @@ public class FieldSearchIndex<T extends NdNode> implements IField, IDestructable
searchKey.searchIndex = this;
}
this.searchKey = searchKey;
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
+ this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$
}
public static <T extends NdNode, B> FieldSearchIndex<T> create(StructDef<B> builder,
final FieldSearchKey<B> searchKey) {
- FieldSearchIndex<T> result = new FieldSearchIndex<T>(searchKey);
+ FieldSearchIndex<T> result = new FieldSearchIndex<T>(searchKey, builder.getStructName(), builder.getNumFields());
builder.add(result);
builder.addDestructableField(result);
@@ -207,12 +213,13 @@ public class FieldSearchIndex<T extends NdNode> implements IField, IDestructable
@Override
public void destruct(Nd nd, long address) {
- this.btreeFactory.destruct(nd, address);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.destructTag);
+ try {
+ this.btreeFactory.destruct(nd, address);
+ } finally {
+ db.getLog().end(this.destructTag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchKey.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchKey.java
index 1b585cb5de..519afd5185 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchKey.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchKey.java
@@ -13,6 +13,8 @@ package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
import org.eclipse.jdt.internal.core.nd.db.BTree;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
import org.eclipse.jdt.internal.core.nd.db.EmptyString;
import org.eclipse.jdt.internal.core.nd.db.IString;
@@ -20,11 +22,12 @@ import org.eclipse.jdt.internal.core.nd.db.IString;
/**
* Represents a search key into a global search index.
*/
-public class FieldSearchKey<T> implements IField, IDestructableField {
- private int offset;
+public class FieldSearchKey<T> extends BaseField implements IDestructableField {
FieldSearchIndex<?> searchIndex;
+ private final Tag destructTag;
+ private final Tag putTag;
- private FieldSearchKey(FieldSearchIndex<?> searchIndex) {
+ private FieldSearchKey(FieldSearchIndex<?> searchIndex, String structName, int fieldNumber) {
if (searchIndex != null) {
if (searchIndex.searchKey != null && searchIndex.searchKey != this) {
throw new IllegalArgumentException(
@@ -34,6 +37,10 @@ public class FieldSearchKey<T> implements IField, IDestructableField {
searchIndex.searchKey = this;
}
this.searchIndex = searchIndex;
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
+ this.putTag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
+ this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$
}
/**
@@ -41,7 +48,7 @@ public class FieldSearchKey<T> implements IField, IDestructableField {
*/
public static <T, B extends NdNode> FieldSearchKey<T> create(StructDef<B> builder,
FieldSearchIndex<B> searchIndex) {
- FieldSearchKey<T> result = new FieldSearchKey<T>(searchIndex);
+ FieldSearchKey<T> result = new FieldSearchKey<T>(searchIndex, builder.getStructName(), builder.getNumFields());
builder.add(result);
builder.addDestructableField(result);
@@ -57,12 +64,17 @@ public class FieldSearchKey<T> implements IField, IDestructableField {
* Sets the value of the key and inserts it into the index if it is not already present
*/
public void put(Nd nd, long address, char[] newString) {
- cleanup(nd, address);
-
Database db = nd.getDB();
- BTree btree = this.searchIndex.get(nd, Database.DATA_AREA_OFFSET);
- db.putRecPtr(address + this.offset, db.newString(newString).getRecord());
- btree.insert(address);
+ db.getLog().start(this.putTag);
+ try {
+ cleanup(nd, address);
+
+ BTree btree = this.searchIndex.get(nd, Database.DATA_AREA_OFFSET);
+ db.putRecPtr(address + this.offset, db.newString(newString).getRecord());
+ btree.insert(address);
+ } finally {
+ db.getLog().end(this.putTag);
+ }
}
public IString get(Nd nd, long address) {
@@ -77,7 +89,13 @@ public class FieldSearchKey<T> implements IField, IDestructableField {
@Override
public void destruct(Nd nd, long address) {
- cleanup(nd, address);
+ Database db = nd.getDB();
+ db.getLog().start(this.destructTag);
+ try {
+ cleanup(nd, address);
+ } finally {
+ db.getLog().end(this.destructTag);
+ }
}
private void cleanup(Nd nd, long address) {
@@ -112,11 +130,6 @@ public class FieldSearchKey<T> implements IField, IDestructableField {
}
@Override
- public void setOffset(int offset) {
- this.offset = offset;
- }
-
- @Override
public int getRecordSize() {
return FieldString.RECORD_SIZE;
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldShort.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldShort.java
index fe2a56b2a0..ea3af54d8f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldShort.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldShort.java
@@ -11,16 +11,21 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
/**
* Declares a Nd field of type short. Can be used in place of {@link Field}&lt{@link Short}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldShort implements IField {
- private int offset;
+public class FieldShort extends BaseField {
+ private final Tag putTag;
- public FieldShort() {
+ public FieldShort(String structName, int fieldNumber) {
+ setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
+ this.putTag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$
}
public short get(Nd nd, long address) {
@@ -29,12 +34,13 @@ public class FieldShort implements IField {
}
public void put(Nd nd, long address, short newValue) {
- nd.getDB().putShort(address + this.offset, newValue);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.putTag);
+ try {
+ nd.getDB().putShort(address + this.offset, newValue);
+ } finally {
+ db.getLog().end(this.putTag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldString.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldString.java
index ddd4493805..f509e288c4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldString.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldString.java
@@ -11,6 +11,8 @@
package org.eclipse.jdt.internal.core.nd.field;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
import org.eclipse.jdt.internal.core.nd.db.Database;
import org.eclipse.jdt.internal.core.nd.db.EmptyString;
import org.eclipse.jdt.internal.core.nd.db.IString;
@@ -19,12 +21,18 @@ import org.eclipse.jdt.internal.core.nd.db.IString;
* Declares a Nd field of type string. Can be used in place of {@link Field}&lt{@link String}&gt in order to
* avoid extra GC overhead.
*/
-public class FieldString implements IDestructableField, IField {
+public class FieldString extends BaseField implements IDestructableField {
public static final int RECORD_SIZE = Database.STRING_SIZE;
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
- private int offset;
+ private final Tag putTag;
+ private final Tag destructTag;
- public FieldString() {
+ public FieldString(String structName, int fieldNumber) {
+ this.putTag = ModificationLog.createTag("Writing field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
+ this.destructTag = ModificationLog
+ .createTag("Destructing field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
+ + " in struct " + structName); //$NON-NLS-1$
}
public IString get(Nd nd, long address) {
@@ -38,18 +46,23 @@ public class FieldString implements IDestructableField, IField {
}
public void put(Nd nd, long address, char[] newString) {
- if (newString == null) {
- newString = EMPTY_CHAR_ARRAY;
- }
- final Database db= nd.getDB();
- IString name= get(nd, address);
- if (name.compare(newString, true) != 0) {
- name.delete();
- if (newString != null && newString.length > 0) {
- db.putRecPtr(address + this.offset, db.newString(newString).getRecord());
- } else {
- db.putRecPtr(address + this.offset, 0);
+ Database db = nd.getDB();
+ db.getLog().start(this.putTag);
+ try {
+ if (newString == null) {
+ newString = EMPTY_CHAR_ARRAY;
}
+ IString name= get(nd, address);
+ if (name.compare(newString, true) != 0) {
+ name.delete();
+ if (newString != null && newString.length > 0) {
+ db.putRecPtr(address + this.offset, db.newString(newString).getRecord());
+ } else {
+ db.putRecPtr(address + this.offset, 0);
+ }
+ }
+ } finally {
+ db.getLog().end(this.putTag);
}
}
@@ -58,13 +71,14 @@ public class FieldString implements IDestructableField, IField {
}
public void destruct(Nd nd, long address) {
- get(nd, address).delete();
- nd.getDB().putRecPtr(address + this.offset, 0);
- }
-
- @Override
- public void setOffset(int offset) {
- this.offset = offset;
+ Database db = nd.getDB();
+ db.getLog().start(this.destructTag);
+ try {
+ get(nd, address).delete();
+ nd.getDB().putRecPtr(address + this.offset, 0);
+ } finally {
+ db.getLog().end(this.destructTag);
+ }
}
@Override
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java
index 979a0eb7de..78a793e4e5 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IField.java
@@ -10,7 +10,47 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.field;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+
+/**
+ * Represents a single field of a struct in the {@link Database}. Holds metadata for that field
+ * and permits laziy initialization of the field offset. Fields are normally instantiated as static
+ * variables. Collectively, they describe the database schema but they are not associated with any
+ * particular instance of data in the database.
+ * <p>
+ * Fields are temporarily mutable. On construction, a number of attributes (such as offset) are
+ * computed in a second pass or are initialized as other fields are constructed. Generally such
+ * attributes can't be computed in the constructor since they depend on knowledge of other fields
+ * that must be instantiated first. However, once {@link StructDef#done()} has been called on the
+ * last {@link StructDef}, fields are immutable and should not ever be modified again.
+ */
public interface IField {
+ /**
+ * Sets the field offset (bytes from the start of the struct). This is invoked some time after field construction,
+ * after the sizes of all preceeding fields are known.
+ */
void setOffset(int offset);
+
+ /**
+ * Returns the size of the field, in bytes.
+ */
int getRecordSize();
+
+ /**
+ * Returns the required byte alignment for the field.
+ */
+ default int getAlignment() {
+ return 1;
+ }
+
+ /**
+ * Returns the name of the field. This is mainly used for error messages, debug output, and diagnostic tools.
+ * Meant to be programmer-readable but not user-readable.
+ */
+ String getFieldName();
+
+ /**
+ * Returns the field offset, in bytes from the start of the struct.
+ */
+ int getOffset();
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java
index 261e85371b..9fe5571b50 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java
@@ -15,11 +15,18 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import org.eclipse.jdt.internal.core.nd.IDestructable;
import org.eclipse.jdt.internal.core.nd.ITypeFactory;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog;
+import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
+import org.eclipse.jdt.internal.core.nd.util.MathUtils;
/**
* Defines a data structure that will appear in the database.
@@ -43,10 +50,11 @@ import org.eclipse.jdt.internal.core.nd.Nd;
public final class StructDef<T> {
Class<T> clazz;
private StructDef<? super T> superClass;
+ private Set<StructDef<?>> dependencies = new HashSet<>();
private List<IField> fields = new ArrayList<>();
private boolean doneCalled;
private boolean offsetsComputed;
- private List<StructDef<? extends T>> subClasses = new ArrayList<>();
+ private List<StructDef<? extends T>> dependents = new ArrayList<>();
private int size;
List<IDestructableField> destructableFields = new ArrayList<>();
boolean refCounted;
@@ -56,6 +64,8 @@ public final class StructDef<T> {
private ITypeFactory<T> factory;
protected boolean hasUserDestructor;
private DeletionSemantics deletionSemantics;
+ final Tag destructTag;
+ private boolean isNdNode;
public static enum DeletionSemantics {
EXPLICIT, OWNED, REFCOUNTED
@@ -70,10 +80,12 @@ public final class StructDef<T> {
}
private StructDef(Class<T> clazz, StructDef<? super T> superClass, boolean isAbstract) {
+ this.destructTag = ModificationLog.createTag("Destructing struct " + clazz.getSimpleName()); //$NON-NLS-1$
this.clazz = clazz;
+ this.isNdNode = NdNode.class.isAssignableFrom(clazz);
this.superClass = superClass;
if (this.superClass != null) {
- this.superClass.subClasses.add(this);
+ addDependency(this.superClass);
}
this.isAbstract = isAbstract;
final String fullyQualifiedClassName = clazz.getName();
@@ -128,11 +140,17 @@ public final class StructDef<T> {
public void destruct(Nd nd, long address) {
checkNotMutable();
- if (StructDef.this.hasUserDestructor) {
- IDestructable destructable = (IDestructable)create(nd, address);
- destructable.destruct();
+ Database db = nd.getDB();
+ db.getLog().start(StructDef.this.destructTag);
+ try {
+ if (StructDef.this.hasUserDestructor) {
+ IDestructable destructable = (IDestructable)create(nd, address);
+ destructable.destruct();
+ }
+ destructFields(nd, address);
+ } finally {
+ db.getLog().end(StructDef.this.destructTag);
}
- destructFields(nd, address);
}
public void destructFields(Nd dom, long address) {
@@ -151,6 +169,32 @@ public final class StructDef<T> {
};
}
+ public void addDependency(StructDef<?> newDependency) {
+ if (newDependency.hasIndirectDependent(new HashSet<>(), this)) {
+ throw new IllegalArgumentException("Circular dependency detected. Struct " //$NON-NLS-1$
+ + getStructName() + " and struct " + newDependency.getStructName() //$NON-NLS-1$
+ + " both depend on one another"); //$NON-NLS-1$
+ }
+ if (this.dependencies.add(newDependency)) {
+ this.superClass.dependents.add(this);
+ }
+ }
+
+ private boolean hasIndirectDependent(Set<StructDef<?>> visited, StructDef<?> structDef) {
+ for (StructDef<?> next : this.dependents) {
+ if (!visited.add(next)) {
+ continue;
+ }
+ if (next.equals(structDef)) {
+ return true;
+ }
+ if (next.hasIndirectDependent(visited, structDef)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public Class<T> getStructClass() {
return this.clazz;
}
@@ -206,6 +250,15 @@ public final class StructDef<T> {
return this.deletionSemantics;
}
+ private boolean areAllDependenciesResolved() {
+ for (StructDef<?> next : this.dependencies) {
+ if (!next.areOffsetsComputed()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Call this once all the fields have been added to the struct definition and it is
* ready to use.
@@ -216,7 +269,7 @@ public final class StructDef<T> {
}
this.doneCalled = true;
- if (this.superClass == null || this.superClass.areOffsetsComputed()) {
+ if (areAllDependenciesResolved()) {
computeOffsets();
}
}
@@ -275,12 +328,13 @@ public final class StructDef<T> {
/**
* Invoked on all StructDef after both {@link #done()} has been called on the struct and
- * {@link #computeOffsets()} has been called on their base class.
+ * {@link #computeOffsets()} has been called on every dependency of this struct.
*/
private void computeOffsets() {
int offset = this.superClass == null ? 0 : this.superClass.size();
for (IField next : this.fields) {
+ offset = MathUtils.roundUpToNearestMultiple(offset, next.getAlignment());
next.setOffset(offset);
offset += next.getRecordSize();
}
@@ -309,7 +363,7 @@ public final class StructDef<T> {
this.offsetsComputed = true;
- for (StructDef<? extends T> next : this.subClasses) {
+ for (StructDef<? extends T> next : this.dependents) {
if (next.doneCalled) {
next.computeOffsets();
}
@@ -317,62 +371,66 @@ public final class StructDef<T> {
}
public FieldPointer addPointer() {
- FieldPointer result = new FieldPointer();
+ FieldPointer result = new FieldPointer(getStructName(), this.fields.size());
add(result);
return result;
}
public FieldShort addShort() {
- FieldShort result = new FieldShort();
+ FieldShort result = new FieldShort(getStructName(), this.fields.size());
add(result);
return result;
}
public FieldInt addInt() {
- FieldInt result = new FieldInt();
+ FieldInt result = new FieldInt(getStructName(), this.fields.size());
add(result);
return result;
}
public FieldLong addLong() {
- FieldLong result = new FieldLong();
+ FieldLong result = new FieldLong(getStructName(), this.fields.size());
add(result);
return result;
}
public FieldString addString() {
- FieldString result = new FieldString();
+ FieldString result = new FieldString(getStructName(), this.fields.size());
add(result);
addDestructableField(result);
return result;
}
public FieldDouble addDouble() {
- FieldDouble result = new FieldDouble();
+ FieldDouble result = new FieldDouble(getStructName(), this.fields.size());
add(result);
return result;
}
public FieldFloat addFloat() {
- FieldFloat result = new FieldFloat();
+ FieldFloat result = new FieldFloat(getStructName(), this.fields.size());
add(result);
return result;
}
+ public String getStructName() {
+ return this.clazz.getSimpleName();
+ }
+
public FieldByte addByte() {
- FieldByte result = new FieldByte();
+ FieldByte result = new FieldByte(getStructName(), this.fields.size());
add(result);
return result;
}
public FieldChar addChar() {
- FieldChar result = new FieldChar();
+ FieldChar result = new FieldChar(getStructName(), this.fields.size());
add(result);
return result;
}
public <F> Field<F> add(ITypeFactory<F> factory1) {
- Field<F> result = new Field<>(factory1);
+ Field<F> result = new Field<>(factory1, getStructName(), this.fields.size());
add(result);
if (result.factory.hasDestructor()) {
this.destructableFields.add(result);
@@ -394,5 +452,11 @@ public final class StructDef<T> {
}
}
-
+ public boolean isNdNode() {
+ return this.isNdNode;
+ }
+
+ public int getNumFields() {
+ return this.fields.size();
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/BindingToIndexConverter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/BindingToIndexConverter.java
deleted file mode 100644
index a8788eb9bd..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/BindingToIndexConverter.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.indexer;
-
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.core.dom.IAnnotationBinding;
-import org.eclipse.jdt.core.dom.IBinding;
-import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
-import org.eclipse.jdt.core.dom.IMethodBinding;
-import org.eclipse.jdt.core.dom.IPackageBinding;
-import org.eclipse.jdt.core.dom.ITypeBinding;
-import org.eclipse.jdt.core.dom.IVariableBinding;
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
-import org.eclipse.jdt.internal.core.nd.java.JavaNames;
-import org.eclipse.jdt.internal.core.nd.java.NdResourceFile;
-import org.eclipse.jdt.internal.core.nd.java.NdTreeNode;
-import org.eclipse.jdt.internal.core.nd.java.NdType;
-import org.eclipse.jdt.internal.core.nd.java.NdTypeId;
-import org.eclipse.jdt.internal.core.nd.java.NdTypeInterface;
-
-public class BindingToIndexConverter {
- private static final boolean ENABLE_LOGGING = false;
- private JavaIndex index;
- private NdResourceFile resource;
-
- public BindingToIndexConverter(NdResourceFile resource) {
- this.resource = resource;
- this.index = JavaIndex.getIndex(resource.getNd());
- }
-
- public void addBinding(NdTreeNode parent, IBinding binding, IProgressMonitor monitor) {
- switch (binding.getKind()) {
- case IBinding.TYPE:
- addType((ITypeBinding) binding, monitor);
- break;
- case IBinding.ANNOTATION:
- addAnnotation(parent, (IAnnotationBinding) binding, monitor);
- break;
- case IBinding.METHOD:
- addMethod(parent, (IMethodBinding) binding, monitor);
- break;
- case IBinding.VARIABLE:
- addVariable(parent, (IVariableBinding) binding, monitor);
- break;
- case IBinding.PACKAGE:
- addPackage(parent, (IPackageBinding) binding, monitor);
- break;
- case IBinding.MEMBER_VALUE_PAIR:
- addMemberValuePair(parent, (IMemberValuePairBinding) binding, monitor);
- break;
- default:
- Package.log("Encountered unknown binding type: " + binding.getKind(), null); //$NON-NLS-1$
- }
- }
-
- public void addMemberValuePair(NdTreeNode parent, IMemberValuePairBinding binding, IProgressMonitor monitor) {
- logInfo("Adding member value pair: " + binding.getName()); //$NON-NLS-1$
- }
-
- public void addPackage(NdTreeNode parent, IPackageBinding binding, IProgressMonitor monitor) {
- logInfo("Adding package: " + binding.getName()); //$NON-NLS-1$
- }
-
- public void addVariable(NdTreeNode parent, IVariableBinding binding, IProgressMonitor monitor) {
- logInfo("Adding variable: " + binding.getName()); //$NON-NLS-1$
- }
-
- public void addMethod(NdTreeNode parent, IMethodBinding binding, IProgressMonitor monitor) {
- logInfo("Adding method: " + binding.getName()); //$NON-NLS-1$
- }
-
- public void addAnnotation(NdTreeNode parent, IAnnotationBinding binding, IProgressMonitor monitor) {
- logInfo("Adding annotation: " + binding.getName()); //$NON-NLS-1$
- }
-
- public NdType addType(ITypeBinding binding, IProgressMonitor monitor) {
- logInfo("Adding type: " + binding.getBinaryName()); //$NON-NLS-1$
-
- NdTypeId name = makeTypeId(binding);
- NdType type = name.findTypeByResourceAddress(this.resource.address);
-
- if (type == null) {
- type = new NdType(getNd(), this.resource);
- }
-
- type.setTypeId(name);
-
- ITypeBinding superclass = binding.getSuperclass();
-
- if (superclass != null) {
- type.setSuperclass(makeTypeId(superclass));
- }
-
- for (ITypeBinding next : binding.getInterfaces()) {
- new NdTypeInterface(getNd(), type, makeTypeId(next));
- }
-
- return type;
- }
-
- private void logInfo(String string) {
- if (ENABLE_LOGGING) {
- Package.logInfo(string);
- }
- }
-
- private NdTypeId makeTypeId(ITypeBinding forBinding) {
- return this.index.createTypeId(JavaNames.binaryNameToFieldDescriptor(forBinding.getBinaryName().toCharArray()));
- }
-
- private Nd getNd() {
- return this.resource.getNd();
- }
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
index d52ce330e7..11259d1005 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
@@ -12,6 +12,7 @@ package org.eclipse.jdt.internal.core.nd.indexer;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
@@ -33,15 +34,9 @@ import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.db.IndexException;
import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
import org.eclipse.jdt.internal.core.nd.java.JavaNames;
import org.eclipse.jdt.internal.core.nd.java.NdAnnotation;
-import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInConstant;
-import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInMethod;
-import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInMethodParameter;
-import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInType;
-import org.eclipse.jdt.internal.core.nd.java.NdAnnotationInVariable;
import org.eclipse.jdt.internal.core.nd.java.NdAnnotationValuePair;
import org.eclipse.jdt.internal.core.nd.java.NdBinding;
import org.eclipse.jdt.internal.core.nd.java.NdComplexTypeSignature;
@@ -51,17 +46,11 @@ import org.eclipse.jdt.internal.core.nd.java.NdConstantArray;
import org.eclipse.jdt.internal.core.nd.java.NdConstantClass;
import org.eclipse.jdt.internal.core.nd.java.NdConstantEnum;
import org.eclipse.jdt.internal.core.nd.java.NdMethod;
-import org.eclipse.jdt.internal.core.nd.java.NdMethodException;
-import org.eclipse.jdt.internal.core.nd.java.NdMethodId;
import org.eclipse.jdt.internal.core.nd.java.NdMethodParameter;
import org.eclipse.jdt.internal.core.nd.java.NdResourceFile;
import org.eclipse.jdt.internal.core.nd.java.NdType;
import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotation;
-import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotationInMethod;
-import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotationInType;
-import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotationInVariable;
import org.eclipse.jdt.internal.core.nd.java.NdTypeArgument;
-import org.eclipse.jdt.internal.core.nd.java.NdTypeBound;
import org.eclipse.jdt.internal.core.nd.java.NdTypeId;
import org.eclipse.jdt.internal.core.nd.java.NdTypeInterface;
import org.eclipse.jdt.internal.core.nd.java.NdTypeParameter;
@@ -78,7 +67,7 @@ public final class ClassFileToIndexConverter {
private static final char[] COMMA = new char[]{','};
private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = new char[0][];
private static final boolean ENABLE_LOGGING = false;
- private static final char[] EMPTY_CHAR_ARRAY = new char[0];
+ static final char[] EMPTY_CHAR_ARRAY = new char[0];
private static final char[] PATH_SEPARATOR = new char[]{'/'};
private static final char[] ARRAY_FIELD_DESCRIPTOR_PREFIX = new char[] { '[' };
private NdResourceFile resource;
@@ -136,8 +125,9 @@ public final class ClassFileToIndexConverter {
IBinaryTypeAnnotation[] typeAnnotations = binaryType.getTypeAnnotations();
if (typeAnnotations != null) {
+ type.allocateTypeAnnotations(typeAnnotations.length);
for (IBinaryTypeAnnotation typeAnnotation : typeAnnotations) {
- NdTypeAnnotationInType annotation = new NdTypeAnnotationInType(getNd(), type);
+ NdTypeAnnotation annotation = type.createTypeAnnotation();
initTypeAnnotation(annotation, typeAnnotation);
}
@@ -190,11 +180,12 @@ public final class ClassFileToIndexConverter {
IBinaryAnnotation[] annotations = binaryType.getAnnotations();
attachAnnotations(type, annotations);
- type.setDeclaringMethod(createMethodId(binaryType.getEnclosingTypeName(), binaryType.getEnclosingMethod()));
+ type.setDeclaringMethod(binaryType.getEnclosingMethod());
IBinaryField[] fields = binaryType.getFields();
if (fields != null) {
+ type.allocateVariables(fields.length);
for (IBinaryField nextField : fields) {
addField(type, nextField);
}
@@ -203,8 +194,26 @@ public final class ClassFileToIndexConverter {
IBinaryMethod[] methods = binaryType.getMethods();
if (methods != null) {
- for (IBinaryMethod next : methods) {
- addMethod(type, next, binaryType);
+ char[][] methodNames = new char[methods.length][];
+ Integer[] sortedElementIndices = new Integer[methods.length];
+
+ for (int idx = 0; idx < sortedElementIndices.length; idx++) {
+ sortedElementIndices[idx] = idx;
+ methodNames[idx] = getSelectorAndDescriptor(methods[idx]);
+ }
+
+ Arrays.sort(sortedElementIndices, (Integer i1, Integer i2) -> {
+ return CharArrayUtils.compare(methodNames[i1], methodNames[i2]);
+ });
+
+ type.allocateMethods(methods.length);
+ for (int idx = 0; idx < methods.length; idx++) {
+ NdMethod newMethod = type.createMethod();
+ int position = sortedElementIndices[idx];
+ newMethod.setDeclarationPosition(position);
+ newMethod.setMethodName(methodNames[position]);
+ IBinaryMethod nextMethod = methods[position];
+ addMethod(newMethod, nextMethod, binaryType);
}
}
@@ -222,6 +231,10 @@ public final class ClassFileToIndexConverter {
return type;
}
+ private char[] getSelectorAndDescriptor(IBinaryMethod binaryMethod) {
+ return CharArrayUtils.concat(binaryMethod.getSelector(), binaryMethod.getMethodDescriptor());
+ }
+
private static char[] getMissingTypeString(char[][][] missingTypeNames) {
char[] missingTypeString = null;
if (missingTypeNames != null) {
@@ -252,8 +265,9 @@ public final class ClassFileToIndexConverter {
private void attachAnnotations(NdMethod method, IBinaryAnnotation[] annotations) {
if (annotations != null) {
+ method.allocateAnnotations(annotations.length);
for (IBinaryAnnotation next : annotations) {
- NdAnnotationInMethod annotation = new NdAnnotationInMethod(getNd(), method);
+ NdAnnotation annotation = method.createAnnotation();
initAnnotation(annotation, next);
}
}
@@ -261,8 +275,9 @@ public final class ClassFileToIndexConverter {
private void attachAnnotations(NdType type, IBinaryAnnotation[] annotations) {
if (annotations != null) {
+ type.allocateAnnotations(annotations.length);
for (IBinaryAnnotation next : annotations) {
- NdAnnotationInType annotation = new NdAnnotationInType(getNd(), type);
+ NdAnnotation annotation = type.createAnnotation();
initAnnotation(annotation, next);
}
}
@@ -270,8 +285,9 @@ public final class ClassFileToIndexConverter {
private void attachAnnotations(NdVariable variable, IBinaryAnnotation[] annotations) {
if (annotations != null) {
+ variable.allocateAnnotations(annotations.length);
for (IBinaryAnnotation next : annotations) {
- NdAnnotationInVariable annotation = new NdAnnotationInVariable(getNd(), variable);
+ NdAnnotation annotation = variable.createAnnotation();
initAnnotation(annotation, next);
}
}
@@ -279,8 +295,9 @@ public final class ClassFileToIndexConverter {
private void attachAnnotations(NdMethodParameter variable, IBinaryAnnotation[] annotations) {
if (annotations != null) {
+ variable.allocateAnnotations(annotations.length);
for (IBinaryAnnotation next : annotations) {
- NdAnnotationInMethodParameter annotation = new NdAnnotationInMethodParameter(getNd(), variable);
+ NdAnnotation annotation = variable.createAnnotation();
initAnnotation(annotation, next);
}
}
@@ -291,10 +308,9 @@ public final class ClassFileToIndexConverter {
*
* @throws CoreException
*/
- private void addMethod(NdType type, IBinaryMethod next, IBinaryType binaryType)
+ private void addMethod(NdMethod method, IBinaryMethod next, IBinaryType binaryType)
throws CoreException {
int flags = 0;
- NdMethod method = new NdMethod(type);
attachAnnotations(method, next.getAnnotations());
@@ -307,8 +323,9 @@ public final class ClassFileToIndexConverter {
IBinaryTypeAnnotation[] typeAnnotations = next.getTypeAnnotations();
if (typeAnnotations != null) {
+ method.allocateTypeAnnotations(typeAnnotations.length);
for (IBinaryTypeAnnotation typeAnnotation : typeAnnotations) {
- NdTypeAnnotationInMethod annotation = new NdTypeAnnotationInMethod(getNd(), method);
+ NdTypeAnnotation annotation = method.createTypeAnnotation();
initTypeAnnotation(annotation, typeAnnotation);
}
@@ -350,6 +367,10 @@ public final class ClassFileToIndexConverter {
int parameterNameIdx = 0;
int annotatedParametersCount = next.getAnnotatedParametersCount();
+ int namedParameterCount = parameterNames == null ? 0 : parameterNames.length;
+ int estimatedParameterCount = Math.max(Math.max(Math.max(numArgumentsInGenericSignature, namedParameterCount),
+ annotatedParametersCount), parameterFieldDescriptors.size());
+ method.allocateParameters(estimatedParameterCount);
short descriptorParameterIdx = 0;
char[] binaryTypeName = binaryType.getName();
@@ -368,8 +389,8 @@ public final class ClassFileToIndexConverter {
if (isCompilerDefined && !compilerDefinedParametersAreIncludedInSignature) {
nextFieldSignature = new SignatureWrapper(nextFieldDescriptor);
}
- NdMethodParameter parameter = new NdMethodParameter(method,
- createTypeSignature(nextFieldSignature, nextFieldDescriptor));
+ NdMethodParameter parameter = method.createNewParameter();
+ parameter.setType(createTypeSignature(nextFieldSignature, nextFieldDescriptor));
parameter.setCompilerDefined(isCompilerDefined);
@@ -379,7 +400,7 @@ public final class ClassFileToIndexConverter {
attachAnnotations(parameter, parameterAnnotations);
}
- if (!isCompilerDefined && parameterNames != null && parameterNames.length > parameterNameIdx) {
+ if (!isCompilerDefined && namedParameterCount > parameterNameIdx) {
parameter.setName(parameterNames[parameterNameIdx++]);
}
descriptorParameterIdx++;
@@ -394,11 +415,12 @@ public final class ClassFileToIndexConverter {
if (exceptionTypes == null) {
exceptionTypes = CharArrayUtils.EMPTY_ARRAY_OF_CHAR_ARRAYS;
}
+ method.allocateExceptions(exceptionTypes.length);
int throwsIdx = 0;
if (hasExceptionsInSignature) {
while (hasAnotherException(signature)) {
signature.start++;
- new NdMethodException(method, createTypeSignature(signature,
+ method.createException(createTypeSignature(signature,
JavaNames.binaryNameToFieldDescriptor(exceptionTypes[throwsIdx])));
throwsIdx++;
}
@@ -406,7 +428,7 @@ public final class ClassFileToIndexConverter {
for (;throwsIdx < exceptionTypes.length; throwsIdx++) {
char[] fieldDescriptor = JavaNames.binaryNameToFieldDescriptor(exceptionTypes[throwsIdx]);
SignatureWrapper convertedWrapper = new SignatureWrapper(fieldDescriptor);
- new NdMethodException(method, createTypeSignature(convertedWrapper,
+ method.createException(createTypeSignature(convertedWrapper,
JavaNames.binaryNameToFieldDescriptor(exceptionTypes[throwsIdx])));
}
}
@@ -420,7 +442,6 @@ public final class ClassFileToIndexConverter {
method.setDefaultValue(createConstantFromMixedType(defaultValue));
}
- method.setMethodId(createMethodId(binaryType.getName(), next.getSelector(), next.getMethodDescriptor()));
method.setModifiers(next.getModifiers());
method.setTagBits(next.getTagBits());
method.setFlags(flags);
@@ -440,7 +461,7 @@ public final class ClassFileToIndexConverter {
* Adds the given field to the given type
*/
private void addField(NdType type, IBinaryField nextField) throws CoreException {
- NdVariable variable = new NdVariable(type);
+ NdVariable variable = type.createVariable();
variable.setName(nextField.getName());
@@ -456,18 +477,23 @@ public final class ClassFileToIndexConverter {
IBinaryTypeAnnotation[] typeAnnotations = nextField.getTypeAnnotations();
if (typeAnnotations != null) {
+ variable.allocateTypeAnnotations(typeAnnotations.length);
for (IBinaryTypeAnnotation next : typeAnnotations) {
- NdTypeAnnotationInVariable annotation = new NdTypeAnnotationInVariable(getNd(), variable);
+ NdTypeAnnotation annotation = variable.createTypeAnnotation();
initTypeAnnotation(annotation, next);
}
}
variable.setType(createTypeSignature(nextTypeSignature, nextField.getTypeName()));
variable.setTagBits(nextField.getTagBits());
+ }
- // char[] fieldDescriptor = nextField.getTypeName();
- // // DO NOT SUBMIT:
- // IBinaryField bf = IndexBinaryType.createBinaryField(variable);
+ private static class TypeParameter {
+ public TypeParameter() {
+ }
+ public List<NdTypeSignature> bounds = new ArrayList<>();
+ public char[] identifier = ClassFileToIndexConverter.EMPTY_CHAR_ARRAY;
+ public boolean firstBoundIsClass;
}
/**
@@ -483,31 +509,46 @@ public final class ClassFileToIndexConverter {
return;
}
+ List<TypeParameter> typeParameters = new ArrayList<>();
+
int indexOfClosingBracket = wrapper.skipAngleContents(wrapper.start) - 1;
wrapper.start++;
- NdTypeParameter parameter = null;
+ TypeParameter parameter = null;
while (wrapper.start < indexOfClosingBracket) {
int colonPos = CharOperation.indexOf(':', genericSignature, wrapper.start, indexOfClosingBracket);
if (colonPos > wrapper.start) {
char[] identifier = CharOperation.subarray(genericSignature, wrapper.start, colonPos);
- parameter = new NdTypeParameter(type, identifier);
+ parameter = new TypeParameter();
+ typeParameters.add(parameter);
+ parameter.identifier = identifier;
wrapper.start = colonPos + 1;
// The first bound is a class as long as it doesn't start with a double-colon
- parameter.setFirstBoundIsClass(wrapper.charAtStart() != ':');
+ parameter.firstBoundIsClass = (wrapper.charAtStart() != ':');
}
skipChar(wrapper, ':');
NdTypeSignature boundSignature = createTypeSignature(wrapper, JAVA_LANG_OBJECT_FIELD_DESCRIPTOR);
- new NdTypeBound(parameter, boundSignature);
+ parameter.bounds.add(boundSignature);
+ }
+
+ type.allocateTypeParameters(typeParameters.size());
+ for (TypeParameter param : typeParameters) {
+ NdTypeParameter ndParam = type.createTypeParameter();
+ ndParam.setIdentifier(param.identifier);
+ ndParam.setFirstBoundIsClass(param.firstBoundIsClass);
+ ndParam.allocateBounds(param.bounds.size());
+ for (NdTypeSignature bound : param.bounds) {
+ ndParam.createBound(bound);
+ }
}
skipChar(wrapper, '>');
}
- private char[] readNextFieldDescriptor(SignatureWrapper genericSignature) {
+ private char[] readNextFieldDescriptor(SignatureWrapper genericSignature) throws CoreException {
int endPosition = findEndOfFieldDescriptor(genericSignature);
char[] result = CharArrayUtils.subarray(genericSignature.signature, genericSignature.start, endPosition);
@@ -515,7 +556,7 @@ public final class ClassFileToIndexConverter {
return result;
}
- private int findEndOfFieldDescriptor(SignatureWrapper genericSignature) {
+ private int findEndOfFieldDescriptor(SignatureWrapper genericSignature) throws CoreException {
char[] signature = genericSignature.signature;
if (signature == null || signature.length == 0) {
@@ -544,7 +585,7 @@ public final class ClassFileToIndexConverter {
case 'Z':
return current + 1;
default:
- throw new IndexException(Package.createStatus("Field descriptor starts with unknown character: " //$NON-NLS-1$
+ throw new CoreException(Package.createStatus("Field descriptor starts with unknown character: " //$NON-NLS-1$
+ genericSignature.toString()));
}
}
@@ -785,30 +826,6 @@ public final class ClassFileToIndexConverter {
return this.index.createTypeId(typeName);
}
- /**
- * Creates a method ID given a method selector, method descriptor, and binary type name
- */
- private NdMethodId createMethodId(char[] binaryTypeName, char[] methodSelector, char[] methodDescriptor) {
- if (methodSelector == null || binaryTypeName == null || methodDescriptor == null) {
- return null;
- }
-
- char[] methodId = JavaNames.getMethodId(binaryTypeName, methodSelector, methodDescriptor);
- return this.index.createMethodId(methodId);
- }
-
- /**
- * Creates a method ID given a method name (which is a method selector followed by a method descriptor.
- */
- private NdMethodId createMethodId(char[] binaryTypeName, char[] methodName) {
- if (methodName == null || binaryTypeName == null) {
- return null;
- }
-
- char[] methodId = JavaNames.getMethodId(binaryTypeName, methodName);
- return this.index.createMethodId(methodId);
- }
-
private void initTypeAnnotation(NdTypeAnnotation annotation, IBinaryTypeAnnotation next) {
int[] typePath = next.getTypePath();
if (typePath != null && typePath.length > 0) {
@@ -855,8 +872,9 @@ public final class ClassFileToIndexConverter {
IBinaryElementValuePair[] pairs = next.getElementValuePairs();
if (pairs != null) {
+ annotation.allocateValuePairs(pairs.length);
for (IBinaryElementValuePair element : pairs) {
- NdAnnotationValuePair nextPair = new NdAnnotationValuePair(annotation, element.getName());
+ NdAnnotationValuePair nextPair = annotation.createValuePair(element.getName());
nextPair.setValue(createConstantFromMixedType(element.getValue()));
}
}
@@ -895,9 +913,9 @@ public final class ClassFileToIndexConverter {
} else if (value instanceof IBinaryAnnotation) {
IBinaryAnnotation binaryAnnotation = (IBinaryAnnotation) value;
- NdAnnotationInConstant annotation = new NdAnnotationInConstant(getNd());
- initAnnotation(annotation, binaryAnnotation);
- return NdConstantAnnotation.create(getNd(), annotation);
+ NdConstantAnnotation constant = new NdConstantAnnotation(getNd());
+ initAnnotation(constant.getValue(), binaryAnnotation);
+ return constant;
} else if (value instanceof Object[]) {
NdConstantArray result = new NdConstantArray(getNd());
Object[] array = (Object[]) value;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
index 5e58ca8862..df12fb7941 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
@@ -47,6 +47,10 @@ import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobGroup;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaElementDelta;
@@ -65,6 +69,7 @@ import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.nd.IReader;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.ChunkCache;
import org.eclipse.jdt.internal.core.nd.db.Database;
import org.eclipse.jdt.internal.core.nd.db.IndexException;
import org.eclipse.jdt.internal.core.nd.java.FileFingerprint;
@@ -75,7 +80,6 @@ import org.eclipse.jdt.internal.core.nd.java.NdResourceFile;
import org.eclipse.jdt.internal.core.nd.java.NdType;
import org.eclipse.jdt.internal.core.nd.java.NdTypeId;
import org.eclipse.jdt.internal.core.nd.java.NdWorkspaceLocation;
-import org.eclipse.jdt.internal.core.nd.java.NdZipEntry;
import org.eclipse.jdt.internal.core.nd.java.TypeRef;
import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeDescriptor;
import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeFactory;
@@ -90,8 +94,22 @@ public final class Indexer {
public static boolean DEBUG;
public static boolean DEBUG_ALLOCATIONS;
public static boolean DEBUG_TIMING;
+ public static boolean DEBUG_SCHEDULING;
public static boolean DEBUG_INSERTIONS;
public static boolean DEBUG_SELFTEST;
+ public static int DEBUG_LOG_SIZE_MB;
+ private static IPreferenceChangeListener listener = new IPreferenceChangeListener() {
+ @Override
+ public void preferenceChange(PreferenceChangeEvent event) {
+ if (JavaIndex.ENABLE_NEW_JAVA_INDEX.equals(event.getKey())) {
+ if (JavaIndex.isEnabled()) {
+ getInstance().rescanAll();
+ } else {
+ ChunkCache.getSharedInstance().clear();
+ }
+ }
+ }
+ };
// This is an arbitrary constant that is larger than the maximum number of ticks
// reported by SubMonitor and small enough that it won't overflow a long when multiplied by a large
@@ -144,6 +162,8 @@ public final class Indexer {
synchronized (mutex) {
if (indexer == null) {
indexer = new Indexer(JavaIndex.getGlobalNd(), ResourcesPlugin.getWorkspace().getRoot());
+ IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID);
+ preferences.addPreferenceChangeListener(listener);
}
return indexer;
}
@@ -173,18 +193,20 @@ public final class Indexer {
}
}
- if (runRescan) {
- // Force a rescan when re-enabling automatic indexing since we may have missed an update
- this.rescanJob.schedule();
- }
-
- if (!enabled) {
- // Wait for any existing indexing operations to finish when disabling automatic indexing since
- // we only want explicitly-triggered indexing operations to run after the method returns
- try {
- this.rescanJob.join(0, null);
- } catch (OperationCanceledException | InterruptedException e) {
- // Don't care
+ if (JavaIndex.isEnabled()) {
+ if (runRescan) {
+ // Force a rescan when re-enabling automatic indexing since we may have missed an update
+ this.rescanJob.schedule();
+ }
+
+ if (!enabled) {
+ // Wait for any existing indexing operations to finish when disabling automatic indexing since
+ // we only want explicitly-triggered indexing operations to run after the method returns
+ try {
+ this.rescanJob.join(0, null);
+ } catch (OperationCanceledException | InterruptedException e) {
+ // Don't care
+ }
}
}
}
@@ -216,6 +238,7 @@ public final class Indexer {
SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
Database db = this.nd.getDB();
db.resetCacheCounters();
+ db.getLog().setBufferSize(DEBUG_LOG_SIZE_MB);
synchronized (this.automaticIndexingMutex) {
this.indexerDirtiedWhileDisabled = false;
@@ -701,6 +724,13 @@ public final class Indexer {
}
subMonitor.setWorkRemaining(zipFile.size());
+ // Preallocate memory for the zipfile entries
+ this.nd.acquireWriteLock(subMonitor.split(5));
+ try {
+ resourceFile.allocateZipEntries(zipFile.size());
+ } finally {
+ this.nd.releaseWriteLock();
+ }
for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) {
SubMonitor nextEntry = subMonitor.split(1).setWorkRemaining(2);
ZipEntry member = e.nextElement();
@@ -714,7 +744,7 @@ public final class Indexer {
Package.logInfo("Inserting non-class file " + fileName + " into " //$NON-NLS-1$//$NON-NLS-2$
+ resourceFile.getLocation().getString() + " " + resourceFile.address); //$NON-NLS-1$
}
- new NdZipEntry(resourceFile, fileName);
+ resourceFile.addZipEntry(fileName);
if (fileName.equals("META-INF/MANIFEST.MF")) { //$NON-NLS-1$
try (InputStream inputStream = zipFile.getInputStream(member)) {
@@ -924,7 +954,7 @@ public final class Indexer {
}
public void rescanAll() {
- if (DEBUG) {
+ if (DEBUG_SCHEDULING) {
Package.logInfo("Scheduling rescanAll now"); //$NON-NLS-1$
}
synchronized (this.automaticIndexingMutex) {
@@ -935,6 +965,9 @@ public final class Indexer {
return;
}
}
+ if (!JavaIndex.isEnabled()) {
+ return;
+ }
this.rescanJob.schedule();
}
@@ -992,6 +1025,9 @@ public final class Indexer {
}
public void waitForIndex(int waitingPolicy, IProgressMonitor monitor) {
+ if (!JavaIndex.isEnabled()) {
+ return;
+ }
switch (waitingPolicy) {
case IJob.ForceImmediate: {
break;
@@ -1012,13 +1048,23 @@ public final class Indexer {
public void rebuildIndex(IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+ this.rescanJob.cancel();
+ try {
+ this.rescanJob.join(0, subMonitor.split(1));
+ } catch (InterruptedException e) {
+ // Nothing to do.
+ }
this.nd.acquireWriteLock(subMonitor.split(1));
try {
this.nd.clear(subMonitor.split(2));
+ this.nd.getDB().flush();
} finally {
this.nd.releaseWriteLock();
}
- rescan(subMonitor.split(98));
+ if (!JavaIndex.isEnabled()) {
+ return;
+ }
+ rescan(subMonitor.split(97));
}
public void requestRebuildIndex() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
index 07b1080c77..e212fc8245 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
@@ -38,16 +38,17 @@ import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
public class JavaIndex {
// Version constants
- static final int CURRENT_VERSION = Nd.version(1, 46);
- static final int MAX_SUPPORTED_VERSION = Nd.version(1, 46);
- static final int MIN_SUPPORTED_VERSION = Nd.version(1, 46);
+ static final int CURRENT_VERSION = Nd.version(1, 49);
+ static final int MAX_SUPPORTED_VERSION = Nd.version(1, 49);
+ static final int MIN_SUPPORTED_VERSION = Nd.version(1, 49);
+
+ public static final String ENABLE_NEW_JAVA_INDEX = "enableNewJavaIndex"; //$NON-NLS-1$
+ public static final boolean ENABLE_NEW_JAVA_INDEX_DEFAULT = false;
// Fields for the search header
public static final FieldSearchIndex<NdResourceFile> FILES;
public static final FieldSearchIndex<NdTypeId> SIMPLE_INDEX;
public static final FieldSearchIndex<NdTypeId> TYPES;
- public static final FieldSearchIndex<NdMethodId> METHODS;
-
public static final StructDef<JavaIndex> type;
static {
@@ -55,7 +56,6 @@ public class JavaIndex {
FILES = FieldSearchIndex.create(type, NdResourceFile.FILENAME);
SIMPLE_INDEX = FieldSearchIndex.create(type, NdTypeId.SIMPLE_NAME);
TYPES = FieldSearchIndex.create(type, NdTypeId.FIELD_DESCRIPTOR);
- METHODS = FieldSearchIndex.create(type, NdMethodId.METHOD_NAME);
type.done();
// This struct needs to fit within the first database chunk.
@@ -185,22 +185,6 @@ public class JavaIndex {
return this.nd;
}
- public NdMethodId findMethodId(char[] methodId) {
- SearchCriteria searchCriteria = SearchCriteria.create(methodId);
-
- return METHODS.findBest(this.nd, this.address, searchCriteria, this.anyResult);
- }
-
- public NdMethodId createMethodId(char[] methodId) {
- NdMethodId existingMethod = findMethodId(methodId);
-
- if (existingMethod != null) {
- return existingMethod;
- }
-
- return new NdMethodId(this.nd, methodId);
- }
-
/**
* Converts a JDT-style path (which may be a resource-relative path or absolute filesystem location) into a location
* (which is unconditionally a filesystem location) or null if none.
@@ -241,7 +225,7 @@ public class JavaIndex {
if (preferenceService == null) {
return true;
}
- return !preferenceService.getBoolean(JavaCore.PLUGIN_ID, "disableNewJavaIndex", false, //$NON-NLS-1$
+ return preferenceService.getBoolean(JavaCore.PLUGIN_ID, ENABLE_NEW_JAVA_INDEX, ENABLE_NEW_JAVA_INDEX_DEFAULT,
null);
}
@@ -289,13 +273,7 @@ public class JavaIndex {
static NdNodeTypeRegistry<NdNode> createTypeRegistry() {
NdNodeTypeRegistry<NdNode> registry = new NdNodeTypeRegistry<>();
- registry.register(0x0001, NdAnnotation.type.getFactory());
- registry.register(0x0004, NdAnnotationInConstant.type.getFactory());
- registry.register(0x0008, NdAnnotationInMethod.type.getFactory());
- registry.register(0x000c, NdAnnotationInMethodParameter.type.getFactory());
- registry.register(0x0010, NdAnnotationInType.type.getFactory());
- registry.register(0x0014, NdAnnotationInVariable.type.getFactory());
- registry.register(0x0020, NdAnnotationValuePair.type.getFactory());
+
registry.register(0x0028, NdBinding.type.getFactory());
registry.register(0x0030, NdComplexTypeSignature.type.getFactory());
registry.register(0x0038, NdConstant.type.getFactory());
@@ -314,26 +292,15 @@ public class JavaIndex {
registry.register(0x0100, NdConstantString.type.getFactory());
registry.register(0x0110, NdMethod.type.getFactory());
registry.register(0x0118, NdMethodAnnotationData.type.getFactory());
- registry.register(0x0120, NdMethodException.type.getFactory());
- registry.register(0x0130, NdMethodId.type.getFactory());
- registry.register(0x0140, NdMethodParameter.type.getFactory());
registry.register(0x0150, NdResourceFile.type.getFactory());
- registry.register(0x0160, NdTreeNode.type.getFactory());
registry.register(0x0170, NdType.type.getFactory());
- registry.register(0x0180, NdTypeAnnotation.type.getFactory());
- registry.register(0x0184, NdTypeAnnotationInMethod.type.getFactory());
- registry.register(0x0188, NdTypeAnnotationInType.type.getFactory());
- registry.register(0x018c, NdTypeAnnotationInVariable.type.getFactory());
registry.register(0x0190, NdTypeArgument.type.getFactory());
- registry.register(0x0194, NdTypeBound.type.getFactory());
registry.register(0x01A0, NdTypeInterface.type.getFactory());
- registry.register(0x01B0, NdTypeParameter.type.getFactory());
registry.register(0x01C0, NdTypeSignature.type.getFactory());
registry.register(0x01D0, NdTypeId.type.getFactory());
registry.register(0x01E0, NdTypeInterface.type.getFactory());
registry.register(0x01F0, NdVariable.type.getFactory());
registry.register(0x0200, NdWorkspaceLocation.type.getFactory());
- registry.register(0x0210, NdZipEntry.type.getFactory());
return registry;
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java
index 9715c100e1..7248ce4708 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java
@@ -13,22 +13,22 @@ package org.eclipse.jdt.internal.core.nd.java;
import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
-public class NdAnnotation extends NdNode {
+public class NdAnnotation extends NdStruct {
public static final FieldManyToOne<NdTypeSignature> ANNOTATION_TYPE;
- public static final FieldOneToMany<NdAnnotationValuePair> ELEMENT_VALUE_PAIRS;
+ public static final FieldList<NdAnnotationValuePair> ELEMENT_VALUE_PAIRS;
@SuppressWarnings("hiding")
public static final StructDef<NdAnnotation> type;
static {
- type = StructDef.create(NdAnnotation.class, NdNode.type);
+ type = StructDef.create(NdAnnotation.class, NdStruct.type);
ANNOTATION_TYPE = FieldManyToOne.create(type, NdTypeSignature.ANNOTATIONS_OF_THIS_TYPE);
- ELEMENT_VALUE_PAIRS = FieldOneToMany.create(type, NdAnnotationValuePair.APPLIES_TO);
+ ELEMENT_VALUE_PAIRS = FieldList.create(type, NdAnnotationValuePair.type);
type.done();
}
@@ -36,10 +36,6 @@ public class NdAnnotation extends NdNode {
super(nd, address);
}
- public NdAnnotation(Nd nd) {
- super(nd);
- }
-
public NdTypeSignature getType() {
return ANNOTATION_TYPE.get(getNd(), this.address);
}
@@ -51,4 +47,14 @@ public class NdAnnotation extends NdNode {
public List<NdAnnotationValuePair> getElementValuePairs() {
return ELEMENT_VALUE_PAIRS.asList(getNd(), this.address);
}
+
+ public NdAnnotationValuePair createValuePair(char[] name) {
+ NdAnnotationValuePair result = ELEMENT_VALUE_PAIRS.append(getNd(), getAddress());
+ result.setName(name);
+ return result;
+ }
+
+ public void allocateValuePairs(int length) {
+ ELEMENT_VALUE_PAIRS.allocate(getNd(), getAddress(), length);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java
deleted file mode 100644
index 2328a49e8e..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdAnnotationInConstant extends NdAnnotation {
- public static final FieldOneToOne<NdConstantAnnotation> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdAnnotationInConstant> type;
-
- static {
- type = StructDef.create(NdAnnotationInConstant.class, NdAnnotation.type);
- OWNER = FieldOneToOne.createOwner(type, NdConstantAnnotation.class, NdConstantAnnotation.VALUE);
- type.done();
- }
-
- public NdAnnotationInConstant(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdAnnotationInConstant(Nd nd) {
- super(nd);
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java
deleted file mode 100644
index c1b524ec79..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdAnnotationInMethod extends NdAnnotation {
- public static final FieldManyToOne<NdMethodAnnotationData> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdAnnotationInMethod> type;
-
- static {
- type = StructDef.create(NdAnnotationInMethod.class, NdAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdMethodAnnotationData.ANNOTATIONS);
- type.done();
- }
-
- public NdAnnotationInMethod(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdAnnotationInMethod(Nd nd, NdMethod owner) {
- super(nd);
-
- OWNER.put(getNd(), this.address, owner.createAnnotationData());
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java
deleted file mode 100644
index 0a4f3fb688..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdAnnotationInMethodParameter extends NdAnnotation {
- public static final FieldManyToOne<NdMethodParameter> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdAnnotationInMethodParameter> type;
-
- static {
- type = StructDef.create(NdAnnotationInMethodParameter.class, NdAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdMethodParameter.ANNOTATIONS);
- type.done();
- }
-
- public NdAnnotationInMethodParameter(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdAnnotationInMethodParameter(Nd nd, NdMethodParameter owner) {
- super(nd);
-
- OWNER.put(getNd(), this.address, owner);
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java
deleted file mode 100644
index c220ed9f01..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdAnnotationInType extends NdAnnotation {
- public static final FieldManyToOne<NdType> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdAnnotationInType> type;
-
- static {
- type = StructDef.create(NdAnnotationInType.class, NdAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdType.ANNOTATIONS);
- type.done();
- }
-
- public NdAnnotationInType(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdAnnotationInType(Nd nd, NdType owner) {
- super(nd);
-
- OWNER.put(getNd(), this.address, owner);
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java
deleted file mode 100644
index 378b2d44a2..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdAnnotationInVariable extends NdAnnotation {
- public static final FieldManyToOne<NdVariable> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdAnnotationInVariable> type;
-
- static {
- type = StructDef.create(NdAnnotationInVariable.class, NdAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdVariable.ANNOTATIONS);
- type.done();
- }
-
- public NdAnnotationInVariable(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdAnnotationInVariable(Nd nd, NdVariable owner) {
- super(nd);
-
- OWNER.put(getNd(), this.address, owner);
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java
index f62ceb37b6..eb5d3c20a8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java
@@ -11,15 +11,13 @@
package org.eclipse.jdt.internal.core.nd.java;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
import org.eclipse.jdt.internal.core.nd.db.IString;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
-public class NdAnnotationValuePair extends NdNode {
- public static final FieldManyToOne<NdAnnotation> APPLIES_TO;
+public class NdAnnotationValuePair extends NdStruct {
public static final FieldString NAME;
public static final FieldOneToOne<NdConstant> VALUE;
@@ -27,10 +25,9 @@ public class NdAnnotationValuePair extends NdNode {
public static final StructDef<NdAnnotationValuePair> type;
static {
- type = StructDef.create(NdAnnotationValuePair.class, NdNode.type);
- APPLIES_TO = FieldManyToOne.createOwner(type, NdAnnotation.ELEMENT_VALUE_PAIRS);
+ type = StructDef.create(NdAnnotationValuePair.class, NdStruct.type);
NAME = type.addString();
- VALUE = FieldOneToOne.create(type, NdConstant.class, NdConstant.PARENT_ANNOTATION_VALUE);
+ VALUE = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_ANNOTATION_VALUE);
type.done();
}
@@ -38,22 +35,11 @@ public class NdAnnotationValuePair extends NdNode {
super(nd, address);
}
- public NdAnnotationValuePair(NdAnnotation annotation, char[] name) {
- super(annotation.getNd());
- Nd nd = annotation.getNd();
- APPLIES_TO.put(nd, this.address, annotation);
- NAME.put(nd, this.address, name);
- }
-
- public NdAnnotation getAnnotation() {
- return APPLIES_TO.get(getNd(), this.address);
- }
-
public IString getName() {
return NAME.get(getNd(), this.address);
}
- public void setName(String name) {
+ public void setName(char[] name) {
NAME.put(getNd(), this.address, name);
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java
index 3c48fc92db..6fb38a9bf2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java
@@ -17,7 +17,7 @@ import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
import org.eclipse.jdt.internal.core.nd.field.FieldInt;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
@@ -26,8 +26,7 @@ import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
*/
public abstract class NdBinding extends NdNode implements IAdaptable {
public static final FieldInt MODIFIERS;
- public static final FieldOneToMany<NdTypeParameter> TYPE_PARAMETERS;
- public static final FieldOneToMany<NdVariable> VARIABLES;
+ public static final FieldList<NdTypeParameter> TYPE_PARAMETERS;
@SuppressWarnings("hiding")
public static final StructDef<NdBinding> type;
@@ -35,8 +34,7 @@ public abstract class NdBinding extends NdNode implements IAdaptable {
static {
type = StructDef.create(NdBinding.class, NdNode.type);
MODIFIERS = type.addInt();
- TYPE_PARAMETERS = FieldOneToMany.create(type, NdTypeParameter.PARENT);
- VARIABLES = FieldOneToMany.create(type, NdVariable.PARENT);
+ TYPE_PARAMETERS = FieldList.create(type, NdTypeParameter.type);
type.done();
}
@@ -48,10 +46,6 @@ public abstract class NdBinding extends NdNode implements IAdaptable {
super(nd);
}
- public List<NdVariable> getVariables() {
- return VARIABLES.asList(getNd(), this.address);
- }
-
/**
* Tests whether this binding has one of the flags defined in {@link Flags}
*/
@@ -106,4 +100,12 @@ public abstract class NdBinding extends NdNode implements IAdaptable {
public List<NdTypeParameter> getTypeParameters() {
return TYPE_PARAMETERS.asList(getNd(), this.address);
}
+
+ public NdTypeParameter createTypeParameter() {
+ return TYPE_PARAMETERS.append(getNd(), getAddress());
+ }
+
+ public void allocateTypeParameters(int elements) {
+ TYPE_PARAMETERS.allocate(getNd(), getAddress(), elements);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java
index b348f4ea76..c5d6733cc4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java
@@ -16,7 +16,6 @@ import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.db.IString;
-import org.eclipse.jdt.internal.core.nd.db.IndexException;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
@@ -107,7 +106,9 @@ public class NdComplexTypeSignature extends NdTypeSignature {
long size = TYPE_ARGUMENTS.size(getNd(), this.address);
if (size != 1) {
- throw new IndexException("Array types should have exactly one argument"); //$NON-NLS-1$
+ throw getNd().describeProblem()
+ .addProblemAddress(TYPE_ARGUMENTS, this.address)
+ .build("Array types should have exactly one argument"); //$NON-NLS-1$
}
return TYPE_ARGUMENTS.get(getNd(), this.address, 0).getType();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java
index 96e604588f..ff4ee5e453 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java
@@ -33,10 +33,10 @@ public abstract class NdConstant extends NdNode {
static {
type = StructDef.createAbstract(NdConstant.class, NdNode.type);
PARENT_ARRAY = FieldManyToOne.createOwner(type, NdConstantArray.ELEMENTS);
- PARENT_ANNOTATION_VALUE = FieldOneToOne.createOwner(type, NdAnnotationValuePair.class,
+ PARENT_ANNOTATION_VALUE = FieldOneToOne.createOwner(type, NdAnnotationValuePair.type,
NdAnnotationValuePair.VALUE);
- PARENT_VARIABLE = FieldOneToOne.createOwner(type, NdVariable.class, NdVariable.CONSTANT);
- PARENT_METHOD = FieldOneToOne.createOwner(type, NdMethod.class, NdMethod.DEFAULT_VALUE);
+ PARENT_VARIABLE = FieldOneToOne.createOwner(type, NdVariable.type, NdVariable.CONSTANT);
+ PARENT_METHOD = FieldOneToOne.createOwner(type, NdMethod.type, NdMethod.DEFAULT_VALUE);
type.done();
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java
index a69e52c4c9..35a0da423b 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java
@@ -12,18 +12,18 @@ package org.eclipse.jdt.internal.core.nd.java;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.Field;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
public final class NdConstantAnnotation extends NdConstant {
- public static final FieldOneToOne<NdAnnotationInConstant> VALUE;
+ public static final Field<NdAnnotation> VALUE;
@SuppressWarnings("hiding")
public static StructDef<NdConstantAnnotation> type;
static {
type = StructDef.create(NdConstantAnnotation.class, NdConstant.type);
- VALUE = FieldOneToOne.create(type, NdAnnotationInConstant.class, NdAnnotationInConstant.OWNER);
+ VALUE = Field.create(type, NdAnnotation.type);
type.done();
}
@@ -31,20 +31,10 @@ public final class NdConstantAnnotation extends NdConstant {
super(nd, address);
}
- protected NdConstantAnnotation(Nd nd) {
+ public NdConstantAnnotation(Nd nd) {
super(nd);
}
- public static NdConstantAnnotation create(Nd nd, NdAnnotationInConstant value) {
- NdConstantAnnotation result = new NdConstantAnnotation(nd);
- result.setValue(value);
- return result;
- }
-
- public void setValue(NdAnnotationInConstant value) {
- VALUE.put(getNd(), this.address, value);
- }
-
public NdAnnotation getValue() {
return VALUE.get(getNd(), this.address);
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
index e3a573049b..ef3dbe9d78 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
@@ -14,39 +14,43 @@ import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldInt;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldShort;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
public class NdMethod extends NdBinding {
- public static final FieldManyToOne<NdMethodId> METHOD_ID;
+ public static final FieldString METHOD_NAME;
public static final FieldShort METHOD_FLAGS;
- public static final FieldManyToOne<NdType> PARENT;
public static final FieldOneToMany<NdVariable> DECLARED_VARIABLES;
- public static final FieldOneToMany<NdMethodParameter> PARAMETERS;
+ public static final FieldList<NdMethodParameter> PARAMETERS;
public static final FieldOneToOne<NdConstant> DEFAULT_VALUE;
- public static final FieldOneToMany<NdMethodException> EXCEPTIONS;
+ public static final FieldList<NdMethodException> EXCEPTIONS;
public static final FieldManyToOne<NdTypeSignature> RETURN_TYPE;
public static final FieldOneToOne<NdMethodAnnotationData> ANNOTATION_DATA;
+ public static final FieldInt DECLARATION_POSITION;
@SuppressWarnings("hiding")
public static final StructDef<NdMethod> type;
static {
type = StructDef.create(NdMethod.class, NdBinding.type);
- METHOD_ID = FieldManyToOne.create(type, NdMethodId.METHODS);
+ METHOD_NAME = type.addString();
METHOD_FLAGS = type.addShort();
- PARENT = FieldManyToOne.createOwner(type, NdType.METHODS);
- PARAMETERS = FieldOneToMany.create(type, NdMethodParameter.PARENT);
+ PARAMETERS = FieldList.create(type, NdMethodParameter.type);
DECLARED_VARIABLES = FieldOneToMany.create(type, NdVariable.DECLARING_METHOD);
- DEFAULT_VALUE = FieldOneToOne.create(type, NdConstant.class, NdConstant.PARENT_METHOD);
- EXCEPTIONS = FieldOneToMany.create(type, NdMethodException.PARENT);
+ DEFAULT_VALUE = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_METHOD);
+ EXCEPTIONS = FieldList.create(type, NdMethodException.type);
RETURN_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_RETURN_TYPE);
- ANNOTATION_DATA = FieldOneToOne.create(type, NdMethodAnnotationData.class, NdMethodAnnotationData.METHOD);
+ ANNOTATION_DATA = FieldOneToOne.create(type, NdMethodAnnotationData.type, NdMethodAnnotationData.METHOD);
+ DECLARATION_POSITION = type.addInt();
type.done();
}
@@ -57,14 +61,20 @@ public class NdMethod extends NdBinding {
super(nd, address);
}
- public NdMethod(NdType parent) {
- super(parent.getNd());
+ public NdMethodParameter createNewParameter() {
+ return PARAMETERS.append(getNd(), getAddress());
+ }
+
+ public void allocateParameters(int numParameters) {
+ PARAMETERS.allocate(this.nd, this.address, numParameters);
+ }
- PARENT.put(getNd(), this.address, parent);
+ public IString getMethodName() {
+ return METHOD_NAME.get(getNd(), this.address);
}
- public NdMethodId getMethodId() {
- return METHOD_ID.get(getNd(), this.address);
+ public void setMethodName(char[] selectorAndDescriptor) {
+ METHOD_NAME.put(getNd(), getAddress(), selectorAndDescriptor);
}
/**
@@ -90,7 +100,7 @@ public class NdMethod extends NdBinding {
return PARAMETERS.asList(getNd(), this.address);
}
- public List<NdAnnotationInMethod> getAnnotations() {
+ public List<NdAnnotation> getAnnotations() {
NdMethodAnnotationData annotationData = getAnnotationData();
if (annotationData != null) {
return annotationData.getAnnotations();
@@ -110,11 +120,7 @@ public class NdMethod extends NdBinding {
RETURN_TYPE.put(getNd(), this.address, createTypeSignature);
}
- public void setMethodId(NdMethodId methodId) {
- METHOD_ID.put(getNd(), this.address, methodId);
- }
-
- public List<NdTypeAnnotationInMethod> getTypeAnnotations() {
+ public List<NdTypeAnnotation> getTypeAnnotations() {
NdMethodAnnotationData annotationData = getAnnotationData();
if (annotationData != null) {
return annotationData.getTypeAnnotations();
@@ -169,7 +175,7 @@ public class NdMethod extends NdBinding {
public String toString() {
try {
CharArrayBuffer arrayBuffer = new CharArrayBuffer();
- arrayBuffer.append(getMethodId().getSelector());
+ arrayBuffer.append(getSelector());
getGenericSignature(arrayBuffer, true);
return arrayBuffer.toString();
} catch (RuntimeException e) {
@@ -179,6 +185,24 @@ public class NdMethod extends NdBinding {
}
}
+ public char[] getSelector() {
+ IString methodName = METHOD_NAME.get(getNd(), getAddress());
+ char[] methodNameString = methodName.getChars();
+ int bracketIndex = CharArrayUtils.indexOf('(', methodNameString);
+ if (bracketIndex == -1) {
+ bracketIndex = methodNameString.length;
+ }
+ return CharArrayUtils.subarray(methodNameString, 0, bracketIndex);
+ }
+
+ public boolean isConstructor() {
+ return org.eclipse.jdt.internal.compiler.classfmt.JavaBinaryNames.isConstructor(getSelector());
+ }
+
+ public boolean isClInit() {
+ return org.eclipse.jdt.internal.compiler.classfmt.JavaBinaryNames.isClinit(getSelector());
+ }
+
public void getGenericSignature(CharArrayBuffer result, boolean includeExceptions) {
NdTypeParameter.getSignature(result, getTypeParameters());
@@ -220,4 +244,52 @@ public class NdMethod extends NdBinding {
private NdMethodAnnotationData getAnnotationData() {
return ANNOTATION_DATA.get(getNd(), getAddress());
}
+
+ public NdMethodException createException(NdTypeSignature createTypeSignature) {
+ NdMethodException result = EXCEPTIONS.append(getNd(), getAddress());
+ result.setExceptionType(createTypeSignature);
+ return result;
+ }
+
+ public void allocateExceptions(int length) {
+ EXCEPTIONS.allocate(this.nd, this.address, length);
+ }
+
+ public NdAnnotation createAnnotation() {
+ return createAnnotationData().createAnnotation();
+ }
+
+ public NdTypeAnnotation createTypeAnnotation() {
+ return createAnnotationData().createTypeAnnotation();
+ }
+
+ public void allocateAnnotations(int length) {
+ if (length > 0) {
+ createAnnotationData().allocateAnnotations(length);
+ }
+ }
+
+ public void allocateTypeAnnotations(int length) {
+ if (length > 0) {
+ createAnnotationData().allocateTypeAnnotations(length);
+ }
+ }
+
+ public void setDeclarationPosition(int position) {
+ DECLARATION_POSITION.put(getNd(), getAddress(), position);
+ }
+
+ /**
+ * Returns the unique 0-based position of the method within the class it was
+ * declared in.
+ */
+ public int getDeclarationPosition() {
+ return DECLARATION_POSITION.get(getNd(), getAddress());
+ }
+
+ public char[] getMethodDescriptor() {
+ char[] name = getMethodName().getChars();
+ int descriptorStart = CharArrayUtils.indexOf('(', name, 0, name.length);
+ return CharArrayUtils.subarray(name, descriptorStart, name.length);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java
index 913eaad849..a06518a635 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodAnnotationData.java
@@ -14,8 +14,8 @@ import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldLong;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
@@ -26,18 +26,18 @@ import org.eclipse.jdt.internal.core.nd.field.StructDef;
public class NdMethodAnnotationData extends NdNode {
public static final FieldOneToOne<NdMethod> METHOD;
public static final FieldLong TAG_BITS;
- public static final FieldOneToMany<NdAnnotationInMethod> ANNOTATIONS;
- public static final FieldOneToMany<NdTypeAnnotationInMethod> TYPE_ANNOTATIONS;
+ public static final FieldList<NdAnnotation> ANNOTATIONS;
+ public static final FieldList<NdTypeAnnotation> TYPE_ANNOTATIONS;
@SuppressWarnings("hiding")
public static final StructDef<NdMethodAnnotationData> type;
static {
type = StructDef.create(NdMethodAnnotationData.class, NdNode.type);
- METHOD = FieldOneToOne.createOwner(type, NdMethod.class, NdMethod.ANNOTATION_DATA);
+ METHOD = FieldOneToOne.createOwner(type, NdMethod.type, NdMethod.ANNOTATION_DATA);
TAG_BITS = type.addLong();
- ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInMethod.OWNER);
- TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInMethod.OWNER);
+ ANNOTATIONS = FieldList.create(type, NdAnnotation.type);
+ TYPE_ANNOTATIONS = FieldList.create(type, NdTypeAnnotation.type);
type.done();
}
@@ -59,11 +59,27 @@ public class NdMethodAnnotationData extends NdNode {
return TAG_BITS.get(getNd(), this.address);
}
- public List<NdTypeAnnotationInMethod> getTypeAnnotations() {
+ public List<NdTypeAnnotation> getTypeAnnotations() {
return TYPE_ANNOTATIONS.asList(getNd(), this.address);
}
- public List<NdAnnotationInMethod> getAnnotations() {
+ public List<NdAnnotation> getAnnotations() {
return ANNOTATIONS.asList(getNd(), this.address);
}
+
+ public NdAnnotation createAnnotation() {
+ return ANNOTATIONS.append(getNd(), getAddress());
+ }
+
+ public void allocateAnnotations(int length) {
+ ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
+
+ public NdTypeAnnotation createTypeAnnotation() {
+ return TYPE_ANNOTATIONS.append(getNd(), getAddress());
+ }
+
+ public void allocateTypeAnnotations(int length) {
+ TYPE_ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java
index 4c7cfe5a26..a90d63d9c3 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java
@@ -11,21 +11,19 @@
package org.eclipse.jdt.internal.core.nd.java;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
-public class NdMethodException extends NdNode {
+public class NdMethodException extends NdStruct {
- public static final FieldManyToOne<NdMethod> PARENT;
public static final FieldManyToOne<NdTypeSignature> EXCEPTION_TYPE;
@SuppressWarnings("hiding")
public static StructDef<NdMethodException> type;
static {
- type = StructDef.create(NdMethodException.class, NdNode.type);
- PARENT = FieldManyToOne.createOwner(type, NdMethod.EXCEPTIONS);
+ type = StructDef.create(NdMethodException.class);
EXCEPTION_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_EXCEPTION);
type.done();
}
@@ -34,21 +32,14 @@ public class NdMethodException extends NdNode {
super(nd, address);
}
- public NdMethodException(NdMethod method, NdTypeSignature createTypeSignature) {
- super(method.getNd());
-
- PARENT.put(getNd(), this.address, method);
- EXCEPTION_TYPE.put(getNd(), this.address, createTypeSignature);
+ public void setExceptionType(NdTypeSignature signature) {
+ EXCEPTION_TYPE.put(getNd(), this.address, signature);
}
public NdTypeSignature getExceptionType() {
return EXCEPTION_TYPE.get(getNd(), this.address);
}
- public NdMethod getParent() {
- return PARENT.get(getNd(), this.address);
- }
-
public String toString() {
try {
return getExceptionType().toString();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java
deleted file mode 100644
index d505c26f8c..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import java.util.List;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
-import org.eclipse.jdt.internal.core.nd.db.IString;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
-import org.eclipse.jdt.internal.core.nd.field.FieldSearchKey;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
-
-/**
- * Represents the fully-qualified signature a method. Holds back-pointers to all the entities that refer to the name,
- * along with pointers to all methods that have this fully-qualified name. Note that this isn't the class declaration
- * itself. If there are multiple jar files containing a class of the same fully-qualified name, there may also be
- * multiple methods with the same method ID.
- */
-public class NdMethodId extends NdNode {
- public static final FieldSearchKey<JavaIndex> METHOD_NAME;
- public static final FieldOneToMany<NdMethod> METHODS;
- public static final FieldOneToMany<NdType> DECLARED_TYPES;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdMethodId> type;
-
- static {
- type = StructDef.create(NdMethodId.class, NdNode.type);
- METHOD_NAME = FieldSearchKey.create(type, JavaIndex.METHODS);
- METHODS = FieldOneToMany.create(type, NdMethod.METHOD_ID, 2);
- DECLARED_TYPES = FieldOneToMany.create(type, NdType.DECLARING_METHOD);
-
- type.useStandardRefCounting().done();
- }
-
- public NdMethodId(Nd nd, long address) {
- super(nd, address);
- }
-
- /**
- *
- * @param nd
- * @param methodIdentifier a field descriptor for the method type followed by a "#" followed by a method selector
- * followed by method descriptor. For example, "Lorg/eclipse/MyClass#foo()Ljava/lang/Object;V"
- */
- public NdMethodId(Nd nd, char[] methodIdentifier) {
- super(nd);
-
- METHOD_NAME.put(nd, this.address, methodIdentifier);
- }
-
- public List<NdType> getDeclaredTypes() {
- return DECLARED_TYPES.asList(getNd(), this.address);
- }
-
- /**
- * Returns the field descriptor for the type (without a trailing ';') followed by a # followed by the method
- * selector followed by the method descriptor. For example, "Lorg/eclipse/MyClass#foo()Ljava/lang/Object;V"
- */
- public IString getMethodName() {
- return METHOD_NAME.get(getNd(), this.address);
- }
-
- public char[] getSelector() {
- char[] name = getMethodName().getChars();
- int selectorStart = CharArrayUtils.indexOf('#', name) + 1;
- int selectorEnd = CharArrayUtils.indexOf('(', name, selectorStart, name.length);
- if (selectorEnd == -1) {
- selectorEnd = name.length;
- }
- return CharArrayUtils.subarray(name, selectorStart, selectorEnd);
- }
-
- public boolean isConstructor() {
- return org.eclipse.jdt.internal.compiler.classfmt.JavaBinaryNames.isConstructor(getSelector());
- }
-
- public char[] getMethodDescriptor() {
- char[] name = getMethodName().getChars();
- int descriptorStart = CharArrayUtils.indexOf('(', name, 0, name.length);
- return CharArrayUtils.subarray(name, descriptorStart, name.length);
- }
-
- public boolean isClInit() {
- return org.eclipse.jdt.internal.compiler.classfmt.JavaBinaryNames.isClinit(getSelector());
- }
-
- public String toString() {
- try {
- return new String(getSelector());
- } catch (RuntimeException e) {
- // This is called most often from the debugger, so we want to return something meaningful even
- // if the code is buggy, the database is corrupt, or we don't have a read lock.
- return super.toString();
- }
- }
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java
index bdcd8324df..47d5df26de 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java
@@ -13,20 +13,19 @@ package org.eclipse.jdt.internal.core.nd.java;
import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
import org.eclipse.jdt.internal.core.nd.db.IString;
import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
-public class NdMethodParameter extends NdNode {
- public static final FieldManyToOne<NdMethod> PARENT;
+public class NdMethodParameter extends NdStruct {
public static final FieldManyToOne<NdTypeSignature> ARGUMENT_TYPE;
public static final FieldString NAME;
- public static final FieldOneToMany<NdAnnotationInMethodParameter> ANNOTATIONS;
+ public static final FieldList<NdAnnotation> ANNOTATIONS;
public static final FieldByte FLAGS;
private static final byte FLG_COMPILER_DEFINED = 0x01;
@@ -35,11 +34,10 @@ public class NdMethodParameter extends NdNode {
public static StructDef<NdMethodParameter> type;
static {
- type = StructDef.create(NdMethodParameter.class, NdNode.type);
- PARENT = FieldManyToOne.create(type, NdMethod.PARAMETERS);
+ type = StructDef.create(NdMethodParameter.class);
ARGUMENT_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_METHOD_ARGUMENT);
NAME = type.addString();
- ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInMethodParameter.OWNER);
+ ANNOTATIONS = FieldList.create(type, NdAnnotation.type);
FLAGS = type.addByte();
type.done();
}
@@ -48,10 +46,7 @@ public class NdMethodParameter extends NdNode {
super(nd, address);
}
- public NdMethodParameter(NdMethod parent, NdTypeSignature argumentType) {
- super(parent.getNd());
-
- PARENT.put(getNd(), this.address, parent);
+ public void setType(NdTypeSignature argumentType) {
ARGUMENT_TYPE.put(getNd(), this.address, argumentType);
}
@@ -67,7 +62,7 @@ public class NdMethodParameter extends NdNode {
return NAME.get(getNd(), this.address);
}
- public List<NdAnnotationInMethodParameter> getAnnotations() {
+ public List<NdAnnotation> getAnnotations() {
return ANNOTATIONS.asList(getNd(), this.address);
}
@@ -102,4 +97,12 @@ public class NdMethodParameter extends NdNode {
return super.toString();
}
}
+
+ public NdAnnotation createAnnotation() {
+ return ANNOTATIONS.append(getNd(), getAddress());
+ }
+
+ public void allocateAnnotations(int length) {
+ ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
index 925d717d1a..9c8e979795 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
@@ -18,9 +18,11 @@ import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
import org.eclipse.jdt.internal.core.nd.db.Database;
import org.eclipse.jdt.internal.core.nd.db.IString;
import org.eclipse.jdt.internal.core.nd.db.IndexException;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldLong;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany.Visitor;
@@ -34,7 +36,7 @@ import org.eclipse.jdt.internal.core.nd.field.StructDef;
/**
* Represents a source of java classes (such as a .jar or .class file).
*/
-public class NdResourceFile extends NdTreeNode {
+public class NdResourceFile extends NdNode {
public static final FieldSearchKey<JavaIndex> FILENAME;
public static final FieldOneToMany<NdType> TYPES;
public static final FieldLong TIME_LAST_USED;
@@ -44,7 +46,7 @@ public class NdResourceFile extends NdTreeNode {
public static final FieldOneToMany<NdWorkspaceLocation> WORKSPACE_MAPPINGS;
public static final FieldString JAVA_ROOT;
public static final FieldLong JDK_LEVEL;
- public static final FieldOneToMany<NdZipEntry> ZIP_ENTRIES;
+ public static final FieldList<NdZipEntry> ZIP_ENTRIES;
public static final FieldString MANIFEST_CONTENT;
public static final FieldShort FILE_FLAGS;
@@ -57,7 +59,7 @@ public class NdResourceFile extends NdTreeNode {
public static final StructDef<NdResourceFile> type;
static {
- type = StructDef.create(NdResourceFile.class, NdTreeNode.type);
+ type = StructDef.create(NdResourceFile.class, NdNode.type);
FILENAME = FieldSearchKey.create(type, JavaIndex.FILES);
TYPES = FieldOneToMany.create(type, NdType.FILE, 16);
TIME_LAST_USED = type.addLong();
@@ -67,7 +69,7 @@ public class NdResourceFile extends NdTreeNode {
WORKSPACE_MAPPINGS = FieldOneToMany.create(type, NdWorkspaceLocation.RESOURCE);
JAVA_ROOT = type.addString();
JDK_LEVEL = type.addLong();
- ZIP_ENTRIES = FieldOneToMany.create(type, NdZipEntry.JAR_FILE);
+ ZIP_ENTRIES = FieldList.create(type, NdZipEntry.type, 1);
MANIFEST_CONTENT = type.addString();
FILE_FLAGS = type.addShort();
@@ -81,7 +83,7 @@ public class NdResourceFile extends NdTreeNode {
}
public NdResourceFile(Nd nd) {
- super(nd, null);
+ super(nd);
}
public boolean isCorruptedZipFile() {
@@ -140,10 +142,6 @@ public class NdResourceFile extends NdTreeNode {
}
}
- public List<NdTreeNode> getChildren() {
- return CHILDREN.asList(this.getNd(), this.address);
- }
-
/**
* Determines whether this file is still in the index. If a {@link NdResourceFile} instance is retained while the
* database lock is released and reobtained, this method should be invoked to ensure that the {@link NdResourceFile}
@@ -151,16 +149,16 @@ public class NdResourceFile extends NdTreeNode {
*/
public boolean isInIndex() {
try {
- Nd nd = getNd();
// In the common case where the resource file was deleted and the memory hasn't yet been reused,
// this will fail.
- if (!nd.isValidAddress(this.address) || NODE_TYPE.get(nd, this.address) != nd.getNodeType(getClass())) {
+ if (!this.nd.isValidAddress(this.address)
+ || NODE_TYPE.get(this.nd, this.address) != this.nd.getNodeType(getClass())) {
return false;
}
char[] filename = FILENAME.get(getNd(), this.address).getChars();
- NdResourceFile result = JavaIndex.FILES.findBest(nd, Database.DATA_AREA_OFFSET,
+ NdResourceFile result = JavaIndex.FILES.findBest(this.nd, Database.DATA_AREA_OFFSET,
SearchCriteria.create(filename), new IResultRank() {
@Override
public long getRank(Nd testNd, long testAddress) {
@@ -330,4 +328,14 @@ public class NdResourceFile extends NdTreeNode {
return super.toString();
}
}
+
+ public void allocateZipEntries(int expectedNumberOfZipEntries) {
+ ZIP_ENTRIES.allocate(this.nd, this.address, expectedNumberOfZipEntries);
+ }
+
+ public NdZipEntry addZipEntry(String fileName) {
+ NdZipEntry result = ZIP_ENTRIES.append(getNd(), getAddress());
+ result.setFilename(fileName);
+ return result;
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java
deleted file mode 100644
index d9e33db804..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
-import org.eclipse.jdt.internal.core.nd.db.IndexException;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-/**
- * {@link NdTreeNode} elements form a tree of nodes rooted at a {@link NdResourceFile}. Each node contains a list of
- * children which it declares and has a pointer to the most specific node which declares it.
- */
-public abstract class NdTreeNode extends NdNode {
- public static final FieldManyToOne<NdTreeNode> PARENT;
- public static final FieldOneToMany<NdTreeNode> CHILDREN;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdTreeNode> type;
-
- static {
- type = StructDef.create(NdTreeNode.class, NdNode.type);
- PARENT = FieldManyToOne.create(type, null);
- CHILDREN = FieldOneToMany.create(type, PARENT, 16);
- type.done();
- }
-
- public NdTreeNode(Nd nd, long address) {
- super(nd, address);
- }
-
- protected NdTreeNode(Nd nd, NdTreeNode parent) {
- super(nd);
-
- PARENT.put(nd, this.address, parent == null ? 0 : parent.address);
- }
-
- public int getChildrenCount() {
- return CHILDREN.size(getNd(), this.address);
- }
-
- public NdTreeNode getChild(int index) {
- return CHILDREN.get(getNd(), this.address, index);
- }
-
- /**
- * Returns the closest ancestor of the given type, or null if none. Note that
- * this looks for an exact match. It will not return subtypes of the given type.
- */
- @SuppressWarnings("unchecked")
- public <T extends NdTreeNode> T getAncestorOfType(Class<T> ancestorType) {
- long targetType = getNd().getNodeType(ancestorType);
-
- Nd nd = getNd();
- long current = PARENT.getAddress(nd, this.address);
-
- while (current != 0) {
- short currentType = NODE_TYPE.get(nd, current);
-
- if (currentType == targetType) {
- NdNode result = load(nd, current);
-
- if (ancestorType.isInstance(result)) {
- return (T) result;
- } else {
- throw new IndexException("The node at address " + current + //$NON-NLS-1$
- " should have been an instance of " + ancestorType.getName() + //$NON-NLS-1$
- " but was an instance of " + result.getClass().getName()); //$NON-NLS-1$
- }
- }
-
- current = PARENT.getAddress(nd, current);
- }
-
- return null;
- }
-
- NdTreeNode getParentNode() {
- return PARENT.get(getNd(), this.address);
- }
-
- public NdBinding getParentBinding() throws IndexException {
- NdNode parent= getParentNode();
- if (parent instanceof NdBinding) {
- return (NdBinding) parent;
- }
- return null;
- }
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java
index d83f37a4f1..ddd7074408 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java
@@ -10,13 +10,13 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.java;
+import java.util.Arrays;
import java.util.List;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.internal.core.nd.INdVisitor;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.db.IString;
import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldLong;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
@@ -30,15 +30,16 @@ public class NdType extends NdBinding {
public static final FieldManyToOne<NdTypeSignature> SUPERCLASS;
public static final FieldOneToMany<NdTypeInterface> INTERFACES;
public static final FieldManyToOne<NdTypeId> DECLARING_TYPE;
- public static final FieldManyToOne<NdMethodId> DECLARING_METHOD;
- public static final FieldOneToMany<NdMethod> METHODS;
- public static final FieldOneToMany<NdTypeAnnotationInType> TYPE_ANNOTATIONS;
- public static final FieldOneToMany<NdAnnotationInType> ANNOTATIONS;
+ public static final FieldList<NdMethod> METHODS;
+ public static final FieldList<NdTypeAnnotation> TYPE_ANNOTATIONS;
+ public static final FieldList<NdAnnotation> ANNOTATIONS;
+ public static final FieldList<NdVariable> VARIABLES;
public static final FieldString MISSING_TYPE_NAMES;
public static final FieldString SOURCE_FILE_NAME;
public static final FieldString INNER_CLASS_SOURCE_NAME;
public static final FieldByte FLAGS;
public static final FieldLong TAG_BITS;
+ public static final FieldString ENCLOSING_METHOD;
/**
* Binary name that was recorded in the .class file if different from the binary
* name that was determined by the .class's name and location. This is only set for
@@ -56,16 +57,17 @@ public class NdType extends NdBinding {
DECLARING_TYPE = FieldManyToOne.create(type, NdTypeId.DECLARED_TYPES);
INTERFACES = FieldOneToMany.create(type, NdTypeInterface.APPLIES_TO);
SUPERCLASS = FieldManyToOne.create(type, NdTypeSignature.SUBCLASSES);
- DECLARING_METHOD = FieldManyToOne.create(type, NdMethodId.DECLARED_TYPES);
- METHODS = FieldOneToMany.create(type, NdMethod.PARENT, 6);
- TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInType.OWNER);
- ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInType.OWNER);
+ METHODS = FieldList.create(type, NdMethod.type);
+ TYPE_ANNOTATIONS = FieldList.create(type, NdTypeAnnotation.type);
+ ANNOTATIONS = FieldList.create(type, NdAnnotation.type);
+ VARIABLES = FieldList.create(type, NdVariable.type);
MISSING_TYPE_NAMES = type.addString();
SOURCE_FILE_NAME = type.addString();
INNER_CLASS_SOURCE_NAME = type.addString();
FLAGS = type.addByte();
TAG_BITS = type.addLong();
FIELD_DESCRIPTOR_FROM_CLASS = type.addString();
+ ENCLOSING_METHOD = type.addString();
type.done();
}
@@ -84,13 +86,6 @@ public class NdType extends NdBinding {
FILE.put(nd, this.address, resource);
}
- /**
- * Called to populate the cache for the bindings in the class scope.
- */
- public void acceptUncached(INdVisitor visitor) throws CoreException {
- super.accept(visitor);
- }
-
public NdTypeId getTypeId() {
return TYPENAME.get(getNd(), this.address);
}
@@ -141,10 +136,6 @@ public class NdType extends NdBinding {
return FILE.get(getNd(), this.address);
}
- public void setDeclaringMethod(NdMethodId createMethodId) {
- DECLARING_METHOD.put(getNd(), this.address, createMethodId);
- }
-
/**
* @param createTypeIdFromBinaryName
*/
@@ -221,8 +212,8 @@ public class NdType extends NdBinding {
return JavaNames.simpleNameToSourceName(simpleName);
}
- public NdMethodId getDeclaringMethod() {
- return DECLARING_METHOD.get(getNd(), this.address);
+ public List<NdVariable> getVariables() {
+ return VARIABLES.asList(getNd(), this.address);
}
@Override
@@ -230,18 +221,59 @@ public class NdType extends NdBinding {
return TYPE_PARAMETERS.asList(getNd(), this.address);
}
- public List<NdTypeAnnotationInType> getTypeAnnotations() {
+ public List<NdTypeAnnotation> getTypeAnnotations() {
return TYPE_ANNOTATIONS.asList(getNd(), this.address);
}
- public List<NdAnnotationInType> getAnnotations() {
+ public List<NdAnnotation> getAnnotations() {
return ANNOTATIONS.asList(getNd(), this.address);
}
+ public NdAnnotation createAnnotation() {
+ return ANNOTATIONS.append(getNd(), getAddress());
+ }
+
+ public void allocateAnnotations(int length) {
+ ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
+
+ /**
+ * Returns the list of methods, sorted by ascending method name (selector + descriptor).
+ */
public List<NdMethod> getMethods() {
return METHODS.asList(getNd(), this.address);
}
+ /**
+ * Returns the list of methods, in declaration order.
+ */
+ public List<NdMethod> getMethodsInDeclarationOrder() {
+ List<NdMethod> unsorted = getMethods();
+ NdMethod[] sorted = new NdMethod[unsorted.size()];
+ for (NdMethod next : unsorted) {
+ int pos = next.getDeclarationPosition();
+
+ if (pos < 0 || pos >= sorted.length) {
+ throw getNd().describeProblem()
+ .addProblemAddress(NdMethod.DECLARATION_POSITION, next.getAddress())
+ .build("Method " + next.getMethodName().getString() + " reports invalid position of " + pos); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ NdMethod oldMethodAtThisPosition = sorted[pos];
+ if (oldMethodAtThisPosition != null) {
+ throw getNd().describeProblem()
+ .addProblemAddress(NdMethod.DECLARATION_POSITION, next.getAddress())
+ .addProblemAddress(NdMethod.DECLARATION_POSITION, oldMethodAtThisPosition.getAddress())
+ .build("Method " + oldMethodAtThisPosition.getMethodName().getString() //$NON-NLS-1$
+ + " and method " + next.getMethodName().getString() + " both claim to be at position " //$NON-NLS-1$//$NON-NLS-2$
+ + pos);
+ }
+ sorted[pos] = next;
+ }
+
+ return Arrays.asList(sorted);
+ }
+
@Override
public String toString() {
try {
@@ -275,4 +307,36 @@ public class NdType extends NdBinding {
}
return descriptorFromClass;
}
+
+ public NdTypeAnnotation createTypeAnnotation() {
+ return TYPE_ANNOTATIONS.append(getNd(), getAddress());
+ }
+
+ public void allocateTypeAnnotations(int length) {
+ TYPE_ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
+
+ public NdVariable createVariable() {
+ return VARIABLES.append(getNd(), getAddress());
+ }
+
+ public void allocateVariables(int length) {
+ VARIABLES.allocate(getNd(), getAddress(), length);
+ }
+
+ public void allocateMethods(int length) {
+ METHODS.allocate(getNd(), getAddress(), length);
+ }
+
+ public NdMethod createMethod() {
+ return METHODS.append(getNd(), getAddress());
+ }
+
+ public void setDeclaringMethod(char[] enclosingMethod) {
+ ENCLOSING_METHOD.put(getNd(), getAddress(), enclosingMethod);
+ }
+
+ public IString getDeclaringMethod() {
+ return ENCLOSING_METHOD.get(getNd(), getAddress());
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java
index e9bfa4a4d6..b6c0908eb1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java
@@ -11,13 +11,14 @@
package org.eclipse.jdt.internal.core.nd.java;
import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
+import org.eclipse.jdt.internal.core.nd.IDestructable;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.db.Database;
import org.eclipse.jdt.internal.core.nd.field.FieldByte;
import org.eclipse.jdt.internal.core.nd.field.FieldPointer;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
-public class NdTypeAnnotation extends NdAnnotation {
+public class NdTypeAnnotation extends NdAnnotation implements IDestructable {
public static final FieldByte TARGET_TYPE;
public static final FieldByte TARGET_ARG0;
public static final FieldByte TARGET_ARG1;
@@ -43,18 +44,13 @@ public class NdTypeAnnotation extends NdAnnotation {
super(nd, address);
}
- public NdTypeAnnotation(Nd nd) {
- super(nd);
- }
-
public void setPath(byte[] path) {
freePath();
- Nd nd = getNd();
- PATH_LENGTH.put(nd, this.address, (byte)path.length);
+ PATH_LENGTH.put(this.nd, this.address, (byte) path.length);
if (path.length > 0) {
- long pathArray = nd.getDB().malloc(path.length, Database.POOL_MISC);
- PATH.put(nd, this.address, pathArray);
- nd.getDB().putBytes(pathArray, path, path.length);
+ long pathArray = this.nd.getDB().malloc(path.length, Database.POOL_MISC);
+ PATH.put(this.nd, this.address, pathArray);
+ this.nd.getDB().putBytes(pathArray, path, path.length);
}
}
@@ -111,12 +107,10 @@ public class NdTypeAnnotation extends NdAnnotation {
@Override
public void destruct() {
freePath();
- super.destruct();
}
private void freePath() {
- Nd nd = getNd();
- long pathPointer = PATH.get(nd, this.address);
- nd.getDB().free(pathPointer, Database.POOL_MISC);
+ long pathPointer = PATH.get(this.nd, this.address);
+ this.nd.getDB().free(pathPointer, Database.POOL_MISC);
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java
deleted file mode 100644
index 06dcce393a..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdTypeAnnotationInMethod extends NdTypeAnnotation {
- public static final FieldManyToOne<NdMethodAnnotationData> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdTypeAnnotationInMethod> type;
-
- static {
- type = StructDef.create(NdTypeAnnotationInMethod.class, NdTypeAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdMethodAnnotationData.TYPE_ANNOTATIONS);
- type.done();
- }
-
- public NdTypeAnnotationInMethod(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdTypeAnnotationInMethod(Nd nd, NdMethod method) {
- super(nd);
-
- OWNER.put(getNd(), this.address, method.createAnnotationData());
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java
deleted file mode 100644
index 7aff109084..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdTypeAnnotationInType extends NdTypeAnnotation {
- public static final FieldManyToOne<NdType> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdTypeAnnotationInType> type;
-
- static {
- type = StructDef.create(NdTypeAnnotationInType.class, NdTypeAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdType.TYPE_ANNOTATIONS);
- type.done();
- }
-
- public NdTypeAnnotationInType(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdTypeAnnotationInType(Nd nd, NdType type) {
- super(nd);
-
- OWNER.put(getNd(), this.address, type);
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java
deleted file mode 100644
index eb591fe06e..0000000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Xenos (Google) - Initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.nd.java;
-
-import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.StructDef;
-
-public class NdTypeAnnotationInVariable extends NdTypeAnnotation {
- public static final FieldManyToOne<NdVariable> OWNER;
-
- @SuppressWarnings("hiding")
- public static final StructDef<NdTypeAnnotationInVariable> type;
-
- static {
- type = StructDef.create(NdTypeAnnotationInVariable.class, NdTypeAnnotation.type);
- OWNER = FieldManyToOne.createOwner(type, NdVariable.TYPE_ANNOTATIONS);
- type.done();
- }
-
- public NdTypeAnnotationInVariable(Nd nd, long address) {
- super(nd, address);
- }
-
- public NdTypeAnnotationInVariable(Nd nd, NdVariable variable) {
- super(nd);
-
- OWNER.put(getNd(), this.address, variable);
- }
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java
index c6c827eeef..1a5e0ef395 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java
@@ -11,7 +11,7 @@
package org.eclipse.jdt.internal.core.nd.java;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
@@ -20,16 +20,14 @@ import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
* Represents the bound on a generic parameter (a ClassBound or InterfaceBound in
* the sense of the Java VM spec Java SE 8 Edition, section 4.7.9.1).
*/
-public class NdTypeBound extends NdNode {
- public static final FieldManyToOne<NdTypeParameter> PARENT;
+public class NdTypeBound extends NdStruct {
public static final FieldManyToOne<NdTypeSignature> TYPE;
@SuppressWarnings("hiding")
public static final StructDef<NdTypeBound> type;
static {
- type = StructDef.create(NdTypeBound.class, NdNode.type);
- PARENT = FieldManyToOne.createOwner(type, NdTypeParameter.BOUNDS);
+ type = StructDef.create(NdTypeBound.class, NdStruct.type);
TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_TYPE_BOUND);
type.done();
@@ -39,17 +37,10 @@ public class NdTypeBound extends NdNode {
super(nd, address);
}
- public NdTypeBound(NdTypeParameter parent, NdTypeSignature signature) {
- super(parent.getNd());
-
- PARENT.put(getNd(), this.address, parent);
+ public void setType(NdTypeSignature signature) {
TYPE.put(getNd(), this.address, signature);
}
- public NdTypeParameter getParent() {
- return PARENT.get(getNd(), this.address);
- }
-
public NdTypeSignature getType() {
return TYPE.get(getNd(), this.address);
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java
index a132f97f9b..b11843b541 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016 Google, Inc and others.
+ * Copyright (c) 2016, 2017 Google, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -128,7 +128,7 @@ public class NdTypeId extends NdTypeSignature {
if (this.fName != null)
return this.fName.equals(name);
- return getSimpleName().equals(name);
+ return getSimpleName().toString().equals(name);
}
public void setSimpleName(String name) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java
index fda4676b18..8809b841ad 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java
@@ -13,10 +13,9 @@ package org.eclipse.jdt.internal.core.nd.java;
import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
import org.eclipse.jdt.internal.core.nd.field.FieldByte;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
@@ -24,10 +23,9 @@ import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
/**
* Represents a TypeParameter, as described in Section 4.7.9.1 of the java VM specification, Java SE 8 edititon.
*/
-public class NdTypeParameter extends NdNode {
- public static final FieldManyToOne<NdBinding> PARENT;
+public class NdTypeParameter extends NdStruct {
public static final FieldString IDENTIFIER;
- public static final FieldOneToMany<NdTypeBound> BOUNDS;
+ public static final FieldList<NdTypeBound> BOUNDS;
public static final FieldByte TYPE_PARAMETER_FLAGS;
public static final byte FLG_FIRST_BOUND_IS_A_CLASS = 0x01;
@@ -36,10 +34,9 @@ public class NdTypeParameter extends NdNode {
public static final StructDef<NdTypeParameter> type;
static {
- type = StructDef.create(NdTypeParameter.class, NdNode.type);
- PARENT = FieldManyToOne.createOwner(type, NdBinding.TYPE_PARAMETERS);
+ type = StructDef.create(NdTypeParameter.class, NdStruct.type);
IDENTIFIER = type.addString();
- BOUNDS = FieldOneToMany.create(type, NdTypeBound.PARENT);
+ BOUNDS = FieldList.create(type, NdTypeBound.type);
TYPE_PARAMETER_FLAGS = type.addByte();
type.done();
@@ -49,10 +46,7 @@ public class NdTypeParameter extends NdNode {
super(nd, address);
}
- public NdTypeParameter(NdBinding parent, char[] identifier) {
- super(parent.getNd());
-
- PARENT.put(getNd(), this.address, parent);
+ public void setIdentifier(char[] identifier) {
IDENTIFIER.put(getNd(), this.address, identifier);
}
@@ -108,4 +102,12 @@ public class NdTypeParameter extends NdNode {
buffer.append('>');
}
}
+
+ public void createBound(NdTypeSignature boundSignature) {
+ BOUNDS.append(getNd(), getAddress()).setType(boundSignature);
+ }
+
+ public void allocateBounds(int numBounds) {
+ BOUNDS.allocate(getNd(), getAddress(), numBounds);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java
index fabc0e86f1..1006637b2c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java
@@ -16,9 +16,9 @@ import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.db.IString;
import org.eclipse.jdt.internal.core.nd.field.FieldByte;
import org.eclipse.jdt.internal.core.nd.field.FieldInt;
+import org.eclipse.jdt.internal.core.nd.field.FieldList;
import org.eclipse.jdt.internal.core.nd.field.FieldLong;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
-import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
@@ -27,13 +27,12 @@ public class NdVariable extends NdBinding {
public static final FieldManyToOne<NdTypeSignature> TYPE;
public static final FieldInt VARIABLE_ID;
public static final FieldManyToOne<NdMethod> DECLARING_METHOD;
- public static final FieldManyToOne<NdBinding> PARENT;
public static final FieldString NAME;
public static final FieldOneToOne<NdConstant> CONSTANT;
public static final FieldLong TAG_BITS;
public static final FieldByte VARIABLE_FLAGS;
- public static final FieldOneToMany<NdAnnotationInVariable> ANNOTATIONS;
- public static final FieldOneToMany<NdTypeAnnotationInVariable> TYPE_ANNOTATIONS;
+ public static final FieldList<NdAnnotation> ANNOTATIONS;
+ public static final FieldList<NdTypeAnnotation> TYPE_ANNOTATIONS;
@SuppressWarnings("hiding")
public static StructDef<NdVariable> type;
@@ -45,13 +44,12 @@ public class NdVariable extends NdBinding {
TYPE = FieldManyToOne.create(type, NdTypeSignature.VARIABLES_OF_TYPE);
VARIABLE_ID = type.addInt();
DECLARING_METHOD = FieldManyToOne.create(type, NdMethod.DECLARED_VARIABLES);
- PARENT = FieldManyToOne.createOwner(type, NdBinding.VARIABLES);
NAME = type.addString();
- CONSTANT = FieldOneToOne.create(type, NdConstant.class, NdConstant.PARENT_VARIABLE);
+ CONSTANT = FieldOneToOne.create(type, NdConstant.type, NdConstant.PARENT_VARIABLE);
TAG_BITS = type.addLong();
VARIABLE_FLAGS = type.addByte();
- ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInVariable.OWNER);
- TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInVariable.OWNER);
+ ANNOTATIONS = FieldList.create(type, NdAnnotation.type);
+ TYPE_ANNOTATIONS = FieldList.create(type, NdTypeAnnotation.type);
type.done();
}
@@ -59,12 +57,6 @@ public class NdVariable extends NdBinding {
super(nd, bindingRecord);
}
- public NdVariable(NdBinding parent) {
- super(parent.getNd());
-
- PARENT.put(getNd(), this.address, parent);
- }
-
public boolean hasVariableFlag(int toTest) {
return (VARIABLE_FLAGS.get(getNd(), this.address) & toTest) != 0;
}
@@ -106,14 +98,22 @@ public class NdVariable extends NdBinding {
TAG_BITS.put(getNd(), this.address, tagBits);
}
- public List<NdTypeAnnotationInVariable> getTypeAnnotations() {
+ public List<NdTypeAnnotation> getTypeAnnotations() {
return TYPE_ANNOTATIONS.asList(getNd(), this.address);
}
- public List<NdAnnotationInVariable> getAnnotations() {
+ public List<NdAnnotation> getAnnotations() {
return ANNOTATIONS.asList(getNd(), this.address);
}
+ public NdAnnotation createAnnotation() {
+ return ANNOTATIONS.append(this.getNd(), this.getAddress());
+ }
+
+ public void allocateAnnotations(int length) {
+ ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
+
public String toString() {
try {
StringBuilder result = new StringBuilder();
@@ -138,4 +138,12 @@ public class NdVariable extends NdBinding {
return super.toString();
}
}
+
+ public NdTypeAnnotation createTypeAnnotation() {
+ return TYPE_ANNOTATIONS.append(getNd(), getAddress());
+ }
+
+ public void allocateTypeAnnotations(int length) {
+ TYPE_ANNOTATIONS.allocate(getNd(), getAddress(), length);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java
index e0086ab193..4e4f82cf52 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdZipEntry.java
@@ -11,25 +11,22 @@
package org.eclipse.jdt.internal.core.nd.java;
import org.eclipse.jdt.internal.core.nd.Nd;
-import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdStruct;
import org.eclipse.jdt.internal.core.nd.db.IString;
-import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
/**
* Stores a (non-class) file within a .jar file.
*/
-public class NdZipEntry extends NdNode {
- public static final FieldManyToOne<NdResourceFile> JAR_FILE;
+public class NdZipEntry extends NdStruct {
public static final FieldString FILE_NAME;
@SuppressWarnings("hiding")
public static final StructDef<NdZipEntry> type;
static {
- type = StructDef.create(NdZipEntry.class, NdNode.type);
- JAR_FILE = FieldManyToOne.createOwner(type, NdResourceFile.ZIP_ENTRIES);
+ type = StructDef.create(NdZipEntry.class, NdStruct.type);
FILE_NAME = type.addString();
type.done();
@@ -39,14 +36,11 @@ public class NdZipEntry extends NdNode {
super(nd, address);
}
- public NdZipEntry(NdResourceFile nd, String path) {
- super(nd.getNd());
-
- JAR_FILE.put(nd.getNd(), getAddress(), nd);
- FILE_NAME.put(nd.getNd(), getAddress(), path);
+ public void setFilename(String filename) {
+ FILE_NAME.put(this.nd, this.address, filename);
}
public IString getFileName() {
- return FILE_NAME.get(getNd(), getAddress());
+ return FILE_NAME.get(this.nd, this.address);
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java
index 9ad5a60953..d81e73a791 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java
@@ -78,7 +78,9 @@ public abstract class TagTreeReader {
readAddress += Database.BYTE_SIZE;
TagHandler<?> reader = this.readers[nextByte];
if (reader == null) {
- throw new IndexException("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$
+ throw nd.describeProblem()
+ .addProblemAddress("tag", address, 1) //$NON-NLS-1$
+ .build("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$
}
return reader.read(nd, readAddress, this, bytesRead);
@@ -98,7 +100,7 @@ public abstract class TagTreeReader {
TagHandler handler = this.readers[key];
if (handler == null) {
- throw new IndexException("Invalid key " + key + " returned from getKeyFor(...)"); //$NON-NLS-1$//$NON-NLS-2$
+ throw nd.describeProblem().build("Invalid key " + key + " returned from getKeyFor(...)"); //$NON-NLS-1$//$NON-NLS-2$
}
handler.write(nd, address, this, toWrite, bytesWritten);
@@ -112,7 +114,9 @@ public abstract class TagTreeReader {
TagHandler<?> handler = this.readers[nextByte];
if (handler == null) {
- throw new IndexException("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$
+ throw nd.describeProblem()
+ .addProblemAddress("tag", address, 1) //$NON-NLS-1$
+ .build("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$
}
handler.destruct(nd, readAddress, this);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
index bd17859b6a..de8ff258ac 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
@@ -42,7 +42,6 @@ import org.eclipse.jdt.internal.core.nd.java.NdConstantClass;
import org.eclipse.jdt.internal.core.nd.java.NdConstantEnum;
import org.eclipse.jdt.internal.core.nd.java.NdMethod;
import org.eclipse.jdt.internal.core.nd.java.NdMethodException;
-import org.eclipse.jdt.internal.core.nd.java.NdMethodId;
import org.eclipse.jdt.internal.core.nd.java.NdMethodParameter;
import org.eclipse.jdt.internal.core.nd.java.NdResourceFile;
import org.eclipse.jdt.internal.core.nd.java.NdType;
@@ -53,7 +52,6 @@ import org.eclipse.jdt.internal.core.nd.java.NdTypeParameter;
import org.eclipse.jdt.internal.core.nd.java.NdTypeSignature;
import org.eclipse.jdt.internal.core.nd.java.NdVariable;
import org.eclipse.jdt.internal.core.nd.java.TypeRef;
-import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
/**
@@ -264,7 +262,7 @@ public class IndexBinaryType implements IBinaryType {
try (IReader rl = this.typeRef.lock()) {
NdType type = this.typeRef.get();
if (type != null) {
- List<NdMethod> methods = type.getMethods();
+ List<NdMethod> methods = type.getMethodsInDeclarationOrder();
if (methods.isEmpty()) {
return null;
@@ -381,17 +379,15 @@ public class IndexBinaryType implements IBinaryType {
}
private IBinaryMethod createBinaryMethod(NdMethod ndMethod) {
- NdMethodId methodId = ndMethod.getMethodId();
-
return IndexBinaryMethod.create().setAnnotations(toAnnotationArray(ndMethod.getAnnotations()))
- .setModifiers(ndMethod.getModifiers()).setIsConstructor(methodId.isConstructor())
+ .setModifiers(ndMethod.getModifiers()).setIsConstructor(ndMethod.isConstructor())
.setArgumentNames(getArgumentNames(ndMethod)).setDefaultValue(unpackValue(ndMethod.getDefaultValue()))
.setExceptionTypeNames(getExceptionTypeNames(ndMethod))
.setGenericSignature(getGenericSignatureFor(ndMethod))
- .setMethodDescriptor(methodId.getMethodDescriptor())
+ .setMethodDescriptor(ndMethod.getMethodDescriptor())
.setParameterAnnotations(getParameterAnnotations(ndMethod))
- .setSelector(ndMethod.getMethodId().getSelector()).setTagBits(ndMethod.getTagBits())
- .setIsClInit(methodId.isClInit()).setTypeAnnotations(createBinaryTypeAnnotations(ndMethod.getTypeAnnotations()));
+ .setSelector(ndMethod.getSelector()).setTagBits(ndMethod.getTagBits())
+ .setIsClInit(ndMethod.isClInit()).setTypeAnnotations(createBinaryTypeAnnotations(ndMethod.getTypeAnnotations()));
}
private static IBinaryTypeAnnotation[] createBinaryTypeAnnotations(List<? extends NdTypeAnnotation> typeAnnotations) {
@@ -423,7 +419,7 @@ public class IndexBinaryType implements IBinaryType {
case AnnotationTargetTypeConstants.METHOD_RECEIVER:
break;
case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER :
- info = next.getTargetInfoArg0();
+ info = next.getTarget();
break;
case AnnotationTargetTypeConstants.THROWS :
info = next.getTarget();
@@ -593,13 +589,12 @@ public class IndexBinaryType implements IBinaryType {
try (IReader rl = this.typeRef.lock()) {
NdType type = this.typeRef.get();
if (type != null) {
- NdMethodId methodId = type.getDeclaringMethod();
+ IString declaringMethod = type.getDeclaringMethod();
- if (methodId != null) {
- char[] methodName = methodId.getMethodName().getChars();
- int startIdx = CharArrayUtils.lastIndexOf('#', methodName);
- this.enclosingMethod = CharArrayUtils.subarray(methodName, startIdx + 1);
- this.enclosingType = CharArrayUtils.subarray(methodName, 1, startIdx);
+ if (declaringMethod.length() != 0) {
+ char[] methodName = declaringMethod.getChars();
+ this.enclosingMethod = methodName;
+ this.enclosingType = type.getDeclaringType().getBinaryName();
} else {
NdTypeId typeId = type.getDeclaringType();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java
new file mode 100644
index 0000000000..25c94e8084
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/MathUtils.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd.util;
+
+public class MathUtils {
+ /**
+ * Rounds the one number up to the nearest multiple of another
+ *
+ * @param numberToRound
+ * number to round
+ * @param toMultipleOfThis the result will be divisible by this number
+ * @return the result will be the smallest multiple of toMultipleOfThis that is no smaller than numberToRound
+ */
+ public static int roundUpToNearestMultiple(int numberToRound, int toMultipleOfThis) {
+ return ((numberToRound + toMultipleOfThis - 1) / toMultipleOfThis) * toMultipleOfThis;
+ }
+
+ /**
+ * Rounds the one number up to the nearest multiple of another, where the second number is a power of two.
+ *
+ * @param numberToRound
+ * number to round
+ * @param aPowerOfTwo
+ * the result will be divisible by this
+ * @return the result will be the smallest multiple of aPowerOfTwo that is no smaller than numberToRound
+ */
+ public static int roundUpToNearestMultipleOfPowerOfTwo(int numberToRound, int aPowerOfTwo) {
+ return ((numberToRound + aPowerOfTwo - 1) & ~(aPowerOfTwo - 1));
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
index 567c568396..e4098a1900 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
@@ -90,6 +90,11 @@ public Index[] getIndexes(IProgressMonitor progressMonitor) {
this.areIndexesReady = indexes.length == length;
return indexes;
}
+
+@Override
+public boolean waitNeeded() {
+ return true;
+}
public String getJobFamily() {
return ""; //$NON-NLS-1$
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index 309e456d5e..b3486a5e80 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -1061,6 +1061,10 @@ public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath
public String toString() {
return "indexing " + searchDocument.getPath(); //$NON-NLS-1$
}
+ @Override
+ public boolean waitNeeded() {
+ return false;
+ }
});
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
index d919fe5f7c..13471831c3 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
@@ -42,4 +42,8 @@ public abstract class IndexRequest implements IJob {
protected Integer updatedIndexState() {
return IndexManager.UPDATING_STATE;
}
+ @Override
+ public boolean waitNeeded() {
+ return true;
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
index db444bf3eb..46b9f0b6b2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
@@ -45,4 +45,14 @@ public interface IJob {
* Returns this job's family
*/
public String getJobFamily();
+
+ /**
+ * Answers if we need some sleep after index write operations. Default implementation returns {@code false}.
+ *
+ * @return true if the job manager should sleep a bit after this job is done to avoid IO tasks overloading OS (which
+ * could cause UI freezes etc).
+ */
+ public default boolean waitNeeded() {
+ return false;
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
index 7c07d0f47d..a7cdccf103 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
@@ -400,8 +400,12 @@ public abstract class JobManager implements Runnable {
if (VERBOSE)
Util.verbose("FINISHED background job - " + job); //$NON-NLS-1$
moveToNextJob();
- if (this.awaitingClients == 0)
- Thread.sleep(50);
+ if (this.awaitingClients == 0 && job.waitNeeded()) {
+ if (VERBOSE) {
+ Util.verbose("WAITING after job - " + job); //$NON-NLS-1$
+ }
+ Thread.sleep(5);
+ }
}
} catch (InterruptedException e) { // background indexing was interrupted
}

Back to the top